summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp15
-rw-r--r--llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp20
-rw-r--r--llvm/lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h3
-rw-r--r--llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp12
-rw-r--r--llvm/test/MC/ARM/big-endian-thumb2-fixup.s6
-rw-r--r--llvm/test/MC/ARM/t2-modified-immediate-fixup-error1.s13
-rw-r--r--llvm/test/MC/ARM/t2-modified-immediate-fixup-error2.s12
-rw-r--r--llvm/test/MC/ARM/t2-modified-immediate-fixup.s45
-rw-r--r--llvm/test/MC/ARM/thumb2-diagnostics.s2
9 files changed, 123 insertions, 5 deletions
diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
index ada816c1638..93b341fce8f 100644
--- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -1026,6 +1026,15 @@ public:
ARM_AM::getSOImmVal(-Value) != -1);
}
bool isT2SOImm() const {
+ // If we have an immediate that's not a constant, treat it as an expression
+ // needing a fixup.
+ if (isImm() && !isa<MCConstantExpr>(getImm())) {
+ // We want to avoid matching :upper16: and :lower16: as we want these
+ // expressions to match in isImm0_65535Expr()
+ const ARMMCExpr *ARM16Expr = dyn_cast<ARMMCExpr>(getImm());
+ return (!ARM16Expr || (ARM16Expr->getKind() != ARMMCExpr::VK_ARM_HI16 &&
+ ARM16Expr->getKind() != ARMMCExpr::VK_ARM_LO16));
+ }
if (!isImm()) return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
@@ -8404,7 +8413,8 @@ bool ARMAsmParser::processInstruction(MCInst &Inst,
// wide encoding wasn't explicit.
if (Inst.getOperand(0).getReg() != Inst.getOperand(1).getReg() ||
!isARMLowRegister(Inst.getOperand(0).getReg()) ||
- (unsigned)Inst.getOperand(2).getImm() > 255 ||
+ (Inst.getOperand(2).isImm() &&
+ (unsigned)Inst.getOperand(2).getImm() > 255) ||
((!inITBlock() && Inst.getOperand(5).getReg() != ARM::CPSR) ||
(inITBlock() && Inst.getOperand(5).getReg() != 0)) ||
(static_cast<ARMOperand &>(*Operands[3]).isToken() &&
@@ -8556,7 +8566,8 @@ bool ARMAsmParser::processInstruction(MCInst &Inst,
// If we can use the 16-bit encoding and the user didn't explicitly
// request the 32-bit variant, transform it here.
if (isARMLowRegister(Inst.getOperand(0).getReg()) &&
- (unsigned)Inst.getOperand(1).getImm() <= 255 &&
+ (Inst.getOperand(1).isImm() &&
+ (unsigned)Inst.getOperand(1).getImm() <= 255) &&
((!inITBlock() && Inst.getOperand(2).getImm() == ARMCC::AL &&
Inst.getOperand(4).getReg() == ARM::CPSR) ||
(inITBlock() && Inst.getOperand(4).getReg() == 0)) &&
diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
index b0d1d3fb9ef..2ac9b98d98c 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
@@ -98,6 +98,7 @@ const MCFixupKindInfo &ARMAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
{"fixup_t2_movt_hi16", 0, 20, 0},
{"fixup_t2_movw_lo16", 0, 20, 0},
{"fixup_arm_mod_imm", 0, 12, 0},
+ {"fixup_t2_so_imm", 0, 26, 0},
};
const static MCFixupKindInfo InfosBE[ARM::NumTargetFixupKinds] = {
// This table *must* be in the order that the fixup_* kinds are defined in
@@ -148,6 +149,7 @@ const MCFixupKindInfo &ARMAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
{"fixup_t2_movt_hi16", 12, 20, 0},
{"fixup_t2_movw_lo16", 12, 20, 0},
{"fixup_arm_mod_imm", 20, 12, 0},
+ {"fixup_t2_so_imm", 26, 6, 0},
};
if (Kind < FirstTargetFixupKind)
@@ -693,6 +695,22 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
return 0;
}
return Value;
+ case ARM::fixup_t2_so_imm:
+ Value = ARM_AM::getT2SOImmVal(Value);
+ if ((int64_t)Value < 0) {
+ Ctx.reportError(Fixup.getLoc(), "out of range immediate fixup value");
+ return 0;
+ }
+ // Value will contain a 12-bit value broken up into a 4-bit shift in bits
+ // 11:8 and the 8-bit immediate in 0:7. The instruction has the immediate
+ // in 0:7. The 4-bit shift is split up into i:imm3 where i is placed at bit
+ // 10 of the upper half-word and imm3 is placed at 14:12 of the lower
+ // half-word.
+ uint64_t EncValue = 0;
+ EncValue |= (Value & 0x800) << 15;
+ EncValue |= (Value & 0x700) << 4;
+ EncValue |= (Value & 0xff);
+ return swapHalfWords(EncValue, IsLittleEndian);
}
}
@@ -792,6 +810,7 @@ static unsigned getFixupKindNumBytes(unsigned Kind) {
case ARM::fixup_arm_movw_lo16:
case ARM::fixup_t2_movt_hi16:
case ARM::fixup_t2_movw_lo16:
+ case ARM::fixup_t2_so_imm:
return 4;
case FK_SecRel_2:
@@ -844,6 +863,7 @@ static unsigned getFixupKindContainerSizeBytes(unsigned Kind) {
case ARM::fixup_t2_movt_hi16:
case ARM::fixup_t2_movw_lo16:
case ARM::fixup_arm_mod_imm:
+ case ARM::fixup_t2_so_imm:
// Instruction size is 4 bytes.
return 4;
}
diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h b/llvm/lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h
index 3fe2302bdd3..9f6c5d7bf92 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h
@@ -110,6 +110,9 @@ enum Fixups {
// fixup_arm_mod_imm - Fixup for mod_imm
fixup_arm_mod_imm,
+ // fixup_t2_so_imm - Fixup for Thumb2 8-bit rotated operand
+ fixup_t2_so_imm,
+
// Marker
LastTargetFixupKind,
NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp
index d9df2c6da7e..f1f35f40990 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp
@@ -339,7 +339,17 @@ public:
unsigned getT2SOImmOpValue(const MCInst &MI, unsigned Op,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
- unsigned SoImm = MI.getOperand(Op).getImm();
+ const MCOperand &MO = MI.getOperand(Op);
+
+ // Support for fixups (MCFixup)
+ if (MO.isExpr()) {
+ const MCExpr *Expr = MO.getExpr();
+ // Fixups resolve to plain values that need to be encoded.
+ MCFixupKind Kind = MCFixupKind(ARM::fixup_t2_so_imm);
+ Fixups.push_back(MCFixup::create(0, Expr, Kind, MI.getLoc()));
+ return 0;
+ }
+ unsigned SoImm = MO.getImm();
unsigned Encoded = ARM_AM::getT2SOImmVal(SoImm);
assert(Encoded != ~0U && "Not a Thumb2 so_imm value?");
return Encoded;
diff --git a/llvm/test/MC/ARM/big-endian-thumb2-fixup.s b/llvm/test/MC/ARM/big-endian-thumb2-fixup.s
index 0aaa26a209f..4435f6ed79e 100644
--- a/llvm/test/MC/ARM/big-endian-thumb2-fixup.s
+++ b/llvm/test/MC/ARM/big-endian-thumb2-fixup.s
@@ -47,3 +47,9 @@ ldst_precel_12_label:
nop
adr_pcrel_12_label:
+@ARM::fixup_t2_so_imm
+.section s_t2_so_imm,"ax",%progbits
+// CHECK-LABEL: Contents of section s_t2_so_imm
+// CHECK: 0000 f1033337
+ add r3, r3,val
+.equ val,0x37373737
diff --git a/llvm/test/MC/ARM/t2-modified-immediate-fixup-error1.s b/llvm/test/MC/ARM/t2-modified-immediate-fixup-error1.s
new file mode 100644
index 00000000000..f5113a64920
--- /dev/null
+++ b/llvm/test/MC/ARM/t2-modified-immediate-fixup-error1.s
@@ -0,0 +1,13 @@
+@ PR28647
+@ RUN: not llvm-mc -triple=thumbv7a-linux-gnueabi -filetype=obj < %s 2>&1 | FileCheck %s
+ .text
+ .syntax unified
+ .balign 2
+
+@ Error with unencodeable immediate
+ add r1, r2, sym0
+@ CHECK: error: out of range immediate fixup value
+ .equ sym0, 0x01abcdef
+.L2:
+ mov r0, .L2
+@ CHECK: error: unsupported relocation on symbol
diff --git a/llvm/test/MC/ARM/t2-modified-immediate-fixup-error2.s b/llvm/test/MC/ARM/t2-modified-immediate-fixup-error2.s
new file mode 100644
index 00000000000..a5672b5eb1f
--- /dev/null
+++ b/llvm/test/MC/ARM/t2-modified-immediate-fixup-error2.s
@@ -0,0 +1,12 @@
+@ PR28647
+@ RUN: not llvm-mc -triple=thumbv7a-linux-gnueabi -filetype=obj < %s 2>&1 | FileCheck %s
+ .text
+ .syntax unified
+ .balign 2
+
+@ mov with :upper16: or :lower16: should not match mov with modified immediate
+ mov r0, :upper16: sym0
+@ CHECK: error: instruction requires: arm-mode
+ mov r0, :lower16: sym0
+@ CHECK: error: instruction requires: arm-mode
+ .equ sym0, 0x01abcdef
diff --git a/llvm/test/MC/ARM/t2-modified-immediate-fixup.s b/llvm/test/MC/ARM/t2-modified-immediate-fixup.s
new file mode 100644
index 00000000000..ad0fae2e666
--- /dev/null
+++ b/llvm/test/MC/ARM/t2-modified-immediate-fixup.s
@@ -0,0 +1,45 @@
+@ PR28647
+@ RUN: llvm-mc < %s -triple=thumbv7a-linux-gnueabi -filetype=obj -o - \
+@ RUN: | llvm-objdump --disassemble -triple=thumbv7a-linux-gnueabi - | FileCheck %s
+ .text
+ .syntax unified
+ .balign 2
+@ Thumb2 modified immediate instructions
+ add r1,r1, sym0
+ sub r1,r2, sym1
+ cmp r2, sym2
+ and r4,r4, sym3
+ orr r8,r9, sym4
+ teq r1, sym5
+ tst r1, sym6
+ sbc r1,r1, sym7
+ adc r1,r0, sym8
+@CHECK: add.w r1, r1, #255
+@CHECK: sub.w r1, r2, #16711935
+@CHECK: cmp.w r2, #4278255360
+@CHECK: and r4, r4, #303174162
+@CHECK: orr r8, r9, #2852126720
+@CHECK: teq.w r1, #1426063360
+@CHECK: tst.w r1, #713031680
+@CHECK: sbc r1, r1, #2785280
+@CHECK: adc r1, r0, #340
+
+.L1:
+ sub r3, r3, #.L2 - .L1
+.L2:
+@CHECK: sub.w r3, r3, #4
+
+@ mov without :upper16: or :lower16: should match mov with modified immediate
+ mov r1, sym3
+@CHECK: mov.w r1, #303174162
+
+@ Modified immediate constants
+ .equ sym0, 0x000000ff
+ .equ sym1, 0x00ff00ff
+ .equ sym2, 0xff00ff00
+ .equ sym3, 0x12121212
+ .equ sym4, 0xaa000000
+ .equ sym5, 0x55000000
+ .equ sym6, 0x2a800000
+ .equ sym7, 0x002a8000
+ .equ sym8, 0x00000154
diff --git a/llvm/test/MC/ARM/thumb2-diagnostics.s b/llvm/test/MC/ARM/thumb2-diagnostics.s
index 76b4cf12626..ca917a0502d 100644
--- a/llvm/test/MC/ARM/thumb2-diagnostics.s
+++ b/llvm/test/MC/ARM/thumb2-diagnostics.s
@@ -76,10 +76,8 @@
@ CHECK-ERRORS: error: branch target out of range
foo2:
- mov r0, foo2
movw r0, foo2
movt r0, foo2
-@ CHECK-ERRORS: error: instruction requires: arm-mode
@ CHECK-ERRORS: error: immediate expression for mov requires :lower16: or :upper16
@ CHECK-ERRORS: ^
@ CHECK-ERRORS: error: immediate expression for mov requires :lower16: or :upper16
OpenPOWER on IntegriCloud