return getModifiers().hasIntModifiers();
}
+ uint64_t applyInputFPModifiers(uint64_t Val, unsigned Size) const;
+
void addImmOperands(MCInst &Inst, unsigned N, bool ApplyModifiers = true) const;
- void addLiteralImmOperand(MCInst &Inst, int64_t Val) const;
+ void addLiteralImmOperand(MCInst &Inst, int64_t Val, bool ApplyModifiers) const;
template <unsigned Bitwidth>
void addKImmFPOperands(MCInst &Inst, unsigned N) const;
if (!Imm.IsFPImm) {
// We got int literal token.
+ if (type == MVT::f64 && hasFPModifiers()) {
+ // Cannot apply fp modifiers to int literals preserving the same semantics
+ // for VOP1/2/C and VOP3 because of integer truncation. To avoid ambiguity,
+ // disable these cases.
+ return false;
+ }
+
unsigned Size = type.getSizeInBits();
if (Size == 64)
Size = 32;
return isRegKind() && AsmParser->getMRI()->getRegClass(RCID).contains(getReg());
}
-void AMDGPUOperand::addImmOperands(MCInst &Inst, unsigned N, bool ApplyModifiers) const {
- int64_t Val = Imm.Val;
- if (isImmTy(ImmTyNone) && ApplyModifiers && Imm.Mods.hasFPModifiers() && Imm.Mods.Neg) {
- // Apply modifiers to immediate value. Only negate can get here
- if (Imm.IsFPImm) {
- APFloat F(BitsToDouble(Val));
- F.changeSign();
- Val = F.bitcastToAPInt().getZExtValue();
- } else {
- Val = -Val;
- }
+uint64_t AMDGPUOperand::applyInputFPModifiers(uint64_t Val, unsigned Size) const
+{
+ assert(isImmTy(ImmTyNone) && Imm.Mods.hasFPModifiers());
+ assert(Size == 2 || Size == 4 || Size == 8);
+
+ const uint64_t FpSignMask = (1ULL << (Size * 8 - 1));
+
+ if (Imm.Mods.Abs) {
+ Val &= ~FpSignMask;
+ }
+ if (Imm.Mods.Neg) {
+ Val ^= FpSignMask;
}
+ return Val;
+}
+
+void AMDGPUOperand::addImmOperands(MCInst &Inst, unsigned N, bool ApplyModifiers) const {
+
if (AMDGPU::isSISrcOperand(AsmParser->getMII()->get(Inst.getOpcode()),
Inst.getNumOperands())) {
- addLiteralImmOperand(Inst, Val);
+ addLiteralImmOperand(Inst, Imm.Val,
+ ApplyModifiers &
+ isImmTy(ImmTyNone) && Imm.Mods.hasFPModifiers());
} else {
- Inst.addOperand(MCOperand::createImm(Val));
+ assert(!isImmTy(ImmTyNone) || !hasModifiers());
+ Inst.addOperand(MCOperand::createImm(Imm.Val));
}
}
-void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val) const {
+void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val, bool ApplyModifiers) const {
const auto& InstDesc = AsmParser->getMII()->get(Inst.getOpcode());
auto OpNum = Inst.getNumOperands();
// Check that this operand accepts literals
assert(AMDGPU::isSISrcOperand(InstDesc, OpNum));
+ if (ApplyModifiers) {
+ assert(AMDGPU::isSISrcFPOperand(InstDesc, OpNum));
+ const unsigned Size = Imm.IsFPImm ? sizeof(double) : getOperandSize(InstDesc, OpNum);
+ Val = applyInputFPModifiers(Val, Size);
+ }
+
APInt Literal(64, Val);
uint8_t OpTy = InstDesc.OpInfo[OpNum].OperandType;
OperandMatchResultTy
AMDGPUAsmParser::parseRegOrImmWithFPInputMods(OperandVector &Operands,
bool AllowImm) {
- // XXX: During parsing we can't determine if minus sign means
- // negate-modifier or negative immediate value.
- // By default we suppose it is modifier.
- bool Negate = false, Abs = false, Abs2 = false;
+ bool Negate = false, Negate2 = false, Abs = false, Abs2 = false;
if (getLexer().getKind()== AsmToken::Minus) {
+ const AsmToken NextToken = getLexer().peekTok();
+
+ // Disable ambiguous constructs like '--1' etc. Should use neg(-1) instead.
+ if (NextToken.is(AsmToken::Minus)) {
+ Error(Parser.getTok().getLoc(), "invalid syntax, expected 'neg' modifier");
+ return MatchOperand_ParseFail;
+ }
+
+ // '-' followed by an integer literal N should be interpreted as integer
+ // negation rather than a floating-point NEG modifier applied to N.
+ // Beside being contr-intuitive, such use of floating-point NEG modifier
+ // results in different meaning of integer literals used with VOP1/2/C
+ // and VOP3, for example:
+ // v_exp_f32_e32 v5, -1 // VOP1: src0 = 0xFFFFFFFF
+ // v_exp_f32_e64 v5, -1 // VOP3: src0 = 0x80000001
+ // Negative fp literals should be handled likewise for unifomtity
+ if (!NextToken.is(AsmToken::Integer) && !NextToken.is(AsmToken::Real)) {
+ Parser.Lex();
+ Negate = true;
+ }
+ }
+
+ if (getLexer().getKind() == AsmToken::Identifier &&
+ Parser.getTok().getString() == "neg") {
+ if (Negate) {
+ Error(Parser.getTok().getLoc(), "expected register or immediate");
+ return MatchOperand_ParseFail;
+ }
+ Parser.Lex();
+ Negate2 = true;
+ if (getLexer().isNot(AsmToken::LParen)) {
+ Error(Parser.getTok().getLoc(), "expected left paren after neg");
+ return MatchOperand_ParseFail;
+ }
Parser.Lex();
- Negate = true;
}
if (getLexer().getKind() == AsmToken::Identifier &&
}
AMDGPUOperand::Modifiers Mods;
- if (Negate) {
- Mods.Neg = true;
- }
if (Abs) {
if (getLexer().getKind() != AsmToken::Pipe) {
Error(Parser.getTok().getLoc(), "expected vertical bar");
Mods.Abs = true;
}
+ if (Negate) {
+ Mods.Neg = true;
+ } else if (Negate2) {
+ if (getLexer().isNot(AsmToken::RParen)) {
+ Error(Parser.getTok().getLoc(), "expected closing parentheses");
+ return MatchOperand_ParseFail;
+ }
+ Parser.Lex();
+ Mods.Neg = true;
+ }
+
if (Mods.hasFPModifiers()) {
AMDGPUOperand &Op = static_cast<AMDGPUOperand &>(*Operands.back());
Op.setModifiers(Mods);
--- /dev/null
+// RUN: llvm-mc -arch=amdgcn -mcpu=tonga -show-encoding %s | FileCheck %s
+
+//---------------------------------------------------------------------------//
+// VOP1/VOP3 F16
+//---------------------------------------------------------------------------//
+
+v_ceil_f16 v0, -1
+// CHECK: [0xc1,0x8a,0x00,0x7e]
+
+v_ceil_f16 v0, -2
+// CHECK: [0xc2,0x8a,0x00,0x7e]
+
+v_ceil_f16 v0, -16
+// CHECK: [0xd0,0x8a,0x00,0x7e]
+
+v_ceil_f16 v0, -0.5
+// CHECK: [0xf1,0x8a,0x00,0x7e]
+
+v_ceil_f16 v0, -1.0
+// CHECK: [0xf3,0x8a,0x00,0x7e]
+
+v_ceil_f16 v0, -2.0
+// CHECK: [0xf5,0x8a,0x00,0x7e]
+
+v_ceil_f16 v0, -4.0
+// CHECK: [0xf7,0x8a,0x00,0x7e]
+
+// Arbitrary f16 literal in hex
+v_ceil_f16 v0, 0xabcd
+// CHECK: [0xff,0x8a,0x00,0x7e,0xcd,0xab,0x00,0x00]
+
+// '-' is a part of hex literal (not a 'neg' modifier)
+v_ceil_f16 v0, -0x5433
+// CHECK: [0xff,0x8a,0x00,0x7e,0xcd,0xab,0x00,0x00]
+
+v_ceil_f16 v0, abs(0xabcd)
+// CHECK: [0xff,0x8a,0x00,0x7e,0xcd,0x2b,0x00,0x00]
+
+v_ceil_f16 v0, neg(0xabcd)
+// CHECK: [0xff,0x8a,0x00,0x7e,0xcd,0x2b,0x00,0x00]
+
+v_ceil_f16 v0, neg(abs(0xabcd))
+// CHECK: [0xff,0x8a,0x00,0x7e,0xcd,0xab,0x00,0x00]
+
+v_ceil_f16 v0, -abs(0xabcd)
+// CHECK: [0xff,0x8a,0x00,0x7e,0xcd,0xab,0x00,0x00]
+
+// 1/(2*pi) encoded as inline constant in VOP1
+v_ceil_f16 v0, 0x3118
+// CHECK: [0xf8,0x8a,0x00,0x7e]
+
+// 1/(2*pi) encoded as inline constant in VOP3
+v_ceil_f16_e64 v0, 0x3118
+// CHECK: [0x00,0x00,0x85,0xd1,0xf8,0x00,0x00,0x00]
+
+// neg(-1/(2*pi)) = 1/(2*pi)
+v_ceil_f16 v0, neg(0xb118)
+// CHECK: [0xf8,0x8a,0x00,0x7e]
+
+// -1/(2*pi) cannot be encoded as inline constant in VOP1
+v_ceil_f16 v0, 0xb118
+// CHECK: [0xff,0x8a,0x00,0x7e,0x18,0xb1,0x00,0x00]
+
+// -1/(2*pi) cannot be encoded as inline constant in VOP1
+v_ceil_f16 v0, neg(0x3118)
+// CHECK: [0xff,0x8a,0x00,0x7e,0x18,0xb1,0x00,0x00]
+
+// -1/(2*pi) can be encoded as inline constant w/ modifiers in VOP3
+v_ceil_f16_e64 v0, neg(0x3118)
+// CHECK: [0x00,0x00,0x85,0xd1,0xf8,0x00,0x00,0x20]
+
+v_ceil_f16_e64 v0, abs(0x3118)
+// CHECK: 0x00,0x01,0x85,0xd1,0xf8,0x00,0x00,0x00]
+
+v_ceil_f16_e64 v0, neg(abs(0x3118))
+// CHECK: [0x00,0x01,0x85,0xd1,0xf8,0x00,0x00,0x20]
+
+v_ceil_f16_e64 v0, neg(|v1|)
+// CHECK: [0x00,0x01,0x85,0xd1,0x01,0x01,0x00,0x20]
+
+v_ceil_f16_e64 v0, -|v1|
+// CHECK: [0x00,0x01,0x85,0xd1,0x01,0x01,0x00,0x20]
+
+//---------------------------------------------------------------------------//
+// VOP1/VOP3 F64
+//---------------------------------------------------------------------------//
+
+// Encoded as inline constant 1 with 'neg' modifier
+v_ceil_f64 v[0:1], neg(1)
+// CHECK: [0x00,0x00,0x58,0xd1,0x81,0x00,0x00,0x20]
+
+// Encoded as inline constant -1 with 'neg' modifier
+v_ceil_f64 v[0:1], neg(-1)
+// CHECK: [0x00,0x00,0x58,0xd1,0xc1,0x00,0x00,0x20]
+
+v_ceil_f64_e32 v[0:1], 1.0
+// CHECK: [0xf2,0x30,0x00,0x7e]
+
+// abs(1.0) = 1.0
+v_ceil_f64_e32 v[0:1], abs(1.0)
+// CHECK: [0xf2,0x30,0x00,0x7e]
+
+// neg(1.0) = -1.0
+v_ceil_f64_e32 v[0:1], neg(1.0)
+// CHECK: [0xf3,0x30,0x00,0x7e]
+
+// 1/(2*pi) encoded as inline constant in VOP1
+v_ceil_f64 v[0:1], 0x3fc45f306dc9c882
+// CHECK: [0xf8,0x30,0x00,0x7e]
+
+// 1/(2*pi) encoded as inline constant in VOP3
+v_ceil_f64_e64 v[0:1], 0x3fc45f306dc9c882
+// CHECK: [0x00,0x00,0x58,0xd1,0xf8,0x00,0x00,0x00]
+
+// -1/(2*pi) cannot be encoded as inline constant in VOP1.
+// It cannot be encoded as literal either due to int literal rules.
+// So it is encoded as VOP3
+v_ceil_f64 v[0:1], abs(0x3fc45f306dc9c882)
+// CHECK: [0x00,0x01,0x58,0xd1,0xf8,0x00,0x00,0x00]
+
+v_ceil_f64 v[0:1], neg(abs(0x3fc45f306dc9c882))
+// CHECK: [0x00,0x01,0x58,0xd1,0xf8,0x00,0x00,0x20]
+
+
+//---------------------------------------------------------------------------//
+// VOP2/VOP3 F32
+//---------------------------------------------------------------------------//
+
+v_add_f32 v5, -1, v2
+// CHECK: [0xc1,0x04,0x0a,0x02]
+
+v_add_f32 v5, -16, v2
+// CHECK: [0xd0,0x04,0x0a,0x02]
+
+v_add_f32 v5, 0x3e22f983, v2
+// CHECK: [0xf8,0x04,0x0a,0x02]
+
+// abs(1/(2*pi)) = 1/(2*pi)
+v_add_f32 v5, abs(0x3e22f983), v2
+// CHECK: [0xf8,0x04,0x0a,0x02]
+
+// neg(-1/(2*pi)) = 1/(2*pi)
+v_add_f32 v5, neg(0xbe22f983), v2
+// CHECK: [0xf8,0x04,0x0a,0x02]
+
+// -1/(2*pi) cannot be encoded as inline constant in VOP1
+v_add_f32 v5, neg(0x3e22f983), v2
+// CHECK: [0xff,0x04,0x0a,0x02,0x83,0xf9,0x22,0xbe]
+
+
+v_add_f32_e64 v0, -2, s0
+// CHECK: [0x00,0x00,0x01,0xd1,0xc2,0x00,0x00,0x00]
+
+v_add_f32_e64 v0, -16, s0
+// CHECK: [0x00,0x00,0x01,0xd1,0xd0,0x00,0x00,0x00]
+
+v_add_f32_e64 v0, -0.5, s0
+// CHECK: [0x00,0x00,0x01,0xd1,0xf1,0x00,0x00,0x00]
+
+v_add_f32_e64 v0, -1.0, s0
+// CHECK: [0x00,0x00,0x01,0xd1,0xf3,0x00,0x00,0x00]
+
+v_add_f32_e64 v0, -2.0, s0
+// CHECK: [0x00,0x00,0x01,0xd1,0xf5,0x00,0x00,0x00]
+
+v_add_f32_e64 v0, -4.0, s0
+// CHECK: [0x00,0x00,0x01,0xd1,0xf7,0x00,0x00,0x00]
+
+v_add_f32_e64 v0, 0x3e22f983, s0
+// CHECK: [0x00,0x00,0x01,0xd1,0xf8,0x00,0x00,0x00]
+
+v_add_f32_e64 v0, neg(0x3e22f983), s0
+// CHECK: [0x00,0x00,0x01,0xd1,0xf8,0x00,0x00,0x20]
+
+//---------------------------------------------------------------------------//
+// VOPC/VOP3
+//---------------------------------------------------------------------------//
+
+v_cmp_eq_f16 vcc, -1, v0
+// CHECK: [0xc1,0x00,0x44,0x7c]
+
+v_cmp_eq_f16_e64 s[0:1], s0, -1
+// CHECK: [0x00,0x00,0x22,0xd0,0x00,0x82,0x01,0x00]
+
+v_cmp_eq_f16_e64 s[0:1], s0, 0x3118
+// CHECK: [0x00,0x00,0x22,0xd0,0x00,0xf0,0x01,0x00]
+
+v_cmp_eq_f16_e64 s[0:1], s0, neg(0x3118)
+// CHECK: [0x00,0x00,0x22,0xd0,0x00,0xf0,0x01,0x40]
+
+v_cmp_eq_f32 vcc, -4.0, v0
+// CHECK: [0xf7,0x00,0x84,0x7c]
+
+// 1/(2*pi) can be encoded as inline constant
+v_cmp_eq_f32 vcc, 0x3e22f983, v0
+// CHECK: [0xf8,0x00,0x84,0x7c]
+
+// -1/(2*pi) cannot be encoded as inline constant in VOPC
+v_cmp_eq_f32 vcc, neg(0x3e22f983), v0
+// CHECK: [0xff,0x00,0x84,0x7c,0x83,0xf9,0x22,0xbe]
+
+// abs(1/(2*pi)) = 1/(2*pi)
+v_cmp_eq_f32 vcc, abs(0x3e22f983), v0
+// CHECK: [0xf8,0x00,0x84,0x7c]
+
+// -1/(2*pi) can be encoded as inline constant w/ modifiers in VOP3
+v_cmp_eq_f32_e64 vcc, neg(0x3e22f983), v0
+// CHECK: [0x6a,0x00,0x42,0xd0,0xf8,0x00,0x02,0x20]
+
+v_cmp_eq_f32_e64 vcc, v0, abs(0x3e22f983)
+// CHECK: [0x6a,0x02,0x42,0xd0,0x00,0xf1,0x01,0x00]
+
+v_cmp_eq_f32_e64 vcc, v0, -abs(0x3e22f983)
+// CHECK: [0x6a,0x02,0x42,0xd0,0x00,0xf1,0x01,0x40]
+
+//---------------------------------------------------------------------------//
+// VOP3
+//---------------------------------------------------------------------------//
+
+v_add_f64 v[0:1], s[0:1], -1
+// CHECK: [0x00,0x00,0x80,0xd2,0x00,0x82,0x01,0x00]
+
+v_add_f64 v[0:1], s[0:1], -16
+// CHECK: [0x00,0x00,0x80,0xd2,0x00,0xa0,0x01,0x00]
+
+v_add_f64 v[0:1], s[0:1], -0.5
+// CHECK: [0x00,0x00,0x80,0xd2,0x00,0xe2,0x01,0x00]
+
+v_add_f64 v[0:1], s[0:1], -1.0
+// CHECK: [0x00,0x00,0x80,0xd2,0x00,0xe6,0x01,0x00]
+
+v_add_f64 v[0:1], s[0:1], -2.0
+// CHECK: [0x00,0x00,0x80,0xd2,0x00,0xea,0x01,0x00]
+
+v_add_f64 v[0:1], s[0:1], -4.0
+// CHECK: [0x00,0x00,0x80,0xd2,0x00,0xee,0x01,0x00]
+
+v_add_f64 v[4:5], s[0:1], 0x3fc45f306dc9c882
+// CHECK: [0x04,0x00,0x80,0xd2,0x00,0xf0,0x01,0x00]
+
+v_add_f64 v[4:5], s[0:1], neg(0x3fc45f306dc9c882)
+// CHECK: [0x04,0x00,0x80,0xd2,0x00,0xf0,0x01,0x40]
+
+
+v_cubeid_f32 v0, s0, s0, -1
+// CHECK: [0x00,0x00,0xc4,0xd1,0x00,0x00,0x04,0x03]
+
+v_cubeid_f32 v0, s0, s0, -4.0
+// CHECK: [0x00,0x00,0xc4,0xd1,0x00,0x00,0xdc,0x03]
+
+v_cubeid_f32 v0, s0, s0, 0x3e22f983
+// CHECK: [0x00,0x00,0xc4,0xd1,0x00,0x00,0xe0,0x03]
+
+v_cubeid_f32 v0, s0, s0, neg(0x3e22f983)
+// CHECK: [0x00,0x00,0xc4,0xd1,0x00,0x00,0xe0,0x83]
+
+v_cubeid_f32 v0, s0, s0, abs(0x3e22f983)
+// CHECK: [0x00,0x04,0xc4,0xd1,0x00,0x00,0xe0,0x03]
\ No newline at end of file