Skip to content

Commit adde667

Browse files
committedJun 5, 2017
[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
1 parent 78819e0 commit adde667

9 files changed

+123
-5
lines changed
 

‎llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,15 @@ class ARMOperand : public MCParsedAsmOperand {
10261026
ARM_AM::getSOImmVal(-Value) != -1);
10271027
}
10281028
bool isT2SOImm() const {
1029+
// If we have an immediate that's not a constant, treat it as an expression
1030+
// needing a fixup.
1031+
if (isImm() && !isa<MCConstantExpr>(getImm())) {
1032+
// We want to avoid matching :upper16: and :lower16: as we want these
1033+
// expressions to match in isImm0_65535Expr()
1034+
const ARMMCExpr *ARM16Expr = dyn_cast<ARMMCExpr>(getImm());
1035+
return (!ARM16Expr || (ARM16Expr->getKind() != ARMMCExpr::VK_ARM_HI16 &&
1036+
ARM16Expr->getKind() != ARMMCExpr::VK_ARM_LO16));
1037+
}
10291038
if (!isImm()) return false;
10301039
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
10311040
if (!CE) return false;
@@ -8404,7 +8413,8 @@ bool ARMAsmParser::processInstruction(MCInst &Inst,
84048413
// wide encoding wasn't explicit.
84058414
if (Inst.getOperand(0).getReg() != Inst.getOperand(1).getReg() ||
84068415
!isARMLowRegister(Inst.getOperand(0).getReg()) ||
8407-
(unsigned)Inst.getOperand(2).getImm() > 255 ||
8416+
(Inst.getOperand(2).isImm() &&
8417+
(unsigned)Inst.getOperand(2).getImm() > 255) ||
84088418
((!inITBlock() && Inst.getOperand(5).getReg() != ARM::CPSR) ||
84098419
(inITBlock() && Inst.getOperand(5).getReg() != 0)) ||
84108420
(static_cast<ARMOperand &>(*Operands[3]).isToken() &&
@@ -8556,7 +8566,8 @@ bool ARMAsmParser::processInstruction(MCInst &Inst,
85568566
// If we can use the 16-bit encoding and the user didn't explicitly
85578567
// request the 32-bit variant, transform it here.
85588568
if (isARMLowRegister(Inst.getOperand(0).getReg()) &&
8559-
(unsigned)Inst.getOperand(1).getImm() <= 255 &&
8569+
(Inst.getOperand(1).isImm() &&
8570+
(unsigned)Inst.getOperand(1).getImm() <= 255) &&
85608571
((!inITBlock() && Inst.getOperand(2).getImm() == ARMCC::AL &&
85618572
Inst.getOperand(4).getReg() == ARM::CPSR) ||
85628573
(inITBlock() && Inst.getOperand(4).getReg() == 0)) &&

‎llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ const MCFixupKindInfo &ARMAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
9898
{"fixup_t2_movt_hi16", 0, 20, 0},
9999
{"fixup_t2_movw_lo16", 0, 20, 0},
100100
{"fixup_arm_mod_imm", 0, 12, 0},
101+
{"fixup_t2_so_imm", 0, 26, 0},
101102
};
102103
const static MCFixupKindInfo InfosBE[ARM::NumTargetFixupKinds] = {
103104
// 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 {
148149
{"fixup_t2_movt_hi16", 12, 20, 0},
149150
{"fixup_t2_movw_lo16", 12, 20, 0},
150151
{"fixup_arm_mod_imm", 20, 12, 0},
152+
{"fixup_t2_so_imm", 26, 6, 0},
151153
};
152154

153155
if (Kind < FirstTargetFixupKind)
@@ -693,6 +695,22 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
693695
return 0;
694696
}
695697
return Value;
698+
case ARM::fixup_t2_so_imm:
699+
Value = ARM_AM::getT2SOImmVal(Value);
700+
if ((int64_t)Value < 0) {
701+
Ctx.reportError(Fixup.getLoc(), "out of range immediate fixup value");
702+
return 0;
703+
}
704+
// Value will contain a 12-bit value broken up into a 4-bit shift in bits
705+
// 11:8 and the 8-bit immediate in 0:7. The instruction has the immediate
706+
// in 0:7. The 4-bit shift is split up into i:imm3 where i is placed at bit
707+
// 10 of the upper half-word and imm3 is placed at 14:12 of the lower
708+
// half-word.
709+
uint64_t EncValue = 0;
710+
EncValue |= (Value & 0x800) << 15;
711+
EncValue |= (Value & 0x700) << 4;
712+
EncValue |= (Value & 0xff);
713+
return swapHalfWords(EncValue, IsLittleEndian);
696714
}
697715
}
698716

@@ -792,6 +810,7 @@ static unsigned getFixupKindNumBytes(unsigned Kind) {
792810
case ARM::fixup_arm_movw_lo16:
793811
case ARM::fixup_t2_movt_hi16:
794812
case ARM::fixup_t2_movw_lo16:
813+
case ARM::fixup_t2_so_imm:
795814
return 4;
796815

797816
case FK_SecRel_2:
@@ -844,6 +863,7 @@ static unsigned getFixupKindContainerSizeBytes(unsigned Kind) {
844863
case ARM::fixup_t2_movt_hi16:
845864
case ARM::fixup_t2_movw_lo16:
846865
case ARM::fixup_arm_mod_imm:
866+
case ARM::fixup_t2_so_imm:
847867
// Instruction size is 4 bytes.
848868
return 4;
849869
}

‎llvm/lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ enum Fixups {
110110
// fixup_arm_mod_imm - Fixup for mod_imm
111111
fixup_arm_mod_imm,
112112

113+
// fixup_t2_so_imm - Fixup for Thumb2 8-bit rotated operand
114+
fixup_t2_so_imm,
115+
113116
// Marker
114117
LastTargetFixupKind,
115118
NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind

‎llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,17 @@ class ARMMCCodeEmitter : public MCCodeEmitter {
339339
unsigned getT2SOImmOpValue(const MCInst &MI, unsigned Op,
340340
SmallVectorImpl<MCFixup> &Fixups,
341341
const MCSubtargetInfo &STI) const {
342-
unsigned SoImm = MI.getOperand(Op).getImm();
342+
const MCOperand &MO = MI.getOperand(Op);
343+
344+
// Support for fixups (MCFixup)
345+
if (MO.isExpr()) {
346+
const MCExpr *Expr = MO.getExpr();
347+
// Fixups resolve to plain values that need to be encoded.
348+
MCFixupKind Kind = MCFixupKind(ARM::fixup_t2_so_imm);
349+
Fixups.push_back(MCFixup::create(0, Expr, Kind, MI.getLoc()));
350+
return 0;
351+
}
352+
unsigned SoImm = MO.getImm();
343353
unsigned Encoded = ARM_AM::getT2SOImmVal(SoImm);
344354
assert(Encoded != ~0U && "Not a Thumb2 so_imm value?");
345355
return Encoded;

‎llvm/test/MC/ARM/big-endian-thumb2-fixup.s

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,9 @@ ldst_precel_12_label:
4747
nop
4848
adr_pcrel_12_label:
4949

50+
@ARM::fixup_t2_so_imm
51+
.section s_t2_so_imm,"ax",%progbits
52+
// CHECK-LABEL: Contents of section s_t2_so_imm
53+
// CHECK: 0000 f1033337
54+
add r3, r3,val
55+
.equ val,0x37373737
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
@ PR28647
2+
@ RUN: not llvm-mc -triple=thumbv7a-linux-gnueabi -filetype=obj < %s 2>&1 | FileCheck %s
3+
.text
4+
.syntax unified
5+
.balign 2
6+
7+
@ Error with unencodeable immediate
8+
add r1, r2, sym0
9+
@ CHECK: error: out of range immediate fixup value
10+
.equ sym0, 0x01abcdef
11+
.L2:
12+
mov r0, .L2
13+
@ CHECK: error: unsupported relocation on symbol
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
@ PR28647
2+
@ RUN: not llvm-mc -triple=thumbv7a-linux-gnueabi -filetype=obj < %s 2>&1 | FileCheck %s
3+
.text
4+
.syntax unified
5+
.balign 2
6+
7+
@ mov with :upper16: or :lower16: should not match mov with modified immediate
8+
mov r0, :upper16: sym0
9+
@ CHECK: error: instruction requires: arm-mode
10+
mov r0, :lower16: sym0
11+
@ CHECK: error: instruction requires: arm-mode
12+
.equ sym0, 0x01abcdef
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
@ PR28647
2+
@ RUN: llvm-mc < %s -triple=thumbv7a-linux-gnueabi -filetype=obj -o - \
3+
@ RUN: | llvm-objdump --disassemble -triple=thumbv7a-linux-gnueabi - | FileCheck %s
4+
.text
5+
.syntax unified
6+
.balign 2
7+
@ Thumb2 modified immediate instructions
8+
add r1,r1, sym0
9+
sub r1,r2, sym1
10+
cmp r2, sym2
11+
and r4,r4, sym3
12+
orr r8,r9, sym4
13+
teq r1, sym5
14+
tst r1, sym6
15+
sbc r1,r1, sym7
16+
adc r1,r0, sym8
17+
@CHECK: add.w r1, r1, #255
18+
@CHECK: sub.w r1, r2, #16711935
19+
@CHECK: cmp.w r2, #4278255360
20+
@CHECK: and r4, r4, #303174162
21+
@CHECK: orr r8, r9, #2852126720
22+
@CHECK: teq.w r1, #1426063360
23+
@CHECK: tst.w r1, #713031680
24+
@CHECK: sbc r1, r1, #2785280
25+
@CHECK: adc r1, r0, #340
26+
27+
.L1:
28+
sub r3, r3, #.L2 - .L1
29+
.L2:
30+
@CHECK: sub.w r3, r3, #4
31+
32+
@ mov without :upper16: or :lower16: should match mov with modified immediate
33+
mov r1, sym3
34+
@CHECK: mov.w r1, #303174162
35+
36+
@ Modified immediate constants
37+
.equ sym0, 0x000000ff
38+
.equ sym1, 0x00ff00ff
39+
.equ sym2, 0xff00ff00
40+
.equ sym3, 0x12121212
41+
.equ sym4, 0xaa000000
42+
.equ sym5, 0x55000000
43+
.equ sym6, 0x2a800000
44+
.equ sym7, 0x002a8000
45+
.equ sym8, 0x00000154

‎llvm/test/MC/ARM/thumb2-diagnostics.s

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,8 @@
7676
@ CHECK-ERRORS: error: branch target out of range
7777

7878
foo2:
79-
mov r0, foo2
8079
movw r0, foo2
8180
movt r0, foo2
82-
@ CHECK-ERRORS: error: instruction requires: arm-mode
8381
@ CHECK-ERRORS: error: immediate expression for mov requires :lower16: or :upper16
8482
@ CHECK-ERRORS: ^
8583
@ CHECK-ERRORS: error: immediate expression for mov requires :lower16: or :upper16

0 commit comments

Comments
 (0)
Please sign in to comment.