diff options
author | Peter Smith <peter.smith@linaro.org> | 2017-06-05 09:37:12 +0000 |
---|---|---|
committer | Peter Smith <peter.smith@linaro.org> | 2017-06-05 09:37:12 +0000 |
commit | adde667007b5793fec2556fb75133c5cb92f5421 (patch) | |
tree | 96cfab0252375d4f5babea8ff952255b4d83b173 | |
parent | 78819e0fd470e1f736891549491ef14f24c68fed (diff) | |
download | bcm5719-llvm-adde667007b5793fec2556fb75133c5cb92f5421.tar.gz bcm5719-llvm-adde667007b5793fec2556fb75133c5cb92f5421.zip |
[ARM] Support fixup for Thumb2 modified immediate
This change adds a new fixup fixup_t2_so_imm for the t2_so_imm_asmoperand
"T2SOImm". The fixup permits code such as:
.L1:
sub r3, r3, #.L2 - .L1
.L2:
to assemble in Thumb2 as well as in ARM state.
The operand predicate isT2SOImm() explicitly doesn't match expressions
containing :upper16: and :lower16: as expressions with these operators
must match the movt and movw instructions.
The test mov r0, foo2 in thumb2-diagnostics is moved to a new file as the
fixup delays the error message till after the assembler has quit due to
the other errors.
As the mov instruction shares the t2_so_imm_asmoperand mov instructions
with a non constant expression now match t2MOVi rather than t2MOVi16 so the
error message is slightly different.
Fixes PR28647
Differential Revision: https://reviews.llvm.org/D33492
llvm-svn: 304702
-rw-r--r-- | llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 15 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp | 20 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h | 3 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp | 12 | ||||
-rw-r--r-- | llvm/test/MC/ARM/big-endian-thumb2-fixup.s | 6 | ||||
-rw-r--r-- | llvm/test/MC/ARM/t2-modified-immediate-fixup-error1.s | 13 | ||||
-rw-r--r-- | llvm/test/MC/ARM/t2-modified-immediate-fixup-error2.s | 12 | ||||
-rw-r--r-- | llvm/test/MC/ARM/t2-modified-immediate-fixup.s | 45 | ||||
-rw-r--r-- | llvm/test/MC/ARM/thumb2-diagnostics.s | 2 |
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 |