Index: lib/Target/ARM/AsmParser/ARMAsmParser.cpp =================================================================== --- lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -1026,6 +1026,15 @@ 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(getImm())) { + // We want to avoid matching :upper16: and :lower16: as we want these + // expressions to match in isImm0_65535Expr() + const ARMMCExpr *ARM16Expr = dyn_cast(getImm()); + return (!ARM16Expr || (ARM16Expr->getKind() != ARMMCExpr::VK_ARM_HI16 && + ARM16Expr->getKind() != ARMMCExpr::VK_ARM_LO16)); + } if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; @@ -8404,7 +8413,8 @@ // 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(*Operands[3]).isToken() && @@ -8556,7 +8566,8 @@ // 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)) && Index: lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp +++ lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp @@ -98,6 +98,7 @@ {"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 @@ {"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 @@ 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 @@ 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 @@ 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; } Index: lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h +++ lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h @@ -110,6 +110,9 @@ // 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 Index: lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp +++ lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp @@ -339,7 +339,17 @@ unsigned getT2SOImmOpValue(const MCInst &MI, unsigned Op, SmallVectorImpl &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; Index: test/MC/ARM/big-endian-thumb2-fixup.s =================================================================== --- test/MC/ARM/big-endian-thumb2-fixup.s +++ test/MC/ARM/big-endian-thumb2-fixup.s @@ -47,3 +47,9 @@ 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 Index: test/MC/ARM/t2-modified-immediate-fixup-error1.s =================================================================== --- /dev/null +++ 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 Index: test/MC/ARM/t2-modified-immediate-fixup-error2.s =================================================================== --- /dev/null +++ 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 Index: test/MC/ARM/t2-modified-immediate-fixup.s =================================================================== --- /dev/null +++ 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 Index: test/MC/ARM/thumb2-diagnostics.s =================================================================== --- test/MC/ARM/thumb2-diagnostics.s +++ 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