[llvm] dc49fbd - [ARM] add Thumb-1 8-bit movs/adds relocations to LLVM
Ties Stuij via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 22 08:35:51 PDT 2023
Author: Ties Stuij
Date: 2023-06-22T16:35:13+01:00
New Revision: dc49fbd2df7dd7236dda0d94c1f091aeba532886
URL: https://github.com/llvm/llvm-project/commit/dc49fbd2df7dd7236dda0d94c1f091aeba532886
DIFF: https://github.com/llvm/llvm-project/commit/dc49fbd2df7dd7236dda0d94c1f091aeba532886.diff
LOG: [ARM] add Thumb-1 8-bit movs/adds relocations to LLVM
This patch adds the LLVM-side plumbing for the following relocations:
- R_ARM_THM_ALU_ABS_G0_NC
- R_ARM_THM_ALU_ABS_G1_NC
- R_ARM_THM_ALU_ABS_G2_NC
- R_ARM_THM_ALU_ABS_G3
(see section 5.6.1.5, Static Thumb16 relocations, of the AArch32 ELF Arm ABI:
https://github.com/ARM-software/abi-aa/blob/844a79fd4c77252a11342709e3b27b2c9f590cf1/aaelf32/aaelf32.rst#5615static-thumb16-relocations)
Which can respectivly be generated by prefixing assembly symbols with:
- :lower0_7:
- :lower8_15:
- :upper0_7:
- :upper8_15:
LLD support for these relocations will be added in a follow-up patch
Reviewed By: john.brawn, MaskRay
Differential Revision: https://reviews.llvm.org/D149443
Added:
llvm/test/MC/ARM/thumb-8-bit-relocs.s
llvm/test/MC/ARM/thumb-fixups.s
Modified:
llvm/include/llvm/BinaryFormat/ELFRelocs/ARM.def
llvm/lib/Target/ARM/ARMInstrInfo.td
llvm/lib/Target/ARM/ARMInstrThumb.td
llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
llvm/lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h
llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp
llvm/lib/Target/ARM/MCTargetDesc/ARMMCExpr.cpp
llvm/lib/Target/ARM/MCTargetDesc/ARMMCExpr.h
llvm/test/MC/ARM/negative-immediates-thumb1-fail.s
llvm/test/MC/ARM/thumb-diagnostics.s
Removed:
################################################################################
diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/ARM.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/ARM.def
index e0709fb818134..47084d1eb0aad 100644
--- a/llvm/include/llvm/BinaryFormat/ELFRelocs/ARM.def
+++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/ARM.def
@@ -135,6 +135,10 @@ ELF_RELOC(R_ARM_PRIVATE_15, 0x7f)
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
index a32478e6ddfbf..471b706cc408a 100644
--- a/llvm/lib/Target/ARM/ARMInstrInfo.td
+++ b/llvm/lib/Target/ARM/ARMInstrInfo.td
@@ -965,6 +965,19 @@ def imm0_255 : Operand<i32>, ImmLeaf<i32, [{ return Imm >= 0 && Imm < 256; }]> {
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<i32>, ImmLeaf<i32, [{ return Imm >= 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<i32>, ImmLeaf<i32, [{
@@ -990,8 +1003,10 @@ def Imm0_65535ExprAsmOperand: AsmOperandClass {
let DiagnosticString = "operand must be an immediate in the range [0,0xffff] or a relocatable expression";
}
-def imm0_65535_expr : Operand<i32> {
- let EncoderMethod = "getHiLo16ImmOpValue";
+def imm0_65535_expr : Operand<i32>, ImmLeaf<i32, [{
+ return Imm >= 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
index bb03d2e2b1fe5..7849133b4322f 100644
--- a/llvm/lib/Target/ARM/ARMInstrThumb.td
+++ b/llvm/lib/Target/ARM/ARMInstrThumb.td
@@ -984,9 +984,9 @@ let isAdd = 1 in {
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 @@ let isAdd = 1 in {
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 @@ let isAdd = 1 in {
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 @@ def tLSRrr : // A8.6.91
// 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 @@ def tMOVi8 : T1sI<(outs tGPR:$Rd), (ins imm0_255:$imm8), IIC_iMOVi,
}
// 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
index 4007161ce3a95..7820cfd51da4a 100644
--- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -1232,6 +1232,18 @@ class ARMOperand : public MCParsedAsmOperand {
return isImmediate<8, 255>();
}
+ bool isImm0_255Expr() const {
+ if (!isImm())
+ return false;
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(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 isUInt<8>(Value);
+ }
+
bool isImm256_65535Expr() const {
if (!isImm()) return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
@@ -6272,7 +6284,8 @@ bool ARMAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
}
case AsmToken::Colon: {
S = Parser.getTok().getLoc();
- // ":lower16:" and ":upper16:" expression prefixes
+ // ":lower16:", ":upper16:", ":lower0_7:", ":lower8_15:", ":upper0_7:" and
+ // ":upper8_15:", expression prefixes
// FIXME: Check it's an expression prefix,
// e.g. (FOO - :lower16:BAR) isn't legal.
ARMMCExpr::VariantKind RefKind;
@@ -6319,8 +6332,9 @@ bool ARMAsmParser::parseImmExpr(int64_t &Out) {
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 +6343,6 @@ bool ARMAsmParser::parsePrefix(ARMMCExpr::VariantKind &RefKind) {
if (getLexer().is(AsmToken::Hash))
Parser.Lex();
- // :lower16: and :upper16: modifiers
assert(getLexer().is(AsmToken::Colon) && "expected a :");
Parser.Lex(); // Eat ':'
@@ -6349,8 +6362,12 @@ bool ARMAsmParser::parsePrefix(ARMMCExpr::VariantKind &RefKind) {
ARMMCExpr::VariantKind VariantKind;
uint8_t SupportedFormats;
} PrefixEntries[] = {
- { "lower16", ARMMCExpr::VK_ARM_LO16, COFF | ELF | MACHO },
- { "upper16", ARMMCExpr::VK_ARM_HI16, 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 +6418,9 @@ bool ARMAsmParser::parsePrefix(ARMMCExpr::VariantKind &RefKind) {
}
Parser.Lex(); // Eat the last ':'
+ // consume an optional trailing '#' (GNU compatibility) bla
+ parseOptionalToken(AsmToken::Hash);
+
return false;
}
@@ -6711,6 +6731,27 @@ void ARMAsmParser::tryConvertingToTwoOperandForm(StringRef Mnemonic,
}
}
+// this function returns true if the operand is one of the following
+// relocations: :upper8_15:, :upper0_7:, :lower8_15: or :lower0_7:
+static bool isThumbI8Relocation(MCParsedAsmOperand &MCOp) {
+ ARMOperand &Op = static_cast<ARMOperand &>(MCOp);
+ if (!Op.isImm())
+ return false;
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Op.getImm());
+ if (CE)
+ return false;
+ const MCExpr *E = dyn_cast<MCExpr>(Op.getImm());
+ if (!E)
+ return false;
+ const ARMMCExpr *ARM16Expr = dyn_cast<ARMMCExpr>(E);
+ if (ARM16Expr && (ARM16Expr->getKind() == ARMMCExpr::VK_ARM_HI_8_15 ||
+ ARM16Expr->getKind() == ARMMCExpr::VK_ARM_HI_0_7 ||
+ ARM16Expr->getKind() == ARMMCExpr::VK_ARM_LO_8_15 ||
+ ARM16Expr->getKind() == ARMMCExpr::VK_ARM_LO_0_7))
+ return true;
+ return false;
+}
+
bool ARMAsmParser::shouldOmitCCOutOperand(StringRef Mnemonic,
OperandVector &Operands) {
// FIXME: This is all horribly hacky. We really need a better way to deal
@@ -6730,6 +6771,10 @@ bool ARMAsmParser::shouldOmitCCOutOperand(StringRef Mnemonic,
static_cast<ARMOperand &>(*Operands[1]).getReg() == 0)
return true;
+ if (Mnemonic == "movs" && Operands.size() > 3 && isThumb() &&
+ isThumbI8Relocation(*Operands[3]))
+ return true;
+
// Register-register 'add' for thumb does not have a cc_out operand
// when there are only two register operands.
if (isThumb() && Mnemonic == "add" && Operands.size() == 5 &&
@@ -7614,6 +7659,19 @@ static bool isVectorPredicable(const MCInstrDesc &MCID) {
return findFirstVectorPredOperandIdx(MCID) != -1;
}
+static bool isARMMCExpr(MCParsedAsmOperand &MCOp) {
+ ARMOperand &Op = static_cast<ARMOperand &>(MCOp);
+ if (!Op.isImm())
+ return false;
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Op.getImm());
+ if (CE)
+ return false;
+ const MCExpr *E = dyn_cast<MCExpr>(Op.getImm());
+ if (!E)
+ return false;
+ return true;
+}
+
// FIXME: We would really like to be able to tablegen'erate this.
bool ARMAsmParser::validateInstruction(MCInst &Inst,
const OperandVector &Operands) {
@@ -8223,6 +8281,22 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
"immediate expression for mov requires :lower16: or :upper16");
break;
}
+ case ARM::tADDi8: {
+ MCParsedAsmOperand &Op = *Operands[4];
+ if (isARMMCExpr(Op) && !isThumbI8Relocation(Op))
+ return Error(Op.getStartLoc(),
+ "Immediate expression for Thumb adds requires :lower0_7:,"
+ " :lower8_15:, :upper0_7: or :upper8_15:");
+ break;
+ }
+ case ARM::tMOVi8: {
+ MCParsedAsmOperand &Op = *Operands[2];
+ if (isARMMCExpr(Op) && !isThumbI8Relocation(Op))
+ return Error(Op.getStartLoc(),
+ "Immediate expression for Thumb movs requires :lower0_7:,"
+ " :lower8_15:, :upper0_7: or :upper8_15:");
+ break;
+ }
case ARM::HINT:
case ARM::t2HINT: {
unsigned Imm8 = Inst.getOperand(0).getImm();
@@ -10541,7 +10615,8 @@ bool ARMAsmParser::processInstruction(MCInst &Inst,
// explicitly specified. From the ARM ARM: "Encoding T1 is preferred
// to encoding T2 if <Rd> is specified and encoding T2 is preferred
// to encoding T1 if <Rd> 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
index ea1363413b4a1..7016918046203 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
@@ -114,6 +114,10 @@ const MCFixupKindInfo &ARMAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
{"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 @@ const MCFixupKindInfo &ARMAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
{"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,20 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
Value = (Hi4 << 16) | (i << 26) | (Mid3 << 12) | (Lo8);
return swapHalfWords(Value, Endian == support::little);
}
+ case ARM::fixup_arm_thumb_upper_8_15:
+ if (IsResolved || !STI->getTargetTriple().isOSBinFormatELF())
+ return (Value & 0xff000000) >> 24;
+ return Value & 0xff;
+ case ARM::fixup_arm_thumb_upper_0_7:
+ if (IsResolved || !STI->getTargetTriple().isOSBinFormatELF())
+ return (Value & 0x00ff0000) >> 16;
+ return Value & 0xff;
+ case ARM::fixup_arm_thumb_lower_8_15:
+ if (IsResolved || !STI->getTargetTriple().isOSBinFormatELF())
+ return (Value & 0x0000ff00) >> 8;
+ return Value & 0xff;
+ 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 +953,10 @@ static unsigned getFixupKindNumBytes(unsigned Kind) {
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 +1027,10 @@ static unsigned getFixupKindContainerSizeBytes(unsigned Kind) {
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
index 2a6bda6ccd810..caebace2eb786 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
@@ -137,6 +137,14 @@ unsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target,
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 @@ unsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target,
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
index 53258a88c7fa2..3bcea577b9b63 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h
@@ -99,6 +99,12 @@ enum Fixups {
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
index 6843b130c90e7..dae323ec24fb1 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp
@@ -87,12 +87,13 @@ class ARMMCCodeEmitter : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &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<MCFixup> &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<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
bool EncodeAddrModeOpValues(const MCInst &MI, unsigned OpIdx,
unsigned &Reg, unsigned &Imm,
@@ -1189,18 +1190,18 @@ getT2AddrModeImm0_1020s4OpValue(const MCInst &MI, unsigned OpIdx,
return (Reg << 8) | Imm8;
}
-uint32_t
-ARMMCCodeEmitter::getHiLo16ImmOpValue(const MCInst &MI, unsigned OpIdx,
- SmallVectorImpl<MCFixup> &Fixups,
- const MCSubtargetInfo &STI) const {
+uint32_t ARMMCCodeEmitter::getHiLoImmOpValue(const MCInst &MI, unsigned OpIdx,
+ SmallVectorImpl<MCFixup> &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<unsigned>(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 +1218,16 @@ ARMMCCodeEmitter::getHiLo16ImmOpValue(const MCInst &MI, unsigned OpIdx,
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 +1242,39 @@ ARMMCCodeEmitter::getHiLo16ImmOpValue(const MCInst &MI, unsigned OpIdx,
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.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCExpr.cpp
index fbad05fb1759f..6be308f4e712a 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCExpr.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCExpr.cpp
@@ -22,8 +22,24 @@ ARMMCExpr::create(VariantKind Kind, const MCExpr *Expr,
void ARMMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
switch (Kind) {
default: llvm_unreachable("Invalid kind!");
- case VK_ARM_HI16: OS << ":upper16:"; break;
- case VK_ARM_LO16: OS << ":lower16:"; break;
+ 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/lib/Target/ARM/MCTargetDesc/ARMMCExpr.h b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCExpr.h
index 033a43288f3ee..edeff9c4ced2d 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCExpr.h
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCExpr.h
@@ -17,8 +17,17 @@ class ARMMCExpr : public MCTargetExpr {
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 @@ class ARMMCExpr : public MCTargetExpr {
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/test/MC/ARM/negative-immediates-thumb1-fail.s b/llvm/test/MC/ARM/negative-immediates-thumb1-fail.s
index 70e01ff1f82c1..5fca2110d5bed 100644
--- 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 r1, r0, #0xFFFFFFF5
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-8-bit-relocs.s b/llvm/test/MC/ARM/thumb-8-bit-relocs.s
new file mode 100644
index 0000000000000..cd13df98223ba
--- /dev/null
+++ b/llvm/test/MC/ARM/thumb-8-bit-relocs.s
@@ -0,0 +1,35 @@
+@ RUN: llvm-mc -triple thumbv6m-eabi -o - %s | FileCheck %s
+@ RUN: llvm-mc -triple thumbv6m-eabi -filetype obj -o - %s | llvm-readobj -r - \
+@ RUN: | FileCheck -check-prefix CHECK-RELOCATIONS %s
+@ RUN: llvm-mc -triple thumbv7m-eabi -o - %s | FileCheck %s
+@ RUN: llvm-mc -triple thumbv7m-eabi -filetype obj -o - %s | llvm-readobj -r - \
+@ RUN: | FileCheck -check-prefix CHECK-RELOCATIONS %s
+
+.syntax unified
+
+.type function,%function
+function:
+ bx lr
+
+.global external
+.type external,%function
+
+.type test,%function
+test:
+ movs r3, :upper8_15:function
+ adds r3, :upper0_7:function
+ adds r3, :lower8_15:function
+ adds r3, :lower0_7:function
+
+@ CHECK-LABEL: test:
+@ CHECK: movs r3, :upper8_15:function
+@ CHECK: adds r3, :upper0_7:function
+@ CHECK: adds r3, :lower8_15:function
+@ CHECK: adds r3, :lower0_7:function
+
+@ CHECK-RELOCATIONS: Relocations [
+@ CHECK-RELOCATIONS: 0x2 R_ARM_THM_ALU_ABS_G3 function
+@ CHECK-RELOCATIONS-NEXT: 0x4 R_ARM_THM_ALU_ABS_G2_NC function
+@ CHECK-RELOCATIONS-NEXT: 0x6 R_ARM_THM_ALU_ABS_G1_NC function
+@ CHECK-RELOCATIONS-NEXT: 0x8 R_ARM_THM_ALU_ABS_G0_NC function
+@ CHECK-RELOCATIONS: ]
diff --git a/llvm/test/MC/ARM/thumb-diagnostics.s b/llvm/test/MC/ARM/thumb-diagnostics.s
index 7179bd89e07c9..cacd7f21cb9d3 100644
--- a/llvm/test/MC/ARM/thumb-diagnostics.s
+++ b/llvm/test/MC/ARM/thumb-diagnostics.s
@@ -195,6 +195,34 @@
@ CHECK-ERRORS: note: operand must be an immediate in the range [0,31]
@ CHECK-ERRORS: note: too many operands for instruction
+@ Out of range immediates for MOVS/ADDS instruction.
+ movs r3, #-1
+ adds r3, #256
+@ CHECK-ERRORS: error: invalid instruction, any one of the following would fix this:
+@ CHECK-ERRORS-NEXT: movs r3, #-1
+@ CHECK-ERRORS-NEXT: ^
+@ CHECK-ERRORS: note: operand must be an immediate in the range [0,255] or a relocatable expression
+@ CHECK-ERRORS-NEXT: movs r3, #-1
+@ CHECK-ERRORS-NEXT: ^
+@ CHECK-ERRORS: note: operand must be a register in range [r0, r7]
+@ CHECK-ERRORS-NEXT: movs r3, #-1
+@ CHECK-ERRORS-NEXT: ^
+@ CHECK-ERRORS: error: invalid instruction, any one of the following would fix this:
+@ CHECK-ERRORS-NEXT: adds r3, #256
+@ CHECK-ERRORS-NEXT: ^
+@ CHECK-ERRORS: note: instruction requires: thumb2
+@ CHECK-ERRORS-NEXT: adds r3, #256
+@ CHECK-ERRORS-NEXT: ^
+@ CHECK-ERRORS: note: invalid operand for instruction
+@ CHECK-ERRORS-NEXT: adds r3, #256
+@ CHECK-ERRORS-NEXT: ^
+@ CHECK-ERRORS-NEXT: note: operand must be an immediate in the range [0,255] or a relocatable expression
+@ CHECK-ERRORS-NEXT: adds r3, #256
+@ CHECK-ERRORS-NEXT: ^
+@ CHECK-ERRORS-NEXT: note: operand must be a register in range [r0, r7]
+@ CHECK-ERRORS-NEXT: adds r3, #256
+@ CHECK-ERRORS-NEXT: ^
+
@ Mismatched source/destination operands for MUL instruction.
muls r1, r2, r3
@ CHECK-ERRORS: error: destination register must match source register
diff --git a/llvm/test/MC/ARM/thumb-fixups.s b/llvm/test/MC/ARM/thumb-fixups.s
new file mode 100644
index 0000000000000..b2d54df6d4a05
--- /dev/null
+++ b/llvm/test/MC/ARM/thumb-fixups.s
@@ -0,0 +1,25 @@
+@ RUN: llvm-mc -triple armv6m-unknown-unknown %s --show-encoding -o - | \
+@ RUN: FileCheck %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
More information about the llvm-commits
mailing list