diff --git a/llvm/lib/Target/ARM/ARMInstrInfo.td b/llvm/lib/Target/ARM/ARMInstrInfo.td --- a/llvm/lib/Target/ARM/ARMInstrInfo.td +++ b/llvm/lib/Target/ARM/ARMInstrInfo.td @@ -2619,6 +2619,7 @@ let Inst{7-4} = 0b0010; let Inst{3-0} = func; let isBranch = 1; + let isIndirectBranch = 1; } // Tail calls. diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp @@ -408,45 +408,51 @@ return MCInstrAnalysis::isConditionalBranch(Inst); } - bool evaluateBranch(const MCInst &Inst, uint64_t Addr, - uint64_t Size, uint64_t &Target) const override { - // We only handle PCRel branches for now. - if (Inst.getNumOperands() == 0 || - Info->get(Inst.getOpcode()).OpInfo[0].OperandType != - MCOI::OPERAND_PCREL) - return false; - - int64_t Imm = Inst.getOperand(0).getImm(); - Target = Addr+Imm+8; // In ARM mode the PC is always off by 8 bytes. - return true; - } -}; - -class ThumbMCInstrAnalysis : public ARMMCInstrAnalysis { -public: - ThumbMCInstrAnalysis(const MCInstrInfo *Info) : ARMMCInstrAnalysis(Info) {} - bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, uint64_t &Target) const override { unsigned OpId; + uint64_t Offset; + switch (Inst.getOpcode()) { - default: + case ARM::B: + case ARM::Bcc: + case ARM::BL: + case ARM::BLXi: + case ARM::BL_pred: + OpId = 0; + Offset = 8; + break; + case ARM::tB: + case ARM::tBcc: + case ARM::t2B: + case ARM::t2Bcc: + case ARM::t2LE: OpId = 0; - if (Inst.getNumOperands() == 0) - return false; + Offset = 4; + break; + case ARM::tCBZ: + case ARM::tCBNZ: + OpId = 1; + Offset = 4; break; + case ARM::tBL: + case ARM::tBLXi: + case ARM::MVE_LETP: case ARM::MVE_WLSTP_8: case ARM::MVE_WLSTP_16: case ARM::MVE_WLSTP_32: case ARM::MVE_WLSTP_64: case ARM::t2WLS: - case ARM::MVE_LETP: case ARM::t2LEUpdate: OpId = 2; + Offset = 4; break; - case ARM::t2LE: - OpId = 1; - break; + default: + // The above should handle all direct branches. + const MCInstrDesc &Desc = Info->get(Inst.getOpcode()); + assert((!Desc.isBranch() || Desc.isIndirectBranch()) && + "Unhandled direct branch"); + return false; } // We only handle PCRel branches for now. @@ -454,8 +460,7 @@ MCOI::OPERAND_PCREL) return false; - // In Thumb mode the PC is always off by 4 bytes. - Target = Addr + Inst.getOperand(OpId).getImm() + 4; + Target = Addr + Inst.getOperand(OpId).getImm() + Offset; return true; } }; @@ -466,10 +471,6 @@ return new ARMMCInstrAnalysis(Info); } -static MCInstrAnalysis *createThumbMCInstrAnalysis(const MCInstrInfo *Info) { - return new ThumbMCInstrAnalysis(Info); -} - bool ARM::isCDECoproc(size_t Coproc, const MCSubtargetInfo &STI) { // Unfortunately we don't have ARMTargetInfo in the disassembler, so we have // to rely on feature bits. @@ -517,10 +518,9 @@ } // Register the MC instruction analyzer. - for (Target *T : {&getTheARMLETarget(), &getTheARMBETarget()}) + for (Target *T : {&getTheARMLETarget(), &getTheARMBETarget(), + &getTheThumbLETarget(), &getTheThumbBETarget()}) TargetRegistry::RegisterMCInstrAnalysis(*T, createARMMCInstrAnalysis); - for (Target *T : {&getTheThumbLETarget(), &getTheThumbBETarget()}) - TargetRegistry::RegisterMCInstrAnalysis(*T, createThumbMCInstrAnalysis); for (Target *T : {&getTheARMLETarget(), &getTheThumbLETarget()}) { TargetRegistry::RegisterMCCodeEmitter(*T, createARMLEMCCodeEmitter); diff --git a/llvm/test/tools/llvm-objdump/ELF/ARM/branch-symbols.s b/llvm/test/tools/llvm-objdump/ELF/ARM/branch-symbols.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/ELF/ARM/branch-symbols.s @@ -0,0 +1,69 @@ +@ RUN: llvm-mc < %s --triple=armv8a -mattr=+mve,+lob -filetype=obj | llvm-objdump -dr - --triple armv8a --mattr=+mve,+lob | FileCheck %s + +foo: + + // Branches + .arm + b foo + ble foo +@ CHECK: 0: fe ff ff ea b #-8 +@ CHECK: 4: fd ff ff da ble #-12 + + .thumb + b foo + b.w foo + ble foo + ble.w foo + le foo + le lr, foo + cbz r0, bar + cbnz r0, bar +@ CHECK: 8: fa e7 b #-12 +@ CHECK: a: ff f7 f9 bf b.w #-14 +@ CHECK: e: f7 dd ble #-18 +@ CHECK: 10: 7f f7 f6 af ble.w #-20 +@ CHECK: 14: 2f f0 0d c0 le #-24 +@ CHECK: 18: 0f f0 0f c0 le lr, #-28 +@ CHECK: 1c: a0 b1 cbz r0, #40 +@ CHECK: 1e: 98 b9 cbnz r0, #38 + + // Calls without relocations (these offsets al correspond to label foo). + .arm + bl #-40 + blx #-44 + bleq #-48 +@ CHECK: 20: f6 ff ff eb bl #-40 +@ CHECK: 24: f5 ff ff fa blx #-44 +@ CHECK: 28: f4 ff ff 0b bleq #-48 + + .thumb + bl #-48 + blx #-52 +@ CHECK: 2c: ff f7 e8 ff bl #-48 +@ CHECK: 30: ff f7 e6 ef blx #-52 + + // Calls with relocations. These currently emit a reference to their own + // location, because we don't take relocations into account when printing + // branch targets. + .arm + bl baz + blx baz + bleq baz +@ CHECK: 34: fe ff ff eb bl #-8 <$a.4> +@ CHECK: 00000034: R_ARM_CALL baz +@ CHECK: 38: fe ff ff fa blx #-8 <$a.4+0x4> +@ CHECK: 00000038: R_ARM_CALL baz +@ CHECK: 3c: fe ff ff 0b bleq #-8 <$a.4+0x8> +@ CHECK: 0000003c: R_ARM_JUMP24 baz + + .thumb + bl baz + blx baz +@ CHECK: 40: ff f7 fe ff bl #-4 <$t.5> +@ CHECK: 00000040: R_ARM_THM_CALL baz +@ CHECK: 44: ff f7 fe ef blx #-4 <$t.5+0x4> +@ CHECK: 00000044: R_ARM_THM_CALL baz + +bar: + +