diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/ARM.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/ARM.def --- a/llvm/include/llvm/BinaryFormat/ELFRelocs/ARM.def +++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/ARM.def @@ -135,6 +135,10 @@ ELF_RELOC(R_ARM_ME_TOO, 0x80) ELF_RELOC(R_ARM_THM_TLS_DESCSEQ16, 0x81) ELF_RELOC(R_ARM_THM_TLS_DESCSEQ32, 0x82) +ELF_RELOC(R_ARM_THM_ALU_ABS_G0_NC, 0x84) +ELF_RELOC(R_ARM_THM_ALU_ABS_G1_NC, 0x85) +ELF_RELOC(R_ARM_THM_ALU_ABS_G2_NC, 0x86) +ELF_RELOC(R_ARM_THM_ALU_ABS_G3, 0x87) ELF_RELOC(R_ARM_THM_BF16, 0x88) ELF_RELOC(R_ARM_THM_BF12, 0x89) ELF_RELOC(R_ARM_THM_BF18, 0x8a) diff --git a/llvm/lib/Target/ARM/ARMInstrInfo.td b/llvm/lib/Target/ARM/ARMInstrInfo.td --- a/llvm/lib/Target/ARM/ARMInstrInfo.td +++ b/llvm/lib/Target/ARM/ARMInstrInfo.td @@ -965,6 +965,19 @@ let ParserMatchClass = Imm0_255AsmOperand; } +// imm0_255_expr - For Thumb1 movs/adds - 8-bit immediate that can also reference +// a relocatable expression. +def Imm0_255ExprAsmOperand: AsmOperandClass { + let Name = "Imm0_255Expr"; + let RenderMethod = "addImmOperands"; + let DiagnosticString = "operand must be an immediate in the range [0,255] or a relocatable expression"; +} + +def imm0_255_expr : Operand, ImmLeaf= 0 && Imm < 256; }]> { + let EncoderMethod = "getHiLoImmOpValue"; + let ParserMatchClass = Imm0_255ExprAsmOperand; +} + /// imm0_65535 - An immediate is in the range [0,65535]. def Imm0_65535AsmOperand: ImmAsmOperand<0,65535> { let Name = "Imm0_65535"; } def imm0_65535 : Operand, ImmLeaf { - let EncoderMethod = "getHiLo16ImmOpValue"; +def imm0_65535_expr : Operand, ImmLeaf= 0 && Imm < 65536; +}]> { + let EncoderMethod = "getHiLoImmOpValue"; let ParserMatchClass = Imm0_65535ExprAsmOperand; } diff --git a/llvm/lib/Target/ARM/ARMInstrThumb.td b/llvm/lib/Target/ARM/ARMInstrThumb.td --- a/llvm/lib/Target/ARM/ARMInstrThumb.td +++ b/llvm/lib/Target/ARM/ARMInstrThumb.td @@ -984,9 +984,9 @@ def tADDi8 : // A8.6.4 T2 T1sItGenEncodeImm<{1,1,0,?,?}, (outs tGPR:$Rdn), - (ins tGPR:$Rn, imm0_255:$imm8), IIC_iALUi, + (ins tGPR:$Rn, imm0_255_expr:$imm8), IIC_iALUi, "add", "\t$Rdn, $imm8", - [(set tGPR:$Rdn, (add tGPR:$Rn, imm8_255:$imm8))]>, + [(set tGPR:$Rdn, (add tGPR:$Rn, imm0_255_expr:$imm8))]>, Sched<[WriteALU]>; // Add register @@ -995,7 +995,8 @@ T1sIGenEncode<0b01100, (outs tGPR:$Rd), (ins tGPR:$Rn, tGPR:$Rm), IIC_iALUr, "add", "\t$Rd, $Rn, $Rm", - [(set tGPR:$Rd, (add tGPR:$Rn, tGPR:$Rm))]>, Sched<[WriteALU]>; + [(set tGPR:$Rd, (add tGPR:$Rn, tGPR:$Rm))]>, + Sched<[WriteALU]>; /// Similar to the above except these set the 's' bit so the /// instruction modifies the CPSR register. @@ -1018,10 +1019,10 @@ Requires<[IsThumb1Only]>, Sched<[WriteALU]>; - def tADDSi8 : tPseudoInst<(outs tGPR:$Rdn), (ins tGPR:$Rn, imm0_255:$imm8), + def tADDSi8 : tPseudoInst<(outs tGPR:$Rdn), (ins tGPR:$Rn, imm0_255_expr:$imm8), 2, IIC_iALUi, [(set tGPR:$Rdn, CPSR, (ARMaddc tGPR:$Rn, - imm8_255:$imm8))]>, + imm0_255_expr:$imm8))]>, Requires<[IsThumb1Only]>, Sched<[WriteALU]>; @@ -1196,9 +1197,9 @@ // Move register let isMoveImm = 1 in -def tMOVi8 : T1sI<(outs tGPR:$Rd), (ins imm0_255:$imm8), IIC_iMOVi, +def tMOVi8 : T1sI<(outs tGPR:$Rd), (ins imm0_255_expr:$imm8), IIC_iMOVi, "mov", "\t$Rd, $imm8", - [(set tGPR:$Rd, imm0_255:$imm8)]>, + [(set tGPR:$Rd, imm0_255_expr:$imm8)]>, T1General<{1,0,0,?,?}>, Sched<[WriteALU]> { // A8.6.96 bits<3> Rd; @@ -1208,8 +1209,8 @@ } // Because we have an explicit tMOVSr below, we need an alias to handle // the immediate "movs" form here. Blech. -def : tInstAlias <"movs $Rdn, $imm", - (tMOVi8 tGPR:$Rdn, CPSR, imm0_255:$imm, 14, 0)>; +def : tInstAlias <"movs $Rdn, $imm8", + (tMOVi8 tGPR:$Rdn, CPSR, imm0_255_expr:$imm8, 14, 0)>; // A7-73: MOV(2) - mov setting flag. diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -1232,6 +1232,16 @@ return isImmediate<8, 255>(); } + bool isImm0_255Expr() const { + if (!isImm()) return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + // If it's not a constant expression, it'll generate a fixup and be + // handled later. + if (!CE) return true; + int64_t Value = CE->getValue(); + return Value >= 0 && Value < 256; + } + bool isImm256_65535Expr() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); @@ -6319,8 +6329,9 @@ return false; } -// parsePrefix - Parse ARM 16-bit relocations expression prefix, i.e. -// :lower16: and :upper16:. +// parsePrefix - Parse ARM 16-bit relocations expression prefixes, i.e. +// :lower16: and :upper16: and Thumb 8-bit relocation expression prefixes, i.e. +// :upper8_15:, :upper0_7:, :lower8_15: and :lower0_7: bool ARMAsmParser::parsePrefix(ARMMCExpr::VariantKind &RefKind) { MCAsmParser &Parser = getParser(); RefKind = ARMMCExpr::VK_ARM_None; @@ -6329,7 +6340,6 @@ if (getLexer().is(AsmToken::Hash)) Parser.Lex(); - // :lower16: and :upper16: modifiers assert(getLexer().is(AsmToken::Colon) && "expected a :"); Parser.Lex(); // Eat ':' @@ -6349,8 +6359,12 @@ ARMMCExpr::VariantKind VariantKind; uint8_t SupportedFormats; } PrefixEntries[] = { - { "lower16", ARMMCExpr::VK_ARM_LO16, COFF | ELF | MACHO }, { "upper16", ARMMCExpr::VK_ARM_HI16, COFF | ELF | MACHO }, + { "lower16", ARMMCExpr::VK_ARM_LO16, COFF | ELF | MACHO }, + { "upper8_15", ARMMCExpr::VK_ARM_HI_8_15, ELF }, + { "upper0_7", ARMMCExpr::VK_ARM_HI_0_7, ELF }, + { "lower8_15", ARMMCExpr::VK_ARM_LO_8_15, ELF }, + { "lower0_7", ARMMCExpr::VK_ARM_LO_0_7, ELF }, }; StringRef IDVal = Parser.getTok().getIdentifier(); @@ -6401,6 +6415,10 @@ } Parser.Lex(); // Eat the last ':' + // consume an optional trailing '#' (GNU compatibility) + if (getLexer().is(AsmToken::Hash)) + Parser.Lex(); + return false; } @@ -10541,7 +10559,9 @@ // explicitly specified. From the ARM ARM: "Encoding T1 is preferred // to encoding T2 if is specified and encoding T2 is preferred // to encoding T1 if is omitted." - if ((unsigned)Inst.getOperand(3).getImm() < 8 && Operands.size() == 6) { + if (Inst.getOperand(3).isImm() && + (unsigned)Inst.getOperand(3).getImm() < 8 && + Operands.size() == 6) { Inst.setOpcode(ARM::tADDi3); return true; } diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp @@ -114,6 +114,10 @@ {"fixup_arm_movw_lo16", 0, 20, 0}, {"fixup_t2_movt_hi16", 0, 20, 0}, {"fixup_t2_movw_lo16", 0, 20, 0}, + {"fixup_arm_thumb_upper_8_15", 0, 8, 0}, + {"fixup_arm_thumb_upper_0_7", 0, 8, 0}, + {"fixup_arm_thumb_lower_8_15", 0, 8, 0}, + {"fixup_arm_thumb_lower_0_7", 0, 8, 0}, {"fixup_arm_mod_imm", 0, 12, 0}, {"fixup_t2_so_imm", 0, 26, 0}, {"fixup_bf_branch", 0, 32, MCFixupKindInfo::FKF_IsPCRel}, @@ -168,6 +172,10 @@ {"fixup_arm_movw_lo16", 12, 20, 0}, {"fixup_t2_movt_hi16", 12, 20, 0}, {"fixup_t2_movw_lo16", 12, 20, 0}, + {"fixup_arm_thumb_upper_8_15", 24, 8, 0}, + {"fixup_arm_thumb_upper_0_7", 24, 8, 0}, + {"fixup_arm_thumb_lower_8_15", 24, 8, 0}, + {"fixup_arm_thumb_lower_0_7", 24, 8, 0}, {"fixup_arm_mod_imm", 20, 12, 0}, {"fixup_t2_so_imm", 26, 6, 0}, {"fixup_bf_branch", 0, 32, MCFixupKindInfo::FKF_IsPCRel}, @@ -487,6 +495,14 @@ Value = (Hi4 << 16) | (i << 26) | (Mid3 << 12) | (Lo8); return swapHalfWords(Value, Endian == support::little); } + case ARM::fixup_arm_thumb_upper_8_15: + return (Value & 0xff000000) >> 24; + case ARM::fixup_arm_thumb_upper_0_7: + return (Value & 0x00ff0000) >> 16; + case ARM::fixup_arm_thumb_lower_8_15: + return (Value & 0x0000ff00) >> 8; + case ARM::fixup_arm_thumb_lower_0_7: + return (Value & 0x000000ff); case ARM::fixup_arm_ldst_pcrel_12: // ARM PC-relative values are offset by 8. Value -= 4; @@ -931,6 +947,10 @@ case ARM::fixup_arm_thumb_bcc: case ARM::fixup_arm_thumb_cp: case ARM::fixup_thumb_adr_pcrel_10: + case ARM::fixup_arm_thumb_upper_8_15: + case ARM::fixup_arm_thumb_upper_0_7: + case ARM::fixup_arm_thumb_lower_8_15: + case ARM::fixup_arm_thumb_lower_0_7: return 1; case FK_Data_2: @@ -1001,6 +1021,10 @@ case ARM::fixup_thumb_adr_pcrel_10: case ARM::fixup_arm_thumb_br: case ARM::fixup_arm_thumb_cb: + case ARM::fixup_arm_thumb_upper_8_15: + case ARM::fixup_arm_thumb_upper_0_7: + case ARM::fixup_arm_thumb_lower_8_15: + case ARM::fixup_arm_thumb_lower_0_7: // Instruction size is 2 bytes. return 2; diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp @@ -137,6 +137,14 @@ return ELF::R_ARM_THM_MOVT_PREL; case ARM::fixup_t2_movw_lo16: return ELF::R_ARM_THM_MOVW_PREL_NC; + case ARM::fixup_arm_thumb_upper_8_15: + return ELF::R_ARM_THM_ALU_ABS_G3; + case ARM::fixup_arm_thumb_upper_0_7: + return ELF::R_ARM_THM_ALU_ABS_G2_NC; + case ARM::fixup_arm_thumb_lower_8_15: + return ELF::R_ARM_THM_ALU_ABS_G1_NC; + case ARM::fixup_arm_thumb_lower_0_7: + return ELF::R_ARM_THM_ALU_ABS_G0_NC; case ARM::fixup_arm_thumb_br: return ELF::R_ARM_THM_JUMP11; case ARM::fixup_arm_thumb_bcc: @@ -265,6 +273,15 @@ case MCSymbolRefExpr::VK_ARM_SBREL: return ELF::R_ARM_THM_MOVW_BREL_NC; } + + case ARM::fixup_arm_thumb_upper_8_15: + return ELF::R_ARM_THM_ALU_ABS_G3; + case ARM::fixup_arm_thumb_upper_0_7: + return ELF::R_ARM_THM_ALU_ABS_G2_NC; + case ARM::fixup_arm_thumb_lower_8_15: + return ELF::R_ARM_THM_ALU_ABS_G1_NC; + case ARM::fixup_arm_thumb_lower_0_7: + return ELF::R_ARM_THM_ALU_ABS_G0_NC; } } diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h b/llvm/lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h @@ -99,6 +99,12 @@ fixup_t2_movt_hi16, // :upper16: fixup_t2_movw_lo16, // :lower16: + // Fixup for Thumb movs (enc T1) and adds (enc T2) 8-bit immediate field (7-0) + fixup_arm_thumb_upper_8_15, // :upper8_15: + fixup_arm_thumb_upper_0_7, // :upper0_7: + fixup_arm_thumb_lower_8_15, // :lower8_15: + fixup_arm_thumb_lower_0_7, // :lower0_7: + // Fixup for mod_imm fixup_arm_mod_imm, diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp @@ -87,12 +87,13 @@ SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; - /// getHiLo16ImmOpValue - Return the encoding for the hi / low 16-bit of - /// the specified operand. This is used for operands with :lower16: and - /// :upper16: prefixes. - uint32_t getHiLo16ImmOpValue(const MCInst &MI, unsigned OpIdx, - SmallVectorImpl &Fixups, - const MCSubtargetInfo &STI) const; + /// getHiLoImmOpValue - Return the encoding for either the hi / low 16-bit, or + /// high/middle-high/middle-low/low 8 bits of the specified operand. This is + /// used for operands with :lower16:, :upper16: :lower0_7:, :lower8_15:, + /// :higher0_7:, and :higher8_15: prefixes. + uint32_t getHiLoImmOpValue(const MCInst &MI, unsigned OpIdx, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; bool EncodeAddrModeOpValues(const MCInst &MI, unsigned OpIdx, unsigned &Reg, unsigned &Imm, @@ -1190,17 +1191,18 @@ } uint32_t -ARMMCCodeEmitter::getHiLo16ImmOpValue(const MCInst &MI, unsigned OpIdx, +ARMMCCodeEmitter::getHiLoImmOpValue(const MCInst &MI, unsigned OpIdx, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { // {20-16} = imm{15-12} // {11-0} = imm{11-0} const MCOperand &MO = MI.getOperand(OpIdx); if (MO.isImm()) - // Hi / lo 16 bits already extracted during earlier passes. + // Hi / lo bits already extracted during earlier passes. return static_cast(MO.getImm()); - // Handle :upper16: and :lower16: assembly prefixes. + // Handle :upper16:, :lower16:, :upper8_15:, :upper0_7:, :lower8_15: + // :lower0_7: assembly prefixes. const MCExpr *E = MO.getExpr(); MCFixupKind Kind; if (E->getKind() == MCExpr::Target) { @@ -1217,6 +1219,16 @@ return (int32_t(Value) & 0xffff0000) >> 16; case ARMMCExpr::VK_ARM_LO16: return (int32_t(Value) & 0x0000ffff); + + case ARMMCExpr::VK_ARM_HI_8_15: + return (int32_t(Value) & 0xff000000) >> 24; + case ARMMCExpr::VK_ARM_HI_0_7: + return (int32_t(Value) & 0x00ff0000) >> 16; + case ARMMCExpr::VK_ARM_LO_8_15: + return (int32_t(Value) & 0x0000ff00) >> 8; + case ARMMCExpr::VK_ARM_LO_0_7: + return (int32_t(Value) & 0x000000ff); + default: llvm_unreachable("Unsupported ARMFixup"); } } @@ -1231,18 +1243,39 @@ Kind = MCFixupKind(isThumb(STI) ? ARM::fixup_t2_movw_lo16 : ARM::fixup_arm_movw_lo16); break; + case ARMMCExpr::VK_ARM_HI_8_15: + if (!isThumb(STI)) + llvm_unreachable(":upper_8_15: not supported in Arm state"); + Kind = MCFixupKind(ARM::fixup_arm_thumb_upper_8_15); + break; + case ARMMCExpr::VK_ARM_HI_0_7: + if (!isThumb(STI)) + llvm_unreachable(":upper_0_7: not supported in Arm state"); + Kind = MCFixupKind(ARM::fixup_arm_thumb_upper_0_7); + break; + case ARMMCExpr::VK_ARM_LO_8_15: + if (!isThumb(STI)) + llvm_unreachable(":lower_8_15: not supported in Arm state"); + Kind = MCFixupKind(ARM::fixup_arm_thumb_lower_8_15); + break; + case ARMMCExpr::VK_ARM_LO_0_7: + if (!isThumb(STI)) + llvm_unreachable(":lower_0_7: not supported in Arm state"); + Kind = MCFixupKind(ARM::fixup_arm_thumb_lower_0_7); + break; } Fixups.push_back(MCFixup::create(0, E, Kind, MI.getLoc())); return 0; } - // If the expression doesn't have :upper16: or :lower16: on it, - // it's just a plain immediate expression, previously those evaluated to - // the lower 16 bits of the expression regardless of whether - // we have a movt or a movw, but that led to misleadingly results. - // This is disallowed in the AsmParser in validateInstruction() - // so this should never happen. - llvm_unreachable("expression without :upper16: or :lower16:"); + // If the expression doesn't have :upper16:, :lower16: on it, it's just a + // plain immediate expression, previously those evaluated to the lower 16 bits + // of the expression regardless of whether we have a movt or a movw, but that + // led to misleadingly results. This is disallowed in the AsmParser in + // validateInstruction() so this should never happen. The same holds for + // thumb1 :upper8_15:, :upper0_7:, lower8_15: or :lower0_7: with movs or adds. + llvm_unreachable("expression without :upper16:, :lower16:, :upper8_15:," + ":upper0_7:, lower8_15: or :lower0_7:"); } uint32_t ARMMCCodeEmitter:: diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCExpr.h b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCExpr.h --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCExpr.h +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCExpr.h @@ -17,8 +17,17 @@ public: enum VariantKind { VK_ARM_None, - VK_ARM_HI16, // The R_ARM_MOVT_ABS relocation (:upper16: in the .s file) - VK_ARM_LO16 // The R_ARM_MOVW_ABS_NC relocation (:lower16: in the .s file) + VK_ARM_HI16, // The R_ARM_MOVT_ABS relocation (:upper16: in the .s file) + VK_ARM_LO16, // The R_ARM_MOVW_ABS_NC relocation (:lower16: in the .s file) + + VK_ARM_HI_8_15, // The R_ARM_THM_ALU_ABS_G3 relocation (:upper8_15: in + // the .s file) + VK_ARM_HI_0_7, // The R_ARM_THM_ALU_ABS_G2_NC relocation (:upper0_8: in the + // .s file) + VK_ARM_LO_8_15, // The R_ARM_THM_ALU_ABS_G1_NC relocation (:lower8_15: in + // the .s file) + VK_ARM_LO_0_7, // The R_ARM_THM_ALU_ABS_G0_NC relocation (:lower0_7: in the + // .s file) }; private: @@ -43,6 +52,22 @@ return create(VK_ARM_LO16, Expr, Ctx); } + static const ARMMCExpr *createUpper8_15(const MCExpr *Expr, MCContext &Ctx) { + return create(VK_ARM_HI_8_15, Expr, Ctx); + } + + static const ARMMCExpr *createUpper0_7(const MCExpr *Expr, MCContext &Ctx) { + return create(VK_ARM_HI_0_7, Expr, Ctx); + } + + static const ARMMCExpr *createLower8_15(const MCExpr *Expr, MCContext &Ctx) { + return create(VK_ARM_LO_8_15, Expr, Ctx); + } + + static const ARMMCExpr *createLower0_7(const MCExpr *Expr, MCContext &Ctx) { + return create(VK_ARM_LO_0_7, Expr, Ctx); + } + /// @} /// @name Accessors /// @{ diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCExpr.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCExpr.cpp --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCExpr.cpp +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCExpr.cpp @@ -24,6 +24,10 @@ default: llvm_unreachable("Invalid kind!"); case VK_ARM_HI16: OS << ":upper16:"; break; case VK_ARM_LO16: OS << ":lower16:"; break; + case VK_ARM_HI_8_15: OS << ":upper8_15:"; break; + case VK_ARM_HI_0_7: OS << ":upper0_7:"; break; + case VK_ARM_LO_8_15: OS << ":lower8_15:"; break; + case VK_ARM_LO_0_7: OS << ":lower0_7:"; break; } const MCExpr *Expr = getSubExpr(); diff --git a/llvm/test/MC/ARM/negative-immediates-thumb1-fail.s b/llvm/test/MC/ARM/negative-immediates-thumb1-fail.s --- a/llvm/test/MC/ARM/negative-immediates-thumb1-fail.s +++ b/llvm/test/MC/ARM/negative-immediates-thumb1-fail.s @@ -12,7 +12,7 @@ ADDs r0, #0xFFFFFEFF # CHECK: error: invalid instruction, any one of the following would fix this: # CHECK-DAG: note: invalid operand for instruction -# CHECK-DAG: note: operand must be an immediate in the range [0,255] +# CHECK-DAG: note: operand must be an immediate in the range [0,255] or a relocatable expression SUBs r1, r0, #0xFFFFFFF5 # CHECK: error: invalid instruction, any one of the following would fix this: diff --git a/llvm/test/MC/ARM/thumb-fixups.s b/llvm/test/MC/ARM/thumb-fixups.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/ARM/thumb-fixups.s @@ -0,0 +1,25 @@ +@ RUN: llvm-mc -triple armv6m-unknown-unknown %s --show-encoding > %t +@ RUN: FileCheck < %t %s + + movs r3, :upper8_15:_foo + adds r3, :upper0_7:_foo + adds r3, :lower8_15:_foo + adds r3, :lower0_7:_foo + +@ CHECK: movs r3, :upper8_15:_foo @ encoding: [A,0x23] +@ CHECK-NEXT: @ fixup A - offset: 0, value: _foo, kind: fixup_arm_thumb_upper_8_15 +@ CHECK-NEXT: adds r3, :upper0_7:_foo @ encoding: [A,0x33] +@ CHECK-NEXT: @ fixup A - offset: 0, value: _foo, kind: fixup_arm_thumb_upper_0_7 +@ CHECK-NEXT: adds r3, :lower8_15:_foo @ encoding: [A,0x33] +@ CHECK-NEXT: @ fixup A - offset: 0, value: _foo, kind: fixup_arm_thumb_lower_8_15 +@ CHECK-NEXT: adds r3, :lower0_7:_foo @ encoding: [A,0x33] +@ CHECK-NEXT: @ fixup A - offset: 0, value: _foo, kind: fixup_arm_thumb_lower_0_7 + +@ GNU syntax variants: + movs r3, #:upper8_15:#_foo + movs r3, #:upper8_15:_foo + +@ CHECK: movs r3, :upper8_15:_foo @ encoding: [A,0x23] +@ CHECK-NEXT: @ fixup A - offset: 0, value: _foo, kind: fixup_arm_thumb_upper_8_15 +@ CHECK-NEXT: movs r3, :upper8_15:_foo @ encoding: [A,0x23] +@ CHECK-NEXT: @ fixup A - offset: 0, value: _foo, kind: fixup_arm_thumb_upper_8_15