}
class T2I<dag oops, dag iops, InstrItinClass itin,
- string opc, string asm, list<dag> pattern>
- : Thumb2I<oops, iops, AddrModeNone, 4, itin, opc, asm, "", pattern>;
+ string opc, string asm, list<dag> pattern, AddrMode am = AddrModeNone>
+ : Thumb2I<oops, iops, am, 4, itin, opc, asm, "", pattern>;
class T2Ii12<dag oops, dag iops, InstrItinClass itin,
string opc, string asm, list<dag> pattern>
: Thumb2I<oops, iops, AddrModeT2_i12, 4, itin, opc, asm, "",pattern>;
}
class ACI<dag oops, dag iops, string opc, string asm,
- list<dag> pattern, IndexMode im = IndexModeNone>
- : I<oops, iops, AddrModeNone, 4, im, BrFrm, NoItinerary,
+ list<dag> pattern, IndexMode im = IndexModeNone,
+ AddrMode am = AddrModeNone>
+ : I<oops, iops, am, 4, im, BrFrm, NoItinerary,
opc, asm, "", pattern> {
let Inst{27-25} = 0b110;
}
class ACInoP<dag oops, dag iops, string opc, string asm,
- list<dag> pattern, IndexMode im = IndexModeNone>
- : InoP<oops, iops, AddrModeNone, 4, im, BrFrm, NoItinerary,
+ list<dag> pattern, IndexMode im = IndexModeNone,
+ AddrMode am = AddrModeNone>
+ : InoP<oops, iops, am, 4, im, BrFrm, NoItinerary,
opc, asm, "", pattern> {
let Inst{31-28} = 0b1111;
let Inst{27-25} = 0b110;
let DecoderNamespace = "CoProc" in {
multiclass LdStCop<bit load, bit Dbit, string asm, list<dag> pattern> {
def _OFFSET : ACI<(outs), (ins p_imm:$cop, c_imm:$CRd, addrmode5:$addr),
- asm, "\t$cop, $CRd, $addr", pattern> {
+ asm, "\t$cop, $CRd, $addr", pattern, IndexModeNone,
+ AddrMode5> {
bits<13> addr;
bits<4> cop;
bits<4> CRd;
}
multiclass LdSt2Cop<bit load, bit Dbit, string asm, list<dag> pattern> {
def _OFFSET : ACInoP<(outs), (ins p_imm:$cop, c_imm:$CRd, addrmode5:$addr),
- asm, "\t$cop, $CRd, $addr", pattern> {
+ asm, "\t$cop, $CRd, $addr", pattern, IndexModeNone,
+ AddrMode5> {
bits<13> addr;
bits<4> cop;
bits<4> CRd;
let EncoderMethod = "getThumbCBTargetOpValue";
let DecoderMethod = "DecodeThumbCmpBROperand";
}
+} // OperandType = "OPERAND_PCREL"
// t_addrmode_pc := <label> => pc + imm8 * 4
//
let PrintMethod = "printThumbLdrLabelOperand";
let ParserMatchClass = ThumbMemPC;
}
-}
// t_addrmode_rr := reg + reg
//
}
// t2ldrlabel := imm12
-def t2ldrlabel : Operand<i32> {
+def t2ldrlabel : MemOperand {
let EncoderMethod = "getAddrModeImm12OpValue";
let PrintMethod = "printThumbLdrLabelOperand";
}
// pci variant is very similar to i12, but supports negative offsets
// from the PC. Only PLD and PLI have pci variants (not PLDW)
-class T2Iplpci<bits<1> inst, string opc> : T2Iso<(outs), (ins t2ldrlabel:$addr),
+class T2Iplpci<bits<1> inst, string opc> : T2Ipc<(outs), (ins t2ldrlabel:$addr),
IIC_Preload, opc, "\t$addr",
[(ARMPreload (ARMWrapper tconstpool:$addr),
(i32 0), (i32 inst))]>, Sched<[WritePreLd]> {
//===----------------------------------------------------------------------===//
// Coprocessor load/store -- for disassembly only
//
-class T2CI<bits<4> op31_28, dag oops, dag iops, string opc, string asm, list<dag> pattern>
- : T2I<oops, iops, NoItinerary, opc, asm, pattern> {
+class T2CI<bits<4> op31_28, dag oops, dag iops, string opc, string asm,
+ list<dag> pattern, AddrMode am = AddrModeNone>
+ : T2I<oops, iops, NoItinerary, opc, asm, pattern, am> {
let Inst{31-28} = op31_28;
let Inst{27-25} = 0b110;
}
multiclass t2LdStCop<bits<4> op31_28, bit load, bit Dbit, string asm, list<dag> pattern> {
def _OFFSET : T2CI<op31_28,
(outs), (ins p_imm:$cop, c_imm:$CRd, addrmode5:$addr),
- asm, "\t$cop, $CRd, $addr", pattern> {
+ asm, "\t$cop, $CRd, $addr", pattern, AddrMode5> {
bits<13> addr;
bits<4> cop;
bits<4> CRd;
}
return false;
}
+
+ Optional<uint64_t> evaluateMemoryOperandAddress(const MCInst &Inst,
+ uint64_t Addr,
+ uint64_t Size) const override;
};
+} // namespace
+
+static Optional<uint64_t>
+// NOLINTNEXTLINE(readability-identifier-naming)
+evaluateMemOpAddrForAddrMode_i12(const MCInst &Inst, const MCInstrDesc &Desc,
+ unsigned MemOpIndex, uint64_t Addr) {
+ if (MemOpIndex + 1 >= Desc.getNumOperands())
+ return None;
+
+ const MCOperand &MO1 = Inst.getOperand(MemOpIndex);
+ const MCOperand &MO2 = Inst.getOperand(MemOpIndex + 1);
+ if (!MO1.isReg() || MO1.getReg() != ARM::PC || !MO2.isImm())
+ return None;
+
+ int32_t OffImm = (int32_t)MO2.getImm();
+ // Special value for #-0. All others are normal.
+ if (OffImm == INT32_MIN)
+ OffImm = 0;
+ return Addr + OffImm;
+}
+
+static Optional<uint64_t> evaluateMemOpAddrForAddrMode3(const MCInst &Inst,
+ const MCInstrDesc &Desc,
+ unsigned MemOpIndex,
+ uint64_t Addr) {
+ if (MemOpIndex + 2 >= Desc.getNumOperands())
+ return None;
+
+ const MCOperand &MO1 = Inst.getOperand(MemOpIndex);
+ const MCOperand &MO2 = Inst.getOperand(MemOpIndex + 1);
+ const MCOperand &MO3 = Inst.getOperand(MemOpIndex + 2);
+ if (!MO1.isReg() || MO1.getReg() != ARM::PC || MO2.getReg() || !MO3.isImm())
+ return None;
+
+ unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm());
+ ARM_AM::AddrOpc Op = ARM_AM::getAM3Op(MO3.getImm());
+
+ if (Op == ARM_AM::sub)
+ return Addr - ImmOffs;
+ return Addr + ImmOffs;
+}
+
+static Optional<uint64_t> evaluateMemOpAddrForAddrMode5(const MCInst &Inst,
+ const MCInstrDesc &Desc,
+ unsigned MemOpIndex,
+ uint64_t Addr) {
+ if (MemOpIndex + 1 >= Desc.getNumOperands())
+ return None;
+
+ const MCOperand &MO1 = Inst.getOperand(MemOpIndex);
+ const MCOperand &MO2 = Inst.getOperand(MemOpIndex + 1);
+ if (!MO1.isReg() || MO1.getReg() != ARM::PC || !MO2.isImm())
+ return None;
+
+ unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm());
+ ARM_AM::AddrOpc Op = ARM_AM::getAM5Op(MO2.getImm());
+
+ if (Op == ARM_AM::sub)
+ return Addr - ImmOffs * 4;
+ return Addr + ImmOffs * 4;
+}
+
+static Optional<uint64_t>
+// NOLINTNEXTLINE(readability-identifier-naming)
+evaluateMemOpAddrForAddrModeT2_i8s4(const MCInst &Inst, const MCInstrDesc &Desc,
+ unsigned MemOpIndex, uint64_t Addr) {
+ if (MemOpIndex + 1 >= Desc.getNumOperands())
+ return None;
+
+ const MCOperand &MO1 = Inst.getOperand(MemOpIndex);
+ const MCOperand &MO2 = Inst.getOperand(MemOpIndex + 1);
+ if (!MO1.isReg() || MO1.getReg() != ARM::PC || !MO2.isImm())
+ return None;
+
+ int32_t OffImm = (int32_t)MO2.getImm();
+ assert(((OffImm & 0x3) == 0) && "Not a valid immediate!");
+
+ // Special value for #-0. All others are normal.
+ if (OffImm == INT32_MIN)
+ OffImm = 0;
+ return Addr + OffImm;
+}
+
+static Optional<uint64_t>
+// NOLINTNEXTLINE(readability-identifier-naming)
+evaluateMemOpAddrForAddrModeT2_pc(const MCInst &Inst, const MCInstrDesc &Desc,
+ unsigned MemOpIndex, uint64_t Addr) {
+ const MCOperand &MO1 = Inst.getOperand(MemOpIndex);
+ if (!MO1.isImm())
+ return None;
+
+ int32_t OffImm = (int32_t)MO1.getImm();
+
+ // Special value for #-0. All others are normal.
+ if (OffImm == INT32_MIN)
+ OffImm = 0;
+ return Addr + OffImm;
+}
+
+static Optional<uint64_t>
+// NOLINTNEXTLINE(readability-identifier-naming)
+evaluateMemOpAddrForAddrModeT1_s(const MCInst &Inst, const MCInstrDesc &Desc,
+ unsigned MemOpIndex, uint64_t Addr) {
+ return evaluateMemOpAddrForAddrModeT2_pc(Inst, Desc, MemOpIndex, Addr);
+}
+
+Optional<uint64_t> ARMMCInstrAnalysis::evaluateMemoryOperandAddress(
+ const MCInst &Inst, uint64_t Addr, uint64_t Size) const {
+ const MCInstrDesc &Desc = Info->get(Inst.getOpcode());
+
+ // Only load instructions can have PC-relative memory addressing.
+ if (!Desc.mayLoad())
+ return None;
+
+ // PC-relative addressing does not update the base register.
+ uint64_t TSFlags = Desc.TSFlags;
+ unsigned IndexMode =
+ (TSFlags & ARMII::IndexModeMask) >> ARMII::IndexModeShift;
+ if (IndexMode != ARMII::IndexModeNone)
+ return None;
+
+ // Find the memory addressing operand in the instruction.
+ unsigned OpIndex = Desc.NumDefs;
+ while (OpIndex < Desc.getNumOperands() &&
+ Desc.OpInfo[OpIndex].OperandType != MCOI::OPERAND_MEMORY)
+ ++OpIndex;
+ if (OpIndex == Desc.getNumOperands())
+ return None;
+
+ // Base address for PC-relative addressing is always 32-bit aligned.
+ Addr &= ~0x3;
+
+ // For ARM instructions the PC offset is 8 bytes, for Thumb instructions it
+ // is 4 bytes.
+ switch (Desc.TSFlags & ARMII::FormMask) {
+ default:
+ Addr += 8;
+ break;
+ case ARMII::ThumbFrm:
+ Addr += 4;
+ break;
+ }
+
+ // Eveluate the address depending on the addressing mode
+ unsigned AddrMode = (TSFlags & ARMII::AddrModeMask);
+ switch (AddrMode) {
+ default:
+ return None;
+ case ARMII::AddrMode_i12:
+ return evaluateMemOpAddrForAddrMode_i12(Inst, Desc, OpIndex, Addr);
+ case ARMII::AddrMode3:
+ return evaluateMemOpAddrForAddrMode3(Inst, Desc, OpIndex, Addr);
+ case ARMII::AddrMode5:
+ return evaluateMemOpAddrForAddrMode5(Inst, Desc, OpIndex, Addr);
+ case ARMII::AddrModeT2_i8s4:
+ return evaluateMemOpAddrForAddrModeT2_i8s4(Inst, Desc, OpIndex, Addr);
+ case ARMII::AddrModeT2_pc:
+ return evaluateMemOpAddrForAddrModeT2_pc(Inst, Desc, OpIndex, Addr);
+ case ARMII::AddrModeT1_s:
+ return evaluateMemOpAddrForAddrModeT1_s(Inst, Desc, OpIndex, Addr);
+ }
}
static MCInstrAnalysis *createARMMCInstrAnalysis(const MCInstrInfo *Info) {
--- /dev/null
+@@ Check that PC-relative memory addressing is annotated\r
+\r
+@ RUN: llvm-mc %s -triple=armv7 -filetype=obj | \\r
+@ RUN: llvm-objdump -d --no-show-raw-insn --triple=armv7 - | \\r
+@ RUN: FileCheck %s\r
+\r
+.text\r
+foo:\r
+@ CHECK: 00000000 <foo>:\r
+ .word 0x01020304\r
+\r
+_start:\r
+@ CHECK: 00000004 <_start>:\r
+\r
+@@ Check a special case immediate for AddrMode_i12\r
+ ldr r1, [pc, #-0]\r
+@ CHECK-NEXT: 4: ldr r1, [pc, #-0] @ 0xc <_start+0x8>\r
+\r
+@@ Check AddrMode_i12 instructions, with positive and negative immediates\r
+ ldr r0, foo\r
+ ldrb r0, bar\r
+ pli _start\r
+ pld bar\r
+@ CHECK-NEXT: 8: ldr r0, [pc, #-16] @ 0x0 <foo>\r
+@ CHECK-NEXT: c: ldrb r0, [pc, #48] @ 0x44 <bar>\r
+@ CHECK-NEXT: 10: pli [pc, #-20] @ 0x4 <_start>\r
+@ CHECK-NEXT: 14: pld [pc, #40] @ 0x44 <bar>\r
+\r
+@@ Check that AddrMode_i12 instructions that do not use PC-relative addressing\r
+@@ are not annotated\r
+ ldr r0, [r1, #8]\r
+@ CHECK-NEXT: 18: ldr r0, [r1, #8]{{$}}\r
+\r
+@@ Check AddrMode3 instructions, with positive and negative immediates\r
+ ldrd r0, r1, foo\r
+ ldrh r0, bar\r
+@ CHECK-NEXT: 1c: ldrd r0, r1, [pc, #-36] @ 0x0 <foo>\r
+@ CHECK-NEXT: 20: ldrh r0, [pc, #28] @ 0x44 <bar>\r
+\r
+@@ Check that AddrMode3 instruction that do not use PC+imm addressing are not\r
+@@ annotated\r
+ ldrh r0, [r1, #8]\r
+ ldrh r0, [pc, r2]\r
+@ CHECK-NEXT: 24: ldrh r0, [r1, #8]{{$}}\r
+@ CHECK-NEXT: 28: ldrh r0, [pc, r2]{{$}}\r
+\r
+@@ Check AddrMode5 instructions, with positive and negative immediates\r
+ ldc p14, c5, foo\r
+ ldcl p6, c4, bar\r
+ ldc2 p5, c2, foo\r
+ ldc2l p3, c1, bar\r
+@ CHECK-NEXT: 2c: ldc p14, c5, [pc, #-52] @ 0x0 <foo>\r
+@ CHECK-NEXT: 30: ldcl p6, c4, [pc, #12] @ 0x44 <bar>\r
+@ CHECK-NEXT: 34: ldc2 p5, c2, [pc, #-60] @ 0x0 <foo>\r
+@ CHECK-NEXT: 38: ldc2l p3, c1, [pc, #4] @ 0x44 <bar>\r
+\r
+@@ Check that AddrMode5 instruction that do not use PC+imm addressing are not\r
+@@ annotated\r
+ ldc p14, c5, [r1, #8]\r
+ ldc p14, c5, [pc], {16}\r
+@ CHECK-NEXT: 3c: ldc p14, c5, [r1, #8]{{$}}\r
+@ CHECK-NEXT: 40: ldc p14, c5, [pc], {16}{{$}}\r
+\r
+bar:\r
+@ CHECK: 00000044 <bar>:\r
+ .word 0x01020304\r
--- /dev/null
+@@ Check that PC-relative memory addressing is annotated\r
+\r
+@ RUN: llvm-mc %s -triple=thumbv6m -filetype=obj | \\r
+@ RUN: llvm-objdump -d --no-show-raw-insn --triple=thumbv6m - | \\r
+@ RUN: FileCheck %s\r
+\r
+.text\r
+_start:\r
+@ CHECK: 00000000 <_start>:\r
+\r
+@@ Check AddrModeT1_s instruction, with 4-byte and 2-byte alignment\r
+ ldr r0, bar\r
+ ldr r1, bar\r
+ ldr r2, bar\r
+ ldr r3, bar\r
+@ CHECK-NEXT: 0: ldr r0, [pc, #4] @ 0x8 <bar>\r
+@ CHECK-NEXT: 2: ldr r1, [pc, #4] @ 0x8 <bar>\r
+@ CHECK-NEXT: 4: ldr r2, [pc, #0] @ 0x8 <bar>\r
+@ CHECK-NEXT: 6: ldr r3, [pc, #0] @ 0x8 <bar>\r
+\r
+ .balign 4\r
+bar:\r
+@ CHECK: 00000008 <bar>:\r
+ .word 0x01020304\r
--- /dev/null
+@@ Check that PC-relative memory addressing is annotated\r
+\r
+@ RUN: llvm-mc %s -triple=thumbv7 -filetype=obj | \\r
+@ RUN: llvm-objdump -d --no-show-raw-insn --triple=thumbv7 - | \\r
+@ RUN: FileCheck %s\r
+\r
+.text\r
+foo:\r
+@ CHECK: 00000000 <foo>:\r
+ .word 0x01020304\r
+\r
+_start:\r
+@ CHECK: 00000004 <_start>:\r
+\r
+@@ Check a special case immediate for AddrModeT2_pc\r
+ .balign 4\r
+ ldr r0, [pc, #-0]\r
+@ CHECK: 4: ldr.w r0, [pc, #-0] @ 0x8 <_start+0x4>\r
+\r
+@@ Same instruction, but the address is not 4-byte aligned\r
+ nop\r
+ ldr r0, [pc, #-0]\r
+@ CHECK: a: ldr.w r0, [pc, #-0] @ 0xc <_start+0x8>\r
+\r
+@@ Check a special case immediate for AddrModeT2_i8s4\r
+ .balign 4\r
+ ldrd r0, r1, [pc, #-0]\r
+@ CHECK: 10: ldrd r0, r1, [pc, #-0] @ 0x14 <_start+0x10>\r
+\r
+@@ Same instruction, but the address is not 4-byte aligned\r
+ nop\r
+ ldrd r0, r1, [pc, #-0]\r
+@ CHECK: 16: ldrd r0, r1, [pc, #-0] @ 0x18 <_start+0x14>\r
+\r
+@@ Check AddrModeT2_pc instructions, with positive and negative immediates\r
+ .balign 4\r
+ ldr r0, foo\r
+ ldrb r0, bar\r
+ ldrsb r0, foo\r
+ ldrsh r0, bar\r
+ pli _start\r
+ pld bar\r
+@ CHECK: 1c: ldr.w r0, [pc, #-32] @ 0x0 <foo>\r
+@ CHECK-NEXT: 20: ldrb.w r0, [pc, #112] @ 0x94 <bar>\r
+@ CHECK-NEXT: 24: ldrsb.w r0, [pc, #-40] @ 0x0 <foo>\r
+@ CHECK-NEXT: 28: ldrsh.w r0, [pc, #104] @ 0x94 <bar>\r
+@ CHECK-NEXT: 2c: pli [pc, #-44] @ 0x4 <_start>\r
+@ CHECK-NEXT: 30: pld [pc, #96] @ 0x94 <bar>\r
+\r
+@@ Same instructions, but the addresses are not 4-byte aligned\r
+ nop\r
+ ldr r0, foo\r
+ ldrb r0, bar\r
+ ldrsb r0, foo\r
+ ldrsh r0, bar\r
+ pli _start\r
+ pld bar\r
+@ CHECK: 36: ldr.w r0, [pc, #-56] @ 0x0 <foo>\r
+@ CHECK-NEXT: 3a: ldrb.w r0, [pc, #88] @ 0x94 <bar>\r
+@ CHECK-NEXT: 3e: ldrsb.w r0, [pc, #-64] @ 0x0 <foo>\r
+@ CHECK-NEXT: 42: ldrsh.w r0, [pc, #80] @ 0x94 <bar>\r
+@ CHECK-NEXT: 46: pli [pc, #-68] @ 0x4 <_start>\r
+@ CHECK-NEXT: 4a: pld [pc, #72] @ 0x94 <bar>\r
+\r
+@@ Check AddrModeT2_i8s4 instructions, with positive and negative immediates\r
+ .balign 4\r
+ ldrd r0, r1, foo\r
+ ldrd r0, r1, bar\r
+@ CHECK: 50: ldrd r0, r1, [pc, #-84] @ 0x0 <foo>\r
+@ CHECK-NEXT: 54: ldrd r0, r1, [pc, #60] @ 0x94 <bar>\r
+\r
+@@ Same instructions, but the addresses are not 4-byte aligned\r
+ nop\r
+ ldrd r0, r1, foo\r
+ ldrd r0, r1, bar\r
+@ CHECK: 5a: ldrd r0, r1, [pc, #-92] @ 0x0 <foo>\r
+@ CHECK-NEXT: 5e: ldrd r0, r1, [pc, #52] @ 0x94 <bar>\r
+\r
+@@ Check that AddrModeT2_i8s4 instructions that do not use PC-relative\r
+@@ addressingare not annotated\r
+ ldrd r0, r1, [r2, #8]\r
+@ CHECK: 62: ldrd r0, r1, [r2, #8]{{$}}\r
+\r
+@@ Check AddrMode5 instructions, with positive and negative immediates\r
+ .balign 4\r
+ ldc p14, c5, foo\r
+ ldcl p6, c4, bar\r
+ ldc2 p5, c2, foo\r
+ ldc2l p3, c1, bar\r
+@ CHECK: 68: ldc p14, c5, [pc, #-108] @ 0x0 <foo>\r
+@ CHECK-NEXT: 6c: ldcl p6, c4, [pc, #36] @ 0x94 <bar>\r
+@ CHECK-NEXT: 70: ldc2 p5, c2, [pc, #-116] @ 0x0 <foo>\r
+@ CHECK-NEXT: 74: ldc2l p3, c1, [pc, #28] @ 0x94 <bar>\r
+\r
+@@ Same instructions, but the addresses are not 4-byte aligned\r
+ nop\r
+ ldc p14, c5, foo\r
+ ldcl p6, c4, bar\r
+ ldc2 p5, c2, foo\r
+ ldc2l p3, c1, bar\r
+@ CHECK: 7a: ldc p14, c5, [pc, #-124] @ 0x0 <foo>\r
+@ CHECK-NEXT: 7e: ldcl p6, c4, [pc, #20] @ 0x94 <bar>\r
+@ CHECK-NEXT: 82: ldc2 p5, c2, [pc, #-132] @ 0x0 <foo>\r
+@ CHECK-NEXT: 86: ldc2l p3, c1, [pc, #12] @ 0x94 <bar>\r
+\r
+@@ Check that AddrMode5 instruction that do not use PC+imm addressing are not\r
+@@ annotated\r
+ ldc p14, c5, [r1, #8]\r
+ ldc p14, c5, [pc], {16}\r
+@ CHECK: 8a: ldc p14, c5, [r1, #8]{{$}}\r
+@ CHECK-NEXT: 8e: ldc p14, c5, [pc], {16}{{$}}\r
+\r
+ .balign 4\r
+bar:\r
+@ CHECK: 00000094 <bar>:\r
+ .word 0x01020304\r