summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp75
-rw-r--r--llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h7
-rw-r--r--llvm/test/MC/ARM/big-endian-thumb2-fixup.s4
-rw-r--r--llvm/test/MC/ARM/thumb1-relax-adr-local.s9
-rw-r--r--llvm/test/MC/ARM/thumb1-relax-bcc-local.s6
-rw-r--r--llvm/test/MC/ARM/thumb1-relax-br-local.s8
-rw-r--r--llvm/test/MC/ARM/thumb1-relax-ldrlit-local-behind.s7
-rw-r--r--llvm/test/MC/ARM/thumb1-relax-ldrlit-local-misaligned.s10
-rw-r--r--llvm/test/MC/ARM/thumb1-relax-ldrlit-local-range.s13
9 files changed, 117 insertions, 22 deletions
diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
index 1fe2dbe7866..75d33212ac9 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
@@ -181,9 +181,8 @@ bool ARMAsmBackend::mayNeedRelaxation(const MCInst &Inst) const {
return false;
}
-bool ARMAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
- const MCRelaxableFragment *DF,
- const MCAsmLayout &Layout) const {
+const char *ARMAsmBackend::reasonForFixupRelaxation(const MCFixup &Fixup,
+ uint64_t Value) const {
switch ((unsigned)Fixup.getKind()) {
case ARM::fixup_arm_thumb_br: {
// Relaxing tB to t2B. tB has a signed 12-bit displacement with the
@@ -193,7 +192,9 @@ bool ARMAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
//
// Relax if the value is too big for a (signed) i8.
int64_t Offset = int64_t(Value) - 4;
- return Offset > 2046 || Offset < -2048;
+ if (Offset > 2046 || Offset < -2048)
+ return "out of range pc-relative fixup value";
+ break;
}
case ARM::fixup_arm_thumb_bcc: {
// Relaxing tBcc to t2Bcc. tBcc has a signed 9-bit displacement with the
@@ -203,23 +204,40 @@ bool ARMAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
//
// Relax if the value is too big for a (signed) i8.
int64_t Offset = int64_t(Value) - 4;
- return Offset > 254 || Offset < -256;
+ if (Offset > 254 || Offset < -256)
+ return "out of range pc-relative fixup value";
+ break;
}
case ARM::fixup_thumb_adr_pcrel_10:
case ARM::fixup_arm_thumb_cp: {
// If the immediate is negative, greater than 1020, or not a multiple
// of four, the wide version of the instruction must be used.
int64_t Offset = int64_t(Value) - 4;
- return Offset > 1020 || Offset < 0 || Offset & 3;
+ if (Offset & 3)
+ return "misaligned pc-relative fixup value";
+ else if (Offset > 1020 || Offset < 0)
+ return "out of range pc-relative fixup value";
+ break;
}
- case ARM::fixup_arm_thumb_cb:
+ case ARM::fixup_arm_thumb_cb: {
// If we have a Thumb CBZ or CBNZ instruction and its target is the next
// instruction it is is actually out of range for the instruction.
// It will be changed to a NOP.
int64_t Offset = (Value & ~1);
- return Offset == 2;
+ if (Offset == 2)
+ return "will be converted to nop";
+ break;
}
- llvm_unreachable("Unexpected fixup kind in fixupNeedsRelaxation()!");
+ default:
+ llvm_unreachable("Unexpected fixup kind in reasonForFixupRelaxation()!");
+ }
+ return nullptr;
+}
+
+bool ARMAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
+ const MCRelaxableFragment *DF,
+ const MCAsmLayout &Layout) const {
+ return reasonForFixupRelaxation(Fixup, Value);
}
void ARMAsmBackend::relaxInstruction(const MCInst &Inst, MCInst &Res) const {
@@ -318,9 +336,10 @@ static uint32_t joinHalfWords(uint32_t FirstHalf, uint32_t SecondHalf,
return Value;
}
-static unsigned adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
- bool IsPCRel, MCContext *Ctx,
- bool IsLittleEndian) {
+unsigned ARMAsmBackend::adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
+ bool IsPCRel, MCContext *Ctx,
+ bool IsLittleEndian,
+ bool IsResolved) const {
unsigned Kind = Fixup.getKind();
switch (Kind) {
default:
@@ -384,8 +403,6 @@ static unsigned adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
return Value;
}
- case ARM::fixup_thumb_adr_pcrel_10:
- return ((Value - 4) >> 2) & 0xff;
case ARM::fixup_arm_adr_pcrel_12: {
// ARM PC-relative values are offset by 8.
Value -= 8;
@@ -518,21 +535,38 @@ static unsigned adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
((uint16_t)imm10LBits) << 1);
return joinHalfWords(FirstHalf, SecondHalf, IsLittleEndian);
}
+ case ARM::fixup_thumb_adr_pcrel_10:
case ARM::fixup_arm_thumb_cp:
- // Offset by 4, and don't encode the low two bits. Two bytes of that
- // 'off by 4' is implicitly handled by the half-word ordering of the
- // Thumb encoding, so we only need to adjust by 2 here.
- return ((Value - 2) >> 2) & 0xff;
+ // On CPUs supporting Thumb2, this will be relaxed to an ldr.w, otherwise we
+ // could have an error on our hands.
+ if (Ctx && !STI->getFeatureBits()[ARM::FeatureThumb2] && IsResolved) {
+ const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
+ if (FixupDiagnostic)
+ Ctx->reportFatalError(Fixup.getLoc(), FixupDiagnostic);
+ }
+ // Offset by 4, and don't encode the low two bits.
+ return ((Value - 4) >> 2) & 0xff;
case ARM::fixup_arm_thumb_cb: {
// Offset by 4 and don't encode the lower bit, which is always 0.
+ // FIXME: diagnose if no Thumb2
uint32_t Binary = (Value - 4) >> 1;
return ((Binary & 0x20) << 4) | ((Binary & 0x1f) << 3);
}
case ARM::fixup_arm_thumb_br:
// Offset by 4 and don't encode the lower bit, which is always 0.
+ if (Ctx && !STI->getFeatureBits()[ARM::FeatureThumb2]) {
+ const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
+ if (FixupDiagnostic)
+ Ctx->reportFatalError(Fixup.getLoc(), FixupDiagnostic);
+ }
return ((Value - 4) >> 1) & 0x7ff;
case ARM::fixup_arm_thumb_bcc:
// Offset by 4 and don't encode the lower bit, which is always 0.
+ if (Ctx && !STI->getFeatureBits()[ARM::FeatureThumb2]) {
+ const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
+ if (FixupDiagnostic)
+ Ctx->reportFatalError(Fixup.getLoc(), FixupDiagnostic);
+ }
return ((Value - 4) >> 1) & 0xff;
case ARM::fixup_arm_pcrel_10_unscaled: {
Value = Value - 8; // ARM fixups offset by an additional word and don't
@@ -617,7 +651,7 @@ void ARMAsmBackend::processFixupValue(const MCAssembler &Asm,
// the instruction. This allows adjustFixupValue() to issue a diagnostic
// if the value aren't invalid.
(void)adjustFixupValue(Fixup, Value, false, &Asm.getContext(),
- IsLittleEndian);
+ IsLittleEndian, IsResolved);
}
/// getFixupKindNumBytes - The number of bytes the fixup may change.
@@ -720,7 +754,8 @@ void ARMAsmBackend::applyFixup(const MCFixup &Fixup, char *Data,
unsigned DataSize, uint64_t Value,
bool IsPCRel) const {
unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
- Value = adjustFixupValue(Fixup, Value, IsPCRel, nullptr, IsLittleEndian);
+ Value =
+ adjustFixupValue(Fixup, Value, IsPCRel, nullptr, IsLittleEndian, true);
if (!Value)
return; // Doesn't change encoding.
diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h b/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h
index 6b4abd5898e..28a62132a41 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h
@@ -45,6 +45,10 @@ public:
const MCValue &Target, uint64_t &Value,
bool &IsResolved) override;
+ unsigned adjustFixupValue(const MCFixup &Fixup, uint64_t Value, bool IsPCRel,
+ MCContext *Ctx, bool IsLittleEndian,
+ bool IsResolved) const;
+
void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
uint64_t Value, bool IsPCRel) const override;
@@ -52,6 +56,9 @@ public:
bool mayNeedRelaxation(const MCInst &Inst) const override;
+ const char *reasonForFixupRelaxation(const MCFixup &Fixup,
+ uint64_t Value) const;
+
bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
const MCRelaxableFragment *DF,
const MCAsmLayout &Layout) const override;
diff --git a/llvm/test/MC/ARM/big-endian-thumb2-fixup.s b/llvm/test/MC/ARM/big-endian-thumb2-fixup.s
index 4fd5276fce6..0aaa26a209f 100644
--- a/llvm/test/MC/ARM/big-endian-thumb2-fixup.s
+++ b/llvm/test/MC/ARM/big-endian-thumb2-fixup.s
@@ -35,14 +35,14 @@ cond_label:
@ARM::fixup_t2_ldst_precel_12
.section s_ldst_precel_12,"ax",%progbits
- ldr r0, ldst_precel_12_label
+ ldr.w r0, ldst_precel_12_label
nop
nop
ldst_precel_12_label:
@ARM::fixup_t2_adr_pcrel_12
.section s_adr_pcrel_12,"ax",%progbits
- adr r0, adr_pcrel_12_label
+ adr.w r0, adr_pcrel_12_label
nop
nop
adr_pcrel_12_label:
diff --git a/llvm/test/MC/ARM/thumb1-relax-adr-local.s b/llvm/test/MC/ARM/thumb1-relax-adr-local.s
new file mode 100644
index 00000000000..65d62f2f097
--- /dev/null
+++ b/llvm/test/MC/ARM/thumb1-relax-adr-local.s
@@ -0,0 +1,9 @@
+@ RUN: not llvm-mc -triple thumbv6m-none-macho -filetype=obj -o /dev/null %s 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s
+
+ .global func1
+ adr r0, Lmisaligned
+Lmisaligned:
+ .word 42
+
+@ CHECK-ERROR: misaligned pc-relative fixup value
+
diff --git a/llvm/test/MC/ARM/thumb1-relax-bcc-local.s b/llvm/test/MC/ARM/thumb1-relax-bcc-local.s
new file mode 100644
index 00000000000..9cb4877ed5a
--- /dev/null
+++ b/llvm/test/MC/ARM/thumb1-relax-bcc-local.s
@@ -0,0 +1,6 @@
+@ RUN: not llvm-mc -triple thumbv6m-none-macho -filetype=obj -o /dev/null %s 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s
+
+ bne Lfar
+ .space 258
+Lfar:
+@ CHECK-ERROR: out of range pc-relative fixup value
diff --git a/llvm/test/MC/ARM/thumb1-relax-br-local.s b/llvm/test/MC/ARM/thumb1-relax-br-local.s
new file mode 100644
index 00000000000..1635d061acf
--- /dev/null
+++ b/llvm/test/MC/ARM/thumb1-relax-br-local.s
@@ -0,0 +1,8 @@
+@ RUN: not llvm-mc -triple thumbv6m-none-macho -filetype=obj -o /dev/null %s 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s
+
+ b Lfar
+ .space 2050
+
+Lfar:
+
+@ CHECK-ERROR: out of range pc-relative fixup value
diff --git a/llvm/test/MC/ARM/thumb1-relax-ldrlit-local-behind.s b/llvm/test/MC/ARM/thumb1-relax-ldrlit-local-behind.s
new file mode 100644
index 00000000000..0c519141b99
--- /dev/null
+++ b/llvm/test/MC/ARM/thumb1-relax-ldrlit-local-behind.s
@@ -0,0 +1,7 @@
+@ RUN: not llvm-mc -triple thumbv6m-none-macho -filetype=obj -o /dev/null %s 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s
+
+Lhere:
+ ldr r0, Lhere
+
+@ CHECK-ERROR: out of range pc-relative fixup value
+
diff --git a/llvm/test/MC/ARM/thumb1-relax-ldrlit-local-misaligned.s b/llvm/test/MC/ARM/thumb1-relax-ldrlit-local-misaligned.s
new file mode 100644
index 00000000000..9566f8afa17
--- /dev/null
+++ b/llvm/test/MC/ARM/thumb1-relax-ldrlit-local-misaligned.s
@@ -0,0 +1,10 @@
+@ RUN: not llvm-mc -triple thumbv6m-none-macho -filetype=obj -o /dev/null %s 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s
+
+ .global func1
+_func1:
+ ldr r0, L_misaligned
+L_misaligned:
+ .word 42
+
+@ CHECK-ERROR: misaligned pc-relative fixup value
+
diff --git a/llvm/test/MC/ARM/thumb1-relax-ldrlit-local-range.s b/llvm/test/MC/ARM/thumb1-relax-ldrlit-local-range.s
new file mode 100644
index 00000000000..f8899698a7d
--- /dev/null
+++ b/llvm/test/MC/ARM/thumb1-relax-ldrlit-local-range.s
@@ -0,0 +1,13 @@
+@ RUN: not llvm-mc -triple thumbv6m-none-macho -filetype=obj -o /dev/null %s 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s
+
+ .global func1
+_func1:
+ ldr r0, L_far
+ .space 1024
+
+ .p2align 2
+L_far:
+ .word 42
+
+@ CHECK-ERROR: out of range pc-relative fixup value
+
OpenPOWER on IntegriCloud