Skip to content

Commit ddbe812

Browse files
committed
[ARM][llvm-objdump] Annotate PC-relative memory operands
This implements `MCInstrAnalysis::evaluateMemoryOperandAddress()` for Arm so that the disassembler can print the target address of memory operands that use PC+immediate addressing. Differential Revision: https://reviews.llvm.org/D105979
1 parent 00809c8 commit ddbe812

File tree

8 files changed

+390
-14
lines changed

8 files changed

+390
-14
lines changed

llvm/lib/Target/ARM/ARMInstrFormats.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,8 +1385,8 @@ class ThumbXI<dag oops, dag iops, AddrMode am, int sz,
13851385
}
13861386

13871387
class T2I<dag oops, dag iops, InstrItinClass itin,
1388-
string opc, string asm, list<dag> pattern>
1389-
: Thumb2I<oops, iops, AddrModeNone, 4, itin, opc, asm, "", pattern>;
1388+
string opc, string asm, list<dag> pattern, AddrMode am = AddrModeNone>
1389+
: Thumb2I<oops, iops, am, 4, itin, opc, asm, "", pattern>;
13901390
class T2Ii12<dag oops, dag iops, InstrItinClass itin,
13911391
string opc, string asm, list<dag> pattern>
13921392
: Thumb2I<oops, iops, AddrModeT2_i12, 4, itin, opc, asm, "",pattern>;

llvm/lib/Target/ARM/ARMInstrInfo.td

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5391,14 +5391,16 @@ def CDP2 : ABXI<0b1110, (outs), (ins p_imm:$cop, imm0_15:$opc1,
53915391
}
53925392

53935393
class ACI<dag oops, dag iops, string opc, string asm,
5394-
list<dag> pattern, IndexMode im = IndexModeNone>
5395-
: I<oops, iops, AddrModeNone, 4, im, BrFrm, NoItinerary,
5394+
list<dag> pattern, IndexMode im = IndexModeNone,
5395+
AddrMode am = AddrModeNone>
5396+
: I<oops, iops, am, 4, im, BrFrm, NoItinerary,
53965397
opc, asm, "", pattern> {
53975398
let Inst{27-25} = 0b110;
53985399
}
53995400
class ACInoP<dag oops, dag iops, string opc, string asm,
5400-
list<dag> pattern, IndexMode im = IndexModeNone>
5401-
: InoP<oops, iops, AddrModeNone, 4, im, BrFrm, NoItinerary,
5401+
list<dag> pattern, IndexMode im = IndexModeNone,
5402+
AddrMode am = AddrModeNone>
5403+
: InoP<oops, iops, am, 4, im, BrFrm, NoItinerary,
54025404
opc, asm, "", pattern> {
54035405
let Inst{31-28} = 0b1111;
54045406
let Inst{27-25} = 0b110;
@@ -5407,7 +5409,8 @@ class ACInoP<dag oops, dag iops, string opc, string asm,
54075409
let DecoderNamespace = "CoProc" in {
54085410
multiclass LdStCop<bit load, bit Dbit, string asm, list<dag> pattern> {
54095411
def _OFFSET : ACI<(outs), (ins p_imm:$cop, c_imm:$CRd, addrmode5:$addr),
5410-
asm, "\t$cop, $CRd, $addr", pattern> {
5412+
asm, "\t$cop, $CRd, $addr", pattern, IndexModeNone,
5413+
AddrMode5> {
54115414
bits<13> addr;
54125415
bits<4> cop;
54135416
bits<4> CRd;
@@ -5478,7 +5481,8 @@ multiclass LdStCop<bit load, bit Dbit, string asm, list<dag> pattern> {
54785481
}
54795482
multiclass LdSt2Cop<bit load, bit Dbit, string asm, list<dag> pattern> {
54805483
def _OFFSET : ACInoP<(outs), (ins p_imm:$cop, c_imm:$CRd, addrmode5:$addr),
5481-
asm, "\t$cop, $CRd, $addr", pattern> {
5484+
asm, "\t$cop, $CRd, $addr", pattern, IndexModeNone,
5485+
AddrMode5> {
54825486
bits<13> addr;
54835487
bits<4> cop;
54845488
bits<4> CRd;

llvm/lib/Target/ARM/ARMInstrThumb.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ def thumb_cb_target : Operand<OtherVT> {
168168
let EncoderMethod = "getThumbCBTargetOpValue";
169169
let DecoderMethod = "DecodeThumbCmpBROperand";
170170
}
171+
} // OperandType = "OPERAND_PCREL"
171172

172173
// t_addrmode_pc := <label> => pc + imm8 * 4
173174
//
@@ -177,7 +178,6 @@ def t_addrmode_pc : MemOperand {
177178
let PrintMethod = "printThumbLdrLabelOperand";
178179
let ParserMatchClass = ThumbMemPC;
179180
}
180-
}
181181

182182
// t_addrmode_rr := reg + reg
183183
//

llvm/lib/Target/ARM/ARMInstrThumb2.td

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ def t2addrmode_imm12 : MemOperand,
200200
}
201201

202202
// t2ldrlabel := imm12
203-
def t2ldrlabel : Operand<i32> {
203+
def t2ldrlabel : MemOperand {
204204
let EncoderMethod = "getAddrModeImm12OpValue";
205205
let PrintMethod = "printThumbLdrLabelOperand";
206206
}
@@ -1927,7 +1927,7 @@ def : InstAlias<"pli${p}.w\t$addr",
19271927

19281928
// pci variant is very similar to i12, but supports negative offsets
19291929
// from the PC. Only PLD and PLI have pci variants (not PLDW)
1930-
class T2Iplpci<bits<1> inst, string opc> : T2Iso<(outs), (ins t2ldrlabel:$addr),
1930+
class T2Iplpci<bits<1> inst, string opc> : T2Ipc<(outs), (ins t2ldrlabel:$addr),
19311931
IIC_Preload, opc, "\t$addr",
19321932
[(ARMPreload (ARMWrapper tconstpool:$addr),
19331933
(i32 0), (i32 inst))]>, Sched<[WritePreLd]> {
@@ -4274,16 +4274,17 @@ def t2ABS : PseudoInst<(outs rGPR:$dst), (ins rGPR:$src),
42744274
//===----------------------------------------------------------------------===//
42754275
// Coprocessor load/store -- for disassembly only
42764276
//
4277-
class T2CI<bits<4> op31_28, dag oops, dag iops, string opc, string asm, list<dag> pattern>
4278-
: T2I<oops, iops, NoItinerary, opc, asm, pattern> {
4277+
class T2CI<bits<4> op31_28, dag oops, dag iops, string opc, string asm,
4278+
list<dag> pattern, AddrMode am = AddrModeNone>
4279+
: T2I<oops, iops, NoItinerary, opc, asm, pattern, am> {
42794280
let Inst{31-28} = op31_28;
42804281
let Inst{27-25} = 0b110;
42814282
}
42824283

42834284
multiclass t2LdStCop<bits<4> op31_28, bit load, bit Dbit, string asm, list<dag> pattern> {
42844285
def _OFFSET : T2CI<op31_28,
42854286
(outs), (ins p_imm:$cop, c_imm:$CRd, addrmode5:$addr),
4286-
asm, "\t$cop, $CRd, $addr", pattern> {
4287+
asm, "\t$cop, $CRd, $addr", pattern, AddrMode5> {
42874288
bits<13> addr;
42884289
bits<4> cop;
42894290
bits<4> CRd;

llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,8 +441,173 @@ class ARMMCInstrAnalysis : public MCInstrAnalysis {
441441
}
442442
return false;
443443
}
444+
445+
Optional<uint64_t> evaluateMemoryOperandAddress(const MCInst &Inst,
446+
uint64_t Addr,
447+
uint64_t Size) const override;
444448
};
445449

450+
} // namespace
451+
452+
static Optional<uint64_t>
453+
// NOLINTNEXTLINE(readability-identifier-naming)
454+
evaluateMemOpAddrForAddrMode_i12(const MCInst &Inst, const MCInstrDesc &Desc,
455+
unsigned MemOpIndex, uint64_t Addr) {
456+
if (MemOpIndex + 1 >= Desc.getNumOperands())
457+
return None;
458+
459+
const MCOperand &MO1 = Inst.getOperand(MemOpIndex);
460+
const MCOperand &MO2 = Inst.getOperand(MemOpIndex + 1);
461+
if (!MO1.isReg() || MO1.getReg() != ARM::PC || !MO2.isImm())
462+
return None;
463+
464+
int32_t OffImm = (int32_t)MO2.getImm();
465+
// Special value for #-0. All others are normal.
466+
if (OffImm == INT32_MIN)
467+
OffImm = 0;
468+
return Addr + OffImm;
469+
}
470+
471+
static Optional<uint64_t> evaluateMemOpAddrForAddrMode3(const MCInst &Inst,
472+
const MCInstrDesc &Desc,
473+
unsigned MemOpIndex,
474+
uint64_t Addr) {
475+
if (MemOpIndex + 2 >= Desc.getNumOperands())
476+
return None;
477+
478+
const MCOperand &MO1 = Inst.getOperand(MemOpIndex);
479+
const MCOperand &MO2 = Inst.getOperand(MemOpIndex + 1);
480+
const MCOperand &MO3 = Inst.getOperand(MemOpIndex + 2);
481+
if (!MO1.isReg() || MO1.getReg() != ARM::PC || MO2.getReg() || !MO3.isImm())
482+
return None;
483+
484+
unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm());
485+
ARM_AM::AddrOpc Op = ARM_AM::getAM3Op(MO3.getImm());
486+
487+
if (Op == ARM_AM::sub)
488+
return Addr - ImmOffs;
489+
return Addr + ImmOffs;
490+
}
491+
492+
static Optional<uint64_t> evaluateMemOpAddrForAddrMode5(const MCInst &Inst,
493+
const MCInstrDesc &Desc,
494+
unsigned MemOpIndex,
495+
uint64_t Addr) {
496+
if (MemOpIndex + 1 >= Desc.getNumOperands())
497+
return None;
498+
499+
const MCOperand &MO1 = Inst.getOperand(MemOpIndex);
500+
const MCOperand &MO2 = Inst.getOperand(MemOpIndex + 1);
501+
if (!MO1.isReg() || MO1.getReg() != ARM::PC || !MO2.isImm())
502+
return None;
503+
504+
unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm());
505+
ARM_AM::AddrOpc Op = ARM_AM::getAM5Op(MO2.getImm());
506+
507+
if (Op == ARM_AM::sub)
508+
return Addr - ImmOffs * 4;
509+
return Addr + ImmOffs * 4;
510+
}
511+
512+
static Optional<uint64_t>
513+
// NOLINTNEXTLINE(readability-identifier-naming)
514+
evaluateMemOpAddrForAddrModeT2_i8s4(const MCInst &Inst, const MCInstrDesc &Desc,
515+
unsigned MemOpIndex, uint64_t Addr) {
516+
if (MemOpIndex + 1 >= Desc.getNumOperands())
517+
return None;
518+
519+
const MCOperand &MO1 = Inst.getOperand(MemOpIndex);
520+
const MCOperand &MO2 = Inst.getOperand(MemOpIndex + 1);
521+
if (!MO1.isReg() || MO1.getReg() != ARM::PC || !MO2.isImm())
522+
return None;
523+
524+
int32_t OffImm = (int32_t)MO2.getImm();
525+
assert(((OffImm & 0x3) == 0) && "Not a valid immediate!");
526+
527+
// Special value for #-0. All others are normal.
528+
if (OffImm == INT32_MIN)
529+
OffImm = 0;
530+
return Addr + OffImm;
531+
}
532+
533+
static Optional<uint64_t>
534+
// NOLINTNEXTLINE(readability-identifier-naming)
535+
evaluateMemOpAddrForAddrModeT2_pc(const MCInst &Inst, const MCInstrDesc &Desc,
536+
unsigned MemOpIndex, uint64_t Addr) {
537+
const MCOperand &MO1 = Inst.getOperand(MemOpIndex);
538+
if (!MO1.isImm())
539+
return None;
540+
541+
int32_t OffImm = (int32_t)MO1.getImm();
542+
543+
// Special value for #-0. All others are normal.
544+
if (OffImm == INT32_MIN)
545+
OffImm = 0;
546+
return Addr + OffImm;
547+
}
548+
549+
static Optional<uint64_t>
550+
// NOLINTNEXTLINE(readability-identifier-naming)
551+
evaluateMemOpAddrForAddrModeT1_s(const MCInst &Inst, const MCInstrDesc &Desc,
552+
unsigned MemOpIndex, uint64_t Addr) {
553+
return evaluateMemOpAddrForAddrModeT2_pc(Inst, Desc, MemOpIndex, Addr);
554+
}
555+
556+
Optional<uint64_t> ARMMCInstrAnalysis::evaluateMemoryOperandAddress(
557+
const MCInst &Inst, uint64_t Addr, uint64_t Size) const {
558+
const MCInstrDesc &Desc = Info->get(Inst.getOpcode());
559+
560+
// Only load instructions can have PC-relative memory addressing.
561+
if (!Desc.mayLoad())
562+
return None;
563+
564+
// PC-relative addressing does not update the base register.
565+
uint64_t TSFlags = Desc.TSFlags;
566+
unsigned IndexMode =
567+
(TSFlags & ARMII::IndexModeMask) >> ARMII::IndexModeShift;
568+
if (IndexMode != ARMII::IndexModeNone)
569+
return None;
570+
571+
// Find the memory addressing operand in the instruction.
572+
unsigned OpIndex = Desc.NumDefs;
573+
while (OpIndex < Desc.getNumOperands() &&
574+
Desc.OpInfo[OpIndex].OperandType != MCOI::OPERAND_MEMORY)
575+
++OpIndex;
576+
if (OpIndex == Desc.getNumOperands())
577+
return None;
578+
579+
// Base address for PC-relative addressing is always 32-bit aligned.
580+
Addr &= ~0x3;
581+
582+
// For ARM instructions the PC offset is 8 bytes, for Thumb instructions it
583+
// is 4 bytes.
584+
switch (Desc.TSFlags & ARMII::FormMask) {
585+
default:
586+
Addr += 8;
587+
break;
588+
case ARMII::ThumbFrm:
589+
Addr += 4;
590+
break;
591+
}
592+
593+
// Eveluate the address depending on the addressing mode
594+
unsigned AddrMode = (TSFlags & ARMII::AddrModeMask);
595+
switch (AddrMode) {
596+
default:
597+
return None;
598+
case ARMII::AddrMode_i12:
599+
return evaluateMemOpAddrForAddrMode_i12(Inst, Desc, OpIndex, Addr);
600+
case ARMII::AddrMode3:
601+
return evaluateMemOpAddrForAddrMode3(Inst, Desc, OpIndex, Addr);
602+
case ARMII::AddrMode5:
603+
return evaluateMemOpAddrForAddrMode5(Inst, Desc, OpIndex, Addr);
604+
case ARMII::AddrModeT2_i8s4:
605+
return evaluateMemOpAddrForAddrModeT2_i8s4(Inst, Desc, OpIndex, Addr);
606+
case ARMII::AddrModeT2_pc:
607+
return evaluateMemOpAddrForAddrModeT2_pc(Inst, Desc, OpIndex, Addr);
608+
case ARMII::AddrModeT1_s:
609+
return evaluateMemOpAddrForAddrModeT1_s(Inst, Desc, OpIndex, Addr);
610+
}
446611
}
447612

448613
static MCInstrAnalysis *createARMMCInstrAnalysis(const MCInstrInfo *Info) {
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
@@ Check that PC-relative memory addressing is annotated
2+
3+
@ RUN: llvm-mc %s -triple=armv7 -filetype=obj | \
4+
@ RUN: llvm-objdump -d --no-show-raw-insn --triple=armv7 - | \
5+
@ RUN: FileCheck %s
6+
7+
.text
8+
foo:
9+
@ CHECK: 00000000 <foo>:
10+
.word 0x01020304
11+
12+
_start:
13+
@ CHECK: 00000004 <_start>:
14+
15+
@@ Check a special case immediate for AddrMode_i12
16+
ldr r1, [pc, #-0]
17+
@ CHECK-NEXT: 4: ldr r1, [pc, #-0] @ 0xc <_start+0x8>
18+
19+
@@ Check AddrMode_i12 instructions, with positive and negative immediates
20+
ldr r0, foo
21+
ldrb r0, bar
22+
pli _start
23+
pld bar
24+
@ CHECK-NEXT: 8: ldr r0, [pc, #-16] @ 0x0 <foo>
25+
@ CHECK-NEXT: c: ldrb r0, [pc, #48] @ 0x44 <bar>
26+
@ CHECK-NEXT: 10: pli [pc, #-20] @ 0x4 <_start>
27+
@ CHECK-NEXT: 14: pld [pc, #40] @ 0x44 <bar>
28+
29+
@@ Check that AddrMode_i12 instructions that do not use PC-relative addressing
30+
@@ are not annotated
31+
ldr r0, [r1, #8]
32+
@ CHECK-NEXT: 18: ldr r0, [r1, #8]{{$}}
33+
34+
@@ Check AddrMode3 instructions, with positive and negative immediates
35+
ldrd r0, r1, foo
36+
ldrh r0, bar
37+
@ CHECK-NEXT: 1c: ldrd r0, r1, [pc, #-36] @ 0x0 <foo>
38+
@ CHECK-NEXT: 20: ldrh r0, [pc, #28] @ 0x44 <bar>
39+
40+
@@ Check that AddrMode3 instruction that do not use PC+imm addressing are not
41+
@@ annotated
42+
ldrh r0, [r1, #8]
43+
ldrh r0, [pc, r2]
44+
@ CHECK-NEXT: 24: ldrh r0, [r1, #8]{{$}}
45+
@ CHECK-NEXT: 28: ldrh r0, [pc, r2]{{$}}
46+
47+
@@ Check AddrMode5 instructions, with positive and negative immediates
48+
ldc p14, c5, foo
49+
ldcl p6, c4, bar
50+
ldc2 p5, c2, foo
51+
ldc2l p3, c1, bar
52+
@ CHECK-NEXT: 2c: ldc p14, c5, [pc, #-52] @ 0x0 <foo>
53+
@ CHECK-NEXT: 30: ldcl p6, c4, [pc, #12] @ 0x44 <bar>
54+
@ CHECK-NEXT: 34: ldc2 p5, c2, [pc, #-60] @ 0x0 <foo>
55+
@ CHECK-NEXT: 38: ldc2l p3, c1, [pc, #4] @ 0x44 <bar>
56+
57+
@@ Check that AddrMode5 instruction that do not use PC+imm addressing are not
58+
@@ annotated
59+
ldc p14, c5, [r1, #8]
60+
ldc p14, c5, [pc], {16}
61+
@ CHECK-NEXT: 3c: ldc p14, c5, [r1, #8]{{$}}
62+
@ CHECK-NEXT: 40: ldc p14, c5, [pc], {16}{{$}}
63+
64+
bar:
65+
@ CHECK: 00000044 <bar>:
66+
.word 0x01020304
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
@@ Check that PC-relative memory addressing is annotated
2+
3+
@ RUN: llvm-mc %s -triple=thumbv6m -filetype=obj | \
4+
@ RUN: llvm-objdump -d --no-show-raw-insn --triple=thumbv6m - | \
5+
@ RUN: FileCheck %s
6+
7+
.text
8+
_start:
9+
@ CHECK: 00000000 <_start>:
10+
11+
@@ Check AddrModeT1_s instruction, with 4-byte and 2-byte alignment
12+
ldr r0, bar
13+
ldr r1, bar
14+
ldr r2, bar
15+
ldr r3, bar
16+
@ CHECK-NEXT: 0: ldr r0, [pc, #4] @ 0x8 <bar>
17+
@ CHECK-NEXT: 2: ldr r1, [pc, #4] @ 0x8 <bar>
18+
@ CHECK-NEXT: 4: ldr r2, [pc, #0] @ 0x8 <bar>
19+
@ CHECK-NEXT: 6: ldr r3, [pc, #0] @ 0x8 <bar>
20+
21+
.balign 4
22+
bar:
23+
@ CHECK: 00000008 <bar>:
24+
.word 0x01020304

0 commit comments

Comments
 (0)