diff --git a/lld/test/ELF/ppc64-toc-call-to-pcrel.s b/lld/test/ELF/ppc64-toc-call-to-pcrel.s --- a/lld/test/ELF/ppc64-toc-call-to-pcrel.s +++ b/lld/test/ELF/ppc64-toc-call-to-pcrel.s @@ -29,23 +29,22 @@ # SYMBOL: 10020020 0 NOTYPE LOCAL DEFAULT [] 2 caller_14 # SYMBOL: 10020040 8 FUNC LOCAL DEFAULT 2 __toc_save_callee -# CHECK-LABEL: callee +# CHECK-LABEL: : # CHECK: blr -# CHECK-LABEL: caller -# CHECK: bl 0x10020040 +# CHECK-LABEL: : +# CHECK: bl 0x10020040 <__toc_save_callee> # CHECK-NEXT: ld 2, 24(1) # CHECK-NEXT: blr -# CHECK-LABEL: caller_14 -# CHECK: bfl 0, 0x10020040 +# CHECK-LABEL: : +# CHECK: bfl 0, 0x10020040 <__toc_save_callee> # CHECK-NEXT: ld 2, 24(1) # CHECK-NEXT: blr -# CHECK-LABEL: __toc_save_callee +# CHECK-LABEL: <__toc_save_callee>: # CHECK-NEXT: std 2, 24(1) -# CHECK-NEXT: b 0x10010000 - +# CHECK-NEXT: b 0x10010000 .section .text_callee, "ax", %progbits callee: diff --git a/llvm/docs/CommandGuide/llvm-objdump.rst b/llvm/docs/CommandGuide/llvm-objdump.rst --- a/llvm/docs/CommandGuide/llvm-objdump.rst +++ b/llvm/docs/CommandGuide/llvm-objdump.rst @@ -226,7 +226,7 @@ When printing a PC-relative global symbol reference, print it as an offset from the leading symbol. - Only works with an X86 linked image. + Only works with PowerPC objects or X86 linked images. Example: A non-symbolized branch instruction with a local target and pc-relative memory access like diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp @@ -28,6 +28,7 @@ #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCELFStreamer.h" #include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInstrAnalysis.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCRegisterInfo.h" @@ -368,6 +369,31 @@ return new PPCInstPrinter(MAI, MII, MRI, T); } +namespace { + +class PPCMCInstrAnalysis : public MCInstrAnalysis { +public: + explicit PPCMCInstrAnalysis(const MCInstrInfo *Info) + : MCInstrAnalysis(Info) {} + + bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, + uint64_t &Target) const override { + unsigned NumOps = Inst.getNumOperands(); + if (NumOps == 0 || + Info->get(Inst.getOpcode()).OpInfo[NumOps - 1].OperandType != + MCOI::OPERAND_PCREL) + return false; + Target = Addr + Inst.getOperand(NumOps - 1).getImm() * Size; + return true; + } +}; + +} // end anonymous namespace + +static MCInstrAnalysis *createPPCMCInstrAnalysis(const MCInstrInfo *Info) { + return new PPCMCInstrAnalysis(Info); +} + extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializePowerPCTargetMC() { for (Target *T : {&getThePPC32Target(), &getThePPC32LETarget(), &getThePPC64Target(), &getThePPC64LETarget()}) { @@ -383,6 +409,9 @@ // Register the MC subtarget info. TargetRegistry::RegisterMCSubtargetInfo(*T, createPPCMCSubtargetInfo); + // Register the MC instruction analyzer. + TargetRegistry::RegisterMCInstrAnalysis(*T, createPPCMCInstrAnalysis); + // Register the MC Code Emitter TargetRegistry::RegisterMCCodeEmitter(*T, createPPCMCCodeEmitter); diff --git a/llvm/test/tools/llvm-objdump/ELF/PowerPC/disassemble-symbolize-operands.ll b/llvm/test/tools/llvm-objdump/ELF/PowerPC/disassemble-symbolize-operands.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/ELF/PowerPC/disassemble-symbolize-operands.ll @@ -0,0 +1,59 @@ +; RUN: llc -mtriple=powerpc64le-unknown-linux-gnu %s -filetype=obj -o %t +; RUN: llvm-objdump %t -d --symbolize-operands --no-show-raw-insn \ +; RUN: | FileCheck %s + +;; Expect to find the branch labels. +; CHECK-LABEL: : +; CHECK: : +; CHECK-NEXT: 20: addi 3, 3, 1 +; CHECK-NEXT: 24: bdnz 0x20 +; CHECK-NEXT: 28: blr + +; CHECK-LABEL: : +; CHECK: 6c: b 0x74 +; CHECK-NEXT: : +; CHECK-NEXT: 70: bf 8, 0x94 +; CHECK-NEXT: : +; CHECK-NEXT: 74: clrldi 3, 30, 32 +; CHECK-NEXT: 78: bl 0x0 +; CHECK-NEXT: 7c: mr 30, 3 +; CHECK-NEXT: 80: cmplwi 30, 11 +; CHECK-NEXT: 84: bt 0, 0x70 +; CHECK-NEXT: 88: bl 0x88 +; CHECK-NEXT: 8c: nop +; CHECK-NEXT: 90: b 0x70 +; CHECK-NEXT: : +; CHECK-NEXT: 94: ld 30, 32(1) + +define internal i32 @internal(i32 %a) { +entry: + br label %for.body + +for.body: + %i = phi i32 [ 0, %entry ], [ %next, %for.body ] + %next = add nuw nsw i32 %i, 1 + %cond = icmp eq i32 %next, %a + br i1 %cond, label %exit, label %for.body + +exit: + ret i32 %next +} + +declare void @extern() + +define void @foo(i1 %breakcond) { +entry: + br label %loop +loop: + %tmp23phi = phi i32 [ %tmp23, %endif ], [ 0, %entry ] + %tmp23 = call i32 @internal(i32 %tmp23phi) + %tmp27 = icmp ult i32 10, %tmp23 + br i1 %tmp27, label %then, label %endif +then: ; preds = %bb + call void @extern() + br label %endif +endif: ; preds = %bb28, %bb + br i1 %breakcond, label %loop, label %loopexit +loopexit: + ret void +} diff --git a/llvm/test/tools/llvm-objdump/XCOFF/disassemble-symbolize-operands.ll b/llvm/test/tools/llvm-objdump/XCOFF/disassemble-symbolize-operands.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/XCOFF/disassemble-symbolize-operands.ll @@ -0,0 +1,63 @@ +; RUN: llc -mtriple=powerpc-ibm-aix-xcoff %s -filetype=obj -o %t +; RUN: llvm-objdump %t -d --symbolize-operands --no-show-raw-insn \ +; RUN: | FileCheck %s + +;; Expect to find the branch labels. +; CHECK-LABEL: <.text>: +;; TODO: <.internal> should be printed instead of <.text>. +; CHECK-NEXT: 0: mr 4, 3 +; CHECK-NEXT: 4: li 3, 0 +; CHECK-NEXT: 8: mtctr 4 +; CHECK-NEXT: : +; CHECK-NEXT: c: addi 3, 3, 1 +; CHECK-NEXT: 10: bdnz 0xc +; CHECK-NEXT: 14: blr + +; CHECK-LABEL: <.foo>: +; CHECK: 5c: b 0x64 +; CHECK-NEXT: : +; CHECK-NEXT: 60: bf 8, 0x84 +; CHECK-NEXT: : +; CHECK-NEXT: 64: mr 3, 31 +; CHECK-NEXT: 68: bl 0x0 <.text> +; CHECK-NEXT: 6c: mr 31, 3 +; CHECK-NEXT: 70: cmplwi 3, 11 +; CHECK-NEXT: 74: bt 0, 0x60 +; CHECK-NEXT: 78: bl 0x0 <.text> +; CHECK-NEXT: 7c: nop +; CHECK-NEXT: 80: b 0x60 +; CHECK-NEXT: : +; CHECK-NEXT: 84: lwz 31, 60(1) + +define internal i32 @internal(i32 %a) { +entry: + br label %for.body + +for.body: + %i = phi i32 [ 0, %entry ], [ %next, %for.body ] + %next = add nuw nsw i32 %i, 1 + %cond = icmp eq i32 %next, %a + br i1 %cond, label %exit, label %for.body + +exit: + ret i32 %next +} + +declare void @extern() + +define void @foo(i1 %breakcond) { +entry: + br label %loop +loop: + %tmp23phi = phi i32 [ %tmp23, %endif ], [ 0, %entry ] + %tmp23 = call i32 @internal(i32 %tmp23phi) + %tmp27 = icmp ult i32 10, %tmp23 + br i1 %tmp27, label %then, label %endif +then: ; preds = %bb + call void @extern() + br label %endif +endif: ; preds = %bb28, %bb + br i1 %breakcond, label %loop, label %loopexit +loopexit: + ret void +} diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -978,8 +978,8 @@ const MCSubtargetInfo *STI, uint64_t SectionAddr, uint64_t Start, uint64_t End, std::unordered_map &Labels) { - // So far only supports X86. - if (!STI->getTargetTriple().isX86()) + // So far only supports PowerPC and X86. + if (!STI->getTargetTriple().isPPC() && !STI->getTargetTriple().isX86()) return; Labels.clear(); @@ -999,8 +999,11 @@ if (Disassembled && MIA) { uint64_t Target; bool TargetKnown = MIA->evaluateBranch(Inst, Index, Size, Target); + // On PowerPC, if the address of a branch is the same as the target, it + // means that it's a function call. Do not mark the label for this case. if (TargetKnown && (Target >= Start && Target < End) && - !Labels.count(Target)) + !Labels.count(Target) && + !(STI->getTargetTriple().isPPC() && Target == Index)) Labels[Target] = ("L" + Twine(LabelCount++)).str(); }