diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index 58562f99d5f4..e4b2a40fba65 100644 --- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -995,7 +995,7 @@ public: void addConstantUImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); uint64_t Imm = getConstantImm() - Offset; - Imm &= (1 << Bits) - 1; + Imm &= (1ULL << Bits) - 1; Imm += Offset; Imm += AdjustOffset; Inst.addOperand(MCOperand::createImm(Imm)); @@ -1093,7 +1093,8 @@ public: bool isRegIdx() const { return Kind == k_RegisterIndex; } bool isImm() const override { return Kind == k_Immediate; } bool isConstantImm() const { - return isImm() && isa(getImm()); + int64_t Res; + return isImm() && getImm()->evaluateAsAbsolute(Res); } bool isConstantImmz() const { return isConstantImm() && getConstantImm() == 0; @@ -1264,7 +1265,9 @@ public: int64_t getConstantImm() const { const MCExpr *Val = getImm(); - return static_cast(Val)->getValue(); + int64_t Value = 0; + (void)Val->evaluateAsAbsolute(Value); + return Value; } MipsOperand *getMemBase() const { @@ -4051,6 +4054,9 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, case Match_SImm32_Relaxed: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 32-bit signed immediate"); + case Match_UImm32_Coerced: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 32-bit immediate"); case Match_MemSImm9: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected memory with 9-bit signed offset"); diff --git a/llvm/lib/Target/Mips/MipsInstrInfo.td b/llvm/lib/Target/Mips/MipsInstrInfo.td index 51fe46953b22..3f3885443f7a 100644 --- a/llvm/lib/Target/Mips/MipsInstrInfo.td +++ b/llvm/lib/Target/Mips/MipsInstrInfo.td @@ -467,6 +467,16 @@ class UImmAsmOperandClass Supers = []> let DiagnosticType = "UImm" # Bits; } +// Generic case - only to support certain assembly pseudo instructions. +class UImmAnyAsmOperandClass Supers = []> + : AsmOperandClass { + let Name = "ImmAny"; + let RenderMethod = "addConstantUImmOperands<32>"; + let PredicateMethod = "isSImm<" # Bits # ">"; + let SuperClasses = Supers; + let DiagnosticType = "ImmAny"; +} + // AsmOperandClasses require a strict ordering which is difficult to manage // as a hierarchy. Instead, we use a linear ordering and impose an order that // is in some places arbitrary. @@ -490,8 +500,13 @@ class UImmAsmOperandClass Supers = []> // uimm5 < uimm5_64, and uimm5 < vsplat_uimm5 // This is entirely arbitrary. We need an ordering and what we pick is // unimportant since only one is possible for a given mnemonic. + +def UImm32CoercedAsmOperandClass : UImmAnyAsmOperandClass<33, []> { + let Name = "UImm32_Coerced"; + let DiagnosticType = "UImm32_Coerced"; +} def SImm32RelaxedAsmOperandClass - : SImmAsmOperandClass<32, []> { + : SImmAsmOperandClass<32, [UImm32CoercedAsmOperandClass]> { let Name = "SImm32_Relaxed"; let PredicateMethod = "isAnyImm<32>"; let DiagnosticType = "SImm32_Relaxed"; @@ -515,6 +530,8 @@ def UImm16RelaxedAsmOperandClass let PredicateMethod = "isAnyImm<16>"; let DiagnosticType = "UImm16_Relaxed"; } +// FIXME: One of these should probably have UImm16AsmOperandClass as the +// superclass instead of UImm16RelaxedasmOPerandClass. def UImm16AsmOperandClass : UImmAsmOperandClass<16, [UImm16RelaxedAsmOperandClass]>; def SImm16RelaxedAsmOperandClass @@ -872,6 +889,10 @@ def simm16_64 : Operand { let ParserMatchClass = !cast("SImm16AsmOperandClass"); } +// like simm32 but coerces simm32 to uimm32. +def uimm32_coerced : Operand { + let ParserMatchClass = !cast("UImm32CoercedAsmOperandClass"); +} // Like simm32 but coerces uimm32 to simm32. def simm32_relaxed : Operand { let DecoderMethod = "DecodeSImmWithOffsetAndScale<32>"; @@ -2387,11 +2408,12 @@ def : MipsInstAlias<"sync", // Assembler Pseudo Instructions //===----------------------------------------------------------------------===// -// We use i32imm on li/la to defer range checking to the assembler. +// We use uimm32_coerced to accept a 33 bit signed number that is rendered into +// a 32 bit number. class LoadImmediate32 : MipsAsmPseudoInst<(outs RO:$rt), (ins Od:$imm32), !strconcat(instr_asm, "\t$rt, $imm32")> ; -def LoadImm32 : LoadImmediate32<"li", i32imm, GPR32Opnd>; +def LoadImm32 : LoadImmediate32<"li", uimm32_coerced, GPR32Opnd>; class LoadAddressFromReg32 : diff --git a/llvm/test/MC/Mips/macro-li-bad.s b/llvm/test/MC/Mips/macro-li-bad.s index 8fe622066e9c..29eedce713ab 100644 --- a/llvm/test/MC/Mips/macro-li-bad.s +++ b/llvm/test/MC/Mips/macro-li-bad.s @@ -7,5 +7,5 @@ .text li $5, 0x100000000 - # 32-BIT: :[[@LINE-1]]:3: error: instruction requires a 32-bit immediate - # 64-BIT: :[[@LINE-2]]:3: error: instruction requires a 32-bit immediate + # 32-BIT: :[[@LINE-1]]:10: error: expected 32-bit immediate + # 64-BIT: :[[@LINE-2]]:10: error: expected 32-bit immediate diff --git a/llvm/test/MC/Mips/macro-li.s b/llvm/test/MC/Mips/macro-li.s index 88e013a854e2..6cdc11d70d25 100644 --- a/llvm/test/MC/Mips/macro-li.s +++ b/llvm/test/MC/Mips/macro-li.s @@ -65,3 +65,11 @@ li $5, 0xc0008000 # CHECK: lui $5, 49152 # encoding: [0x3c,0x05,0xc0,0x00 # CHECK: ori $5, $5, 32768 # encoding: [0x34,0xa5,0x80,0x00] li $5, 0x80008000 # CHECK: lui $5, 32768 # encoding: [0x3c,0x05,0x80,0x00] # CHECK: ori $5, $5, 32768 # encoding: [0x34,0xa5,0x80,0x00] +li $4, ~0xffffffff # CHECK; addiu $4, $zero, 0 # encoding: [0x24,0x04,0x00,0x00] +li $4, ~0x80000001 # CHECK: lui $4, 32767 # encoding: [0x3c,0x04,0x7f,0xff] + # CHECK: ori $4, $4, 65534 # encoding: [0x34,0x84,0xff,0xfe] +li $4, ~0x80000000 # CHECK: lui $4, 32767 # encoding: [0x3c,0x04,0x7f,0xff] + # CHECK: ori $4, $4, 65535 # encoding: [0x34,0x84,0xff,0xff] +li $4, ~0x7fffffff # CHECK: lui $4, 32768 # encoding: [0x3c,0x04,0x80,0x00] +li $4, ~0x00000001 # CHECK: addiu $4, $zero, -2 # encoding: [0x24,0x04,0xff,0xfe] +li $4, ~0x00000000 # CHECK: addiu $4, $zero, -1 # encoding: [0x24,0x04,0xff,0xff]