From 60db144980fec301db38405364e4b89608aa03bd Mon Sep 17 00:00:00 2001 From: quic-areg Date: Thu, 19 Jun 2025 11:00:52 -0700 Subject: [PATCH 1/5] [Hexagon][llvm-objdump] Improve disassembly of Hexagon bundles Hexagon instructions are VLIW "bundles" of up to four instruction words encoded as a single MCInst with operands for each sub-instruction. Previously, the disassembler's getInstruction() returned the full bundle, which made it difficult to work with llvm-objdump. For example, since all instructions are bundles, and bundles do not branch, branch targets could not be printed. This patch modifies the Hexagon disassembler to return individual sub-instructions instead of entire bundles, enabling correct printing of branch targets and relocations. It also introduces `MCDisassembler::getInstructionBundle` for cases where the full bundle is still needed. By default, llvm-objdump separates instructions with newlines. However, this does not work well for Hexagon syntax: { inst1 inst2 inst3 inst4 } :endloop0 Instructions may be followed by a closing brace, a closing brace with `:endloop`, or a newline. Branches must appear within the braces. To address this, `PrettyPrinter::getInstructionSeparator()` is added and overridden for Hexagon. --- lld/test/ELF/hexagon-plt.s | 18 +- lld/test/ELF/hexagon-shared.s | 2 +- lld/test/ELF/hexagon-tls-gd-xform.s | 4 +- .../llvm/MC/MCDisassembler/MCDisassembler.h | 12 ++ .../Disassembler/HexagonDisassembler.cpp | 109 ++++++++--- .../MCTargetDesc/HexagonInstPrinter.cpp | 35 ++-- .../MCTargetDesc/HexagonMCTargetDesc.cpp | 19 +- llvm/test/MC/Hexagon/two_ext.s | 4 +- .../ELF/Hexagon/branch-targets.yaml | 26 +++ llvm/tools/llvm-mc/Disassembler.cpp | 6 +- llvm/tools/llvm-objdump/llvm-objdump.cpp | 179 +++++++++++------- 11 files changed, 275 insertions(+), 139 deletions(-) create mode 100644 llvm/test/tools/llvm-objdump/ELF/Hexagon/branch-targets.yaml diff --git a/lld/test/ELF/hexagon-plt.s b/lld/test/ELF/hexagon-plt.s index 679de82923a72..780dc434a6698 100644 --- a/lld/test/ELF/hexagon-plt.s +++ b/lld/test/ELF/hexagon-plt.s @@ -30,31 +30,31 @@ # DIS: <_start>: ## Direct call ## Call foo directly -# DIS-NEXT: { call 0x2003c } +# DIS-NEXT: { call 0x2003c } ## Call bar via plt -# DIS-NEXT: { call 0x20060 } +# DIS-NEXT: { call 0x20060 } ## Call weak via plt -# DIS-NEXT: { call 0x20070 } +# DIS-NEXT: { call 0x20070 } # DIS-NEXT: { immext(#0) ## Call foo directly -# DIS-NEXT: if (p0) jump:nt 0x2003c } +# DIS-NEXT: if (p0) jump:nt 0x2003c } # DIS-NEXT: { immext(#64) ## Call bar via plt -# DIS-NEXT: if (p0) jump:nt 0x20060 } +# DIS-NEXT: if (p0) jump:nt 0x20060 } # DIS-NEXT: { immext(#64) ## Call weak via plt -# DIS-NEXT: if (p0) jump:nt 0x20070 } +# DIS-NEXT: if (p0) jump:nt 0x20070 } # DIS-NEXT: { immext(#0) ## Call foo directly -# DIS-NEXT: r0 = #0 ; jump 0x2003c } +# DIS-NEXT: r0 = #0 ; jump 0x2003c } # DIS-NEXT: { immext(#0) ## Call bar via plt -# DIS-NEXT: r0 = #0 ; jump 0x20060 } +# DIS-NEXT: r0 = #0 ; jump 0x20060 } # DIS-NEXT: { immext(#0) ## Call weak via plt -# DIS-NEXT: r0 = #0 ; jump 0x20070 } +# DIS-NEXT: r0 = #0 ; jump 0x20070 } # DIS: : # DIS-NEXT: 2003c: diff --git a/lld/test/ELF/hexagon-shared.s b/lld/test/ELF/hexagon-shared.s index cc62662d278e2..7f7390f1fa8d8 100644 --- a/lld/test/ELF/hexagon-shared.s +++ b/lld/test/ELF/hexagon-shared.s @@ -88,7 +88,7 @@ pvar: # PLT-NEXT: jumpr r28 } # TEXT: bc 00 01 00 000100bc -# TEXT: { call 0x10300 } +# TEXT: { call 0x10300 } # TEXT: if (p0) jump:nt 0x10300 # TEXT: r0 = #0 ; jump 0x10300 # TEXT: r0 = add(r1,##-65548) diff --git a/lld/test/ELF/hexagon-tls-gd-xform.s b/lld/test/ELF/hexagon-tls-gd-xform.s index 65aeb118fcb33..ade54e8a16fad 100644 --- a/lld/test/ELF/hexagon-tls-gd-xform.s +++ b/lld/test/ELF/hexagon-tls-gd-xform.s @@ -18,10 +18,10 @@ _start: .ifdef GDPLT call x@gdplt -# CHECK_GDPLT: 101ec: { call 0x10220 } +# CHECK_GDPLT: 101ec: { call 0x10220 <__tls_get_addr@plt> } .else call x -# CHECK: 101b8: { call 0x101e0 } +# CHECK: 101b8: { call 0x101e0 } .endif # CHECK_GDPLT: 10220: { immext(#0x20040) diff --git a/llvm/include/llvm/MC/MCDisassembler/MCDisassembler.h b/llvm/include/llvm/MC/MCDisassembler/MCDisassembler.h index 3a7ca1a69ab85..cae2fbcac1fef 100644 --- a/llvm/include/llvm/MC/MCDisassembler/MCDisassembler.h +++ b/llvm/include/llvm/MC/MCDisassembler/MCDisassembler.h @@ -136,6 +136,18 @@ class LLVM_ABI MCDisassembler { ArrayRef Bytes, uint64_t Address, raw_ostream &CStream) const = 0; + /// Returns the disassembly of an instruction bundle for VLIW architectures + /// like Hexagon. + /// + /// \param Instr - An MCInst to populate with the contents of + /// the Bundle with sub-instructions encoded as Inst operands. + virtual DecodeStatus getInstructionBundle(MCInst &Instr, uint64_t &Size, + ArrayRef Bytes, + uint64_t Address, + raw_ostream &CStream) const { + return Fail; + } + /// Used to perform separate target specific disassembly for a particular /// symbol. May parse any prelude that precedes instructions after the /// start of a symbol, or the entire symbol. diff --git a/llvm/lib/Target/Hexagon/Disassembler/HexagonDisassembler.cpp b/llvm/lib/Target/Hexagon/Disassembler/HexagonDisassembler.cpp index 5bd31707acb6f..22cff7c80fa01 100644 --- a/llvm/lib/Target/Hexagon/Disassembler/HexagonDisassembler.cpp +++ b/llvm/lib/Target/Hexagon/Disassembler/HexagonDisassembler.cpp @@ -43,12 +43,12 @@ namespace { class HexagonDisassembler : public MCDisassembler { public: std::unique_ptr const MCII; - std::unique_ptr CurrentBundle; + mutable std::unique_ptr CurrentBundle; mutable MCInst const *CurrentExtender; HexagonDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, MCInstrInfo const *MCII) - : MCDisassembler(STI, Ctx), MCII(MCII), CurrentBundle(new MCInst *), + : MCDisassembler(STI, Ctx), MCII(MCII), CurrentBundle(nullptr), CurrentExtender(nullptr) {} DecodeStatus getSingleInstruction(MCInst &Instr, MCInst &MCB, @@ -57,7 +57,23 @@ class HexagonDisassembler : public MCDisassembler { DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, ArrayRef Bytes, uint64_t Address, raw_ostream &CStream) const override; + + DecodeStatus getInstructionBundle(MCInst &Instr, uint64_t &Size, + ArrayRef Bytes, uint64_t Address, + raw_ostream &CStream) const override; + void remapInstruction(MCInst &Instr) const; + +private: + bool makeBundle(ArrayRef Bytes, uint64_t Address, + uint64_t &BytesToSkip, raw_ostream &CS) const; + + void resetBundle() const { + CurrentBundle.reset(); + CurrentInstruction = nullptr; + } + + mutable MCOperand *CurrentInstruction = nullptr; }; static uint64_t fullValue(HexagonDisassembler const &Disassembler, MCInst &MI, @@ -171,43 +187,88 @@ LLVMInitializeHexagonDisassembler() { createHexagonDisassembler); } -DecodeStatus HexagonDisassembler::getInstruction(MCInst &MI, uint64_t &Size, - ArrayRef Bytes, - uint64_t Address, - raw_ostream &CS) const { - CommentStream = &CS; - - DecodeStatus Result = DecodeStatus::Success; +bool HexagonDisassembler::makeBundle(ArrayRef Bytes, uint64_t Address, + uint64_t &BytesToSkip, + raw_ostream &CS) const { bool Complete = false; - Size = 0; + DecodeStatus Result = DecodeStatus::Success; - *CurrentBundle = &MI; - MI.setOpcode(Hexagon::BUNDLE); - MI.addOperand(MCOperand::createImm(0)); + CurrentBundle.reset(new MCInst); + CurrentBundle->setOpcode(Hexagon::BUNDLE); + CurrentBundle->addOperand(MCOperand::createImm(0)); while (Result == Success && !Complete) { if (Bytes.size() < HEXAGON_INSTR_SIZE) - return MCDisassembler::Fail; + return false; MCInst *Inst = getContext().createMCInst(); - Result = getSingleInstruction(*Inst, MI, Bytes, Address, CS, Complete); - MI.addOperand(MCOperand::createInst(Inst)); - Size += HEXAGON_INSTR_SIZE; + Result = getSingleInstruction(*Inst, *CurrentBundle, Bytes, Address, CS, + Complete); + CurrentBundle->addOperand(MCOperand::createInst(Inst)); + BytesToSkip += HEXAGON_INSTR_SIZE; Bytes = Bytes.slice(HEXAGON_INSTR_SIZE); } if (Result == MCDisassembler::Fail) - return Result; - if (Size > HEXAGON_MAX_PACKET_SIZE) - return MCDisassembler::Fail; + return false; + if (BytesToSkip > HEXAGON_MAX_PACKET_SIZE) + return false; const auto ArchSTI = Hexagon_MC::getArchSubtarget(&STI); const auto STI_ = (ArchSTI != nullptr) ? *ArchSTI : STI; - HexagonMCChecker Checker(getContext(), *MCII, STI_, MI, + HexagonMCChecker Checker(getContext(), *MCII, STI_, *CurrentBundle, *getContext().getRegisterInfo(), false); if (!Checker.check()) - return MCDisassembler::Fail; - remapInstruction(MI); + return false; + remapInstruction(*CurrentBundle); + return true; +} + +DecodeStatus HexagonDisassembler::getInstruction(MCInst &MI, uint64_t &Size, + ArrayRef Bytes, + uint64_t Address, + raw_ostream &CS) const { + CommentStream = &CS; + + Size = 0; + uint64_t BytesToSkip = 0; + + if (!CurrentBundle) { + if (!makeBundle(Bytes, Address, BytesToSkip, CS)) { + Size = BytesToSkip; + resetBundle(); + return MCDisassembler::Fail; + } + CurrentInstruction = (CurrentBundle->begin() + 1); + } + + MI = *(CurrentInstruction->getInst()); + Size = HEXAGON_INSTR_SIZE; + if (++CurrentInstruction == CurrentBundle->end()) + resetBundle(); return MCDisassembler::Success; } +DecodeStatus HexagonDisassembler::getInstructionBundle(MCInst &MI, + uint64_t &Size, + ArrayRef Bytes, + uint64_t Address, + raw_ostream &CS) const { + CommentStream = &CS; + Size = 0; + uint64_t BytesToSkip = 0; + assert(!CurrentBundle); + + if (!makeBundle(Bytes, Address, BytesToSkip, CS)) { + Size = BytesToSkip; + resetBundle(); + return MCDisassembler::Fail; + } + + MI = *CurrentBundle; + Size = HEXAGON_INSTR_SIZE * HexagonMCInstrInfo::bundleSize(MI); + resetBundle(); + + return Success; +} + void HexagonDisassembler::remapInstruction(MCInst &Instr) const { for (auto I: HexagonMCInstrInfo::bundleInstructions(Instr)) { auto &MI = const_cast(*I.getInst()); @@ -482,7 +543,7 @@ DecodeStatus HexagonDisassembler::getSingleInstruction(MCInst &MI, MCInst &MCB, unsigned Offset = 1; bool Vector = HexagonMCInstrInfo::isVector(*MCII, MI); bool PrevVector = false; - auto Instructions = HexagonMCInstrInfo::bundleInstructions(**CurrentBundle); + auto Instructions = HexagonMCInstrInfo::bundleInstructions(*CurrentBundle); auto i = Instructions.end() - 1; for (auto n = Instructions.begin() - 1;; --i, ++Offset) { if (i == n) diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.cpp index 9030e43b7149f..50b66772212a4 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.cpp @@ -33,30 +33,17 @@ void HexagonInstPrinter::printRegName(raw_ostream &O, MCRegister Reg) { void HexagonInstPrinter::printInst(const MCInst *MI, uint64_t Address, StringRef Annot, const MCSubtargetInfo &STI, raw_ostream &OS) { - assert(HexagonMCInstrInfo::isBundle(*MI)); - assert(HexagonMCInstrInfo::bundleSize(*MI) <= HEXAGON_PACKET_SIZE); - assert(HexagonMCInstrInfo::bundleSize(*MI) > 0); - HasExtender = false; - for (auto const &I : HexagonMCInstrInfo::bundleInstructions(*MI)) { - MCInst const &MCI = *I.getInst(); - if (HexagonMCInstrInfo::isDuplex(MII, MCI)) { - printInstruction(MCI.getOperand(1).getInst(), Address, OS); - OS << '\v'; - HasExtender = false; - printInstruction(MCI.getOperand(0).getInst(), Address, OS); - } else - printInstruction(&MCI, Address, OS); - HasExtender = HexagonMCInstrInfo::isImmext(MCI); - OS << "\n"; - } - - bool IsLoop0 = HexagonMCInstrInfo::isInnerLoop(*MI); - bool IsLoop1 = HexagonMCInstrInfo::isOuterLoop(*MI); - if (IsLoop0) { - OS << (IsLoop1 ? " :endloop01" : " :endloop0"); - } else if (IsLoop1) { - OS << " :endloop1"; - } + if (HexagonMCInstrInfo::isDuplex(MII, *MI)) { + printInstruction(MI->getOperand(1).getInst(), Address, OS); + OS << '\v'; + HasExtender = false; + printInstruction(MI->getOperand(0).getInst(), Address, OS); + } else + printInstruction(MI, Address, OS); + HasExtender = HexagonMCInstrInfo::isImmext(*MI); + if ((MI->getOpcode() & HexagonII::INST_PARSE_MASK) == + HexagonII::INST_PARSE_PACKET_END) + HasExtender = false; } void HexagonInstPrinter::printOperand(MCInst const *MI, unsigned OpNo, diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp index 980df819b2c26..bfea50e2d6dc0 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp @@ -252,8 +252,21 @@ class HexagonTargetAsmStreamer : public HexagonTargetStreamer { std::string Buffer; { raw_string_ostream TempStream(Buffer); - InstPrinter.printInst(&Inst, Address, "", STI, TempStream); + for (auto &I : HexagonMCInstrInfo::bundleInstructions(Inst)) { + InstPrinter.printInst(I.getInst(), Address, "", STI, TempStream); + TempStream << "\n"; + } + } + + std::string LoopString = ""; + bool IsLoop0 = HexagonMCInstrInfo::isInnerLoop(Inst); + bool IsLoop1 = HexagonMCInstrInfo::isOuterLoop(Inst); + if (IsLoop0) { + LoopString += (IsLoop1 ? " :endloop01" : " :endloop0"); + } else if (IsLoop1) { + LoopString += " :endloop1"; } + StringRef Contents(Buffer); auto PacketBundle = Contents.rsplit('\n'); auto HeadTail = PacketBundle.first.split('\n'); @@ -275,9 +288,9 @@ class HexagonTargetAsmStreamer : public HexagonTargetStreamer { } if (HexagonMCInstrInfo::isMemReorderDisabled(Inst)) - OS << "\n\t} :mem_noshuf" << PacketBundle.second; + OS << "\n\t} :mem_noshuf" << LoopString; else - OS << "\t}" << PacketBundle.second; + OS << "\t}" << LoopString; } void finish() override { finishAttributeSection(); } diff --git a/llvm/test/MC/Hexagon/two_ext.s b/llvm/test/MC/Hexagon/two_ext.s index 28b2aa3f1ecae..09b51c5f029a7 100644 --- a/llvm/test/MC/Hexagon/two_ext.s +++ b/llvm/test/MC/Hexagon/two_ext.s @@ -6,7 +6,7 @@ if (!p1) call foo_b } # CHECK: 00004000 { immext(#0) -# CHECK: 5d004100 if (p1) call 0x0 +# CHECK: 5d004100 if (p1) call 0x0 <.text> # CHECK: 00004000 immext(#0) -# CHECK: 5d20c100 if (!p1) call 0x0 } +# CHECK: 5d20c100 if (!p1) call 0x0 <.text> } diff --git a/llvm/test/tools/llvm-objdump/ELF/Hexagon/branch-targets.yaml b/llvm/test/tools/llvm-objdump/ELF/Hexagon/branch-targets.yaml new file mode 100644 index 0000000000000..61ac32c658f6c --- /dev/null +++ b/llvm/test/tools/llvm-objdump/ELF/Hexagon/branch-targets.yaml @@ -0,0 +1,26 @@ +## Check that branch targets are printed within instruction packets for Hexagon + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_HEXAGON + Flags: [ EF_HEXAGON_MACH_V68, EF_HEXAGON_ISA_V68 ] +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x10 + Content: 00C09DA000C000781EC01E9600C09DA000C0005A1EC01E96 +... + +# RUN: yaml2obj %s | llvm-objdump -d - | FileCheck %s + +# CHECK: 00000000 <.text>: +# CHECK-NEXT: 0: 00 c0 9d a0 a09dc000 { allocframe(#0x0) } +# CHECK-NEXT: 4: 00 c0 00 78 7800c000 { r0 = #0x0 } +# CHECK-NEXT: 8: 1e c0 1e 96 961ec01e { dealloc_return } +# CHECK-NEXT: c: 00 c0 9d a0 a09dc000 { allocframe(#0x0) } +# CHECK-NEXT: 10: 00 c0 00 5a 5a00c000 { call 0x10 <.text+0x10> } +# CHECK-NEXT: 14: 1e c0 1e 96 961ec01e { dealloc_return } \ No newline at end of file diff --git a/llvm/tools/llvm-mc/Disassembler.cpp b/llvm/tools/llvm-mc/Disassembler.cpp index 607184e3b7247..86727931067a5 100644 --- a/llvm/tools/llvm-mc/Disassembler.cpp +++ b/llvm/tools/llvm-mc/Disassembler.cpp @@ -45,7 +45,11 @@ static bool PrintInsts(const MCDisassembler &DisAsm, const ByteArrayTy &Bytes, MCInst Inst; MCDisassembler::DecodeStatus S; - S = DisAsm.getInstruction(Inst, Size, Data.slice(Index), Index, nulls()); + if (STI.getTargetTriple().getArch() == Triple::hexagon) + S = DisAsm.getInstructionBundle(Inst, Size, Data.slice(Index), Index, + nulls()); + else + S = DisAsm.getInstruction(Inst, Size, Data.slice(Index), Index, nulls()); switch (S) { case MCDisassembler::Fail: SM.PrintMessage(SMLoc::getFromPointer(Bytes.second[Index]), diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp index c5967cd090eec..612a7a92ea378 100644 --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -693,6 +693,32 @@ class PrettyPrinter { } else OS << "\t"; } + + virtual std::string getInstructionSeparator() const { return "\n"; } + + virtual void emitPostInstructionInfo(formatted_raw_ostream &FOS, + const MCAsmInfo &MAI, + const MCSubtargetInfo &STI, + StringRef Comments, + LiveVariablePrinter &LVP) { + do { + if (!Comments.empty()) { + // Emit a line of comments. + StringRef Comment; + std::tie(Comment, Comments) = Comments.split('\n'); + // MAI.getCommentColumn() assumes that instructions are printed at the + // position of 8, while getInstStartColumn() returns the actual + // position. + unsigned CommentColumn = + MAI.getCommentColumn() - 8 + getInstStartColumn(STI); + FOS.PadToColumn(CommentColumn); + FOS << MAI.getCommentString() << ' ' << Comment; + } + LVP.printAfterInst(FOS); + FOS << getInstructionSeparator(); + } while (!Comments.empty()); + FOS.flush(); + } }; PrettyPrinter PrettyPrinterInst; @@ -714,6 +740,32 @@ class HexagonPrettyPrinter : public PrettyPrinter { } } } + + std::string getInstructionSeparator() const override { + SmallString<40> Separator; + raw_svector_ostream OS(Separator); + if (ShouldClosePacket) { + OS << " }"; + if (IsLoop0 || IsLoop1) + OS << " "; + if (IsLoop0) + OS << (IsLoop1 ? ":endloop01" : ":endloop0"); + else if (IsLoop1) + OS << ":endloop1"; + } + OS << '\n'; + return OS.str().str(); + } + + void emitPostInstructionInfo(formatted_raw_ostream &FOS, const MCAsmInfo &MAI, + const MCSubtargetInfo &STI, StringRef Comments, + LiveVariablePrinter &LVP) override { + + PrettyPrinter::emitPostInstructionInfo(FOS, MAI, STI, Comments, LVP); + if (ShouldClosePacket) + reset(); + } + void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef Bytes, object::SectionedAddress Address, formatted_raw_ostream &OS, StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, @@ -724,60 +776,64 @@ class HexagonPrettyPrinter : public PrettyPrinter { if (!MI) { printLead(Bytes, Address.Address, OS); OS << " "; + reset(); return; } - std::string Buffer; + + StringRef Preamble = IsStartOfBundle ? " { " : " "; + + if (SP && (PrintSource || PrintLines)) + SP->printSourceLine(OS, Address, ObjectFilename, LVP, ""); + printLead(Bytes, Address.Address, OS); + OS << Preamble; + std::string Buf; { - raw_string_ostream TempStream(Buffer); + raw_string_ostream TempStream(Buf); IP.printInst(MI, Address.Address, "", STI, TempStream); } - StringRef Contents(Buffer); - // Split off bundle attributes - auto PacketBundle = Contents.rsplit('\n'); - // Split off first instruction from the rest - auto HeadTail = PacketBundle.first.split('\n'); - auto Preamble = " { "; - auto Separator = ""; - - // Hexagon's packets require relocations to be inline rather than - // clustered at the end of the packet. - std::vector::const_iterator RelCur = Rels->begin(); - std::vector::const_iterator RelEnd = Rels->end(); - auto PrintReloc = [&]() -> void { - while ((RelCur != RelEnd) && (RelCur->getOffset() <= Address.Address)) { - if (RelCur->getOffset() == Address.Address) { - printRelocation(OS, ObjectFilename, *RelCur, Address.Address, false); - return; - } - ++RelCur; - } - }; + StringRef Contents(Buf); + + auto Duplex = Contents.split('\v'); + bool HasDuplex = !Duplex.second.empty(); + if (HasDuplex) { + OS << Duplex.first; + OS << "; "; + OS << Duplex.second; + } else { + OS << Duplex.first; + } - while (!HeadTail.first.empty()) { - OS << Separator; - Separator = "\n"; - if (SP && (PrintSource || PrintLines)) - SP->printSourceLine(OS, Address, ObjectFilename, LVP, ""); - printLead(Bytes, Address.Address, OS); - OS << Preamble; - Preamble = " "; - StringRef Inst; - auto Duplex = HeadTail.first.split('\v'); - if (!Duplex.second.empty()) { - OS << Duplex.first; - OS << "; "; - Inst = Duplex.second; - } + uint32_t Instruction = support::endian::read32le(Bytes.data()); + + uint32_t ParseMask = 0x0000c000; + uint32_t PacketEndMask = 0x0000c000; + uint32_t LoopEndMask = 0x00008000; + uint32_t ParseBits = Instruction & ParseMask; + + if (ParseBits == LoopEndMask) { + if (IsStartOfBundle) + IsLoop0 = true; else - Inst = HeadTail.first; - OS << Inst; - HeadTail = HeadTail.second.split('\n'); - if (HeadTail.first.empty()) - OS << " } " << PacketBundle.second; - PrintReloc(); - Bytes = Bytes.slice(4); - Address.Address += 4; + IsLoop1 = true; } + + IsStartOfBundle = false; + + if (ParseBits == PacketEndMask || HasDuplex) + ShouldClosePacket = true; + } + +private: + bool IsStartOfBundle = true; + bool IsLoop0 = false; + bool IsLoop1 = false; + bool ShouldClosePacket = false; + + void reset() { + IsStartOfBundle = true; + IsLoop0 = false; + IsLoop1 = false; + ShouldClosePacket = false; } }; HexagonPrettyPrinter HexagonPrettyPrinterInst; @@ -1610,29 +1666,6 @@ static StringRef getSegmentName(const MachOObjectFile *MachO, return ""; } -static void emitPostInstructionInfo(formatted_raw_ostream &FOS, - const MCAsmInfo &MAI, - const MCSubtargetInfo &STI, - StringRef Comments, - LiveVariablePrinter &LVP) { - do { - if (!Comments.empty()) { - // Emit a line of comments. - StringRef Comment; - std::tie(Comment, Comments) = Comments.split('\n'); - // MAI.getCommentColumn() assumes that instructions are printed at the - // position of 8, while getInstStartColumn() returns the actual position. - unsigned CommentColumn = - MAI.getCommentColumn() - 8 + getInstStartColumn(STI); - FOS.PadToColumn(CommentColumn); - FOS << MAI.getCommentString() << ' ' << Comment; - } - LVP.printAfterInst(FOS); - FOS << '\n'; - } while (!Comments.empty()); - FOS.flush(); -} - static void createFakeELFSections(ObjectFile &Obj) { assert(Obj.isELF()); if (auto *Elf32LEObj = dyn_cast(&Obj)) @@ -2526,15 +2559,15 @@ disassembleObject(ObjectFile &Obj, const ObjectFile &DbgObj, } assert(DT->Context->getAsmInfo()); - emitPostInstructionInfo(FOS, *DT->Context->getAsmInfo(), - *DT->SubtargetInfo, CommentStream.str(), LVP); + DT->Printer->emitPostInstructionInfo(FOS, *DT->Context->getAsmInfo(), + *DT->SubtargetInfo, + CommentStream.str(), LVP); Comments.clear(); if (BTF) printBTFRelocation(FOS, *BTF, {Index, Section.getIndex()}, LVP); - // Hexagon handles relocs in pretty printer - if (InlineRelocs && Obj.getArch() != Triple::hexagon) { + if (InlineRelocs) { while (findRel()) { // When --adjust-vma is used, update the address printed. printRelocation(FOS, Obj.getFileName(), *RelCur, From 6527156bdb57ca2f8209f615691c136b92c3f4e7 Mon Sep 17 00:00:00 2001 From: quic-areg Date: Thu, 26 Jun 2025 11:36:57 -0700 Subject: [PATCH 2/5] fix braces style --- llvm/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.cpp index 50b66772212a4..f83e06cd3d930 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.cpp @@ -38,8 +38,9 @@ void HexagonInstPrinter::printInst(const MCInst *MI, uint64_t Address, OS << '\v'; HasExtender = false; printInstruction(MI->getOperand(0).getInst(), Address, OS); - } else + } else { printInstruction(MI, Address, OS); + } HasExtender = HexagonMCInstrInfo::isImmext(*MI); if ((MI->getOpcode() & HexagonII::INST_PARSE_MASK) == HexagonII::INST_PARSE_PACKET_END) From d12711d18ae33ecdf306fe791d93bc89f454f451 Mon Sep 17 00:00:00 2001 From: quic-areg Date: Thu, 26 Jun 2025 11:38:21 -0700 Subject: [PATCH 3/5] add newline for test --- llvm/test/tools/llvm-objdump/ELF/Hexagon/branch-targets.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/test/tools/llvm-objdump/ELF/Hexagon/branch-targets.yaml b/llvm/test/tools/llvm-objdump/ELF/Hexagon/branch-targets.yaml index 61ac32c658f6c..7463ea8690639 100644 --- a/llvm/test/tools/llvm-objdump/ELF/Hexagon/branch-targets.yaml +++ b/llvm/test/tools/llvm-objdump/ELF/Hexagon/branch-targets.yaml @@ -23,4 +23,4 @@ Sections: # CHECK-NEXT: 8: 1e c0 1e 96 961ec01e { dealloc_return } # CHECK-NEXT: c: 00 c0 9d a0 a09dc000 { allocframe(#0x0) } # CHECK-NEXT: 10: 00 c0 00 5a 5a00c000 { call 0x10 <.text+0x10> } -# CHECK-NEXT: 14: 1e c0 1e 96 961ec01e { dealloc_return } \ No newline at end of file +# CHECK-NEXT: 14: 1e c0 1e 96 961ec01e { dealloc_return } From 09499d61b871fcd7a1893dd07a9e7dc7979f34ec Mon Sep 17 00:00:00 2001 From: quic-areg Date: Wed, 2 Jul 2025 14:14:32 -0700 Subject: [PATCH 4/5] - remove getInstructionSeparator - test improvements: - multi-insn packets - branch targets - endloops - inline relocations --- .../ELF/Hexagon/branch-targets.yaml | 26 ---------- .../ELF/Hexagon/hexagon-bundles.s | 47 +++++++++++++++++++ llvm/tools/llvm-objdump/llvm-objdump.cpp | 13 ++--- 3 files changed, 54 insertions(+), 32 deletions(-) delete mode 100644 llvm/test/tools/llvm-objdump/ELF/Hexagon/branch-targets.yaml create mode 100644 llvm/test/tools/llvm-objdump/ELF/Hexagon/hexagon-bundles.s diff --git a/llvm/test/tools/llvm-objdump/ELF/Hexagon/branch-targets.yaml b/llvm/test/tools/llvm-objdump/ELF/Hexagon/branch-targets.yaml deleted file mode 100644 index 7463ea8690639..0000000000000 --- a/llvm/test/tools/llvm-objdump/ELF/Hexagon/branch-targets.yaml +++ /dev/null @@ -1,26 +0,0 @@ -## Check that branch targets are printed within instruction packets for Hexagon - ---- !ELF -FileHeader: - Class: ELFCLASS32 - Data: ELFDATA2LSB - Type: ET_REL - Machine: EM_HEXAGON - Flags: [ EF_HEXAGON_MACH_V68, EF_HEXAGON_ISA_V68 ] -Sections: - - Name: .text - Type: SHT_PROGBITS - Flags: [ SHF_ALLOC, SHF_EXECINSTR ] - AddressAlign: 0x10 - Content: 00C09DA000C000781EC01E9600C09DA000C0005A1EC01E96 -... - -# RUN: yaml2obj %s | llvm-objdump -d - | FileCheck %s - -# CHECK: 00000000 <.text>: -# CHECK-NEXT: 0: 00 c0 9d a0 a09dc000 { allocframe(#0x0) } -# CHECK-NEXT: 4: 00 c0 00 78 7800c000 { r0 = #0x0 } -# CHECK-NEXT: 8: 1e c0 1e 96 961ec01e { dealloc_return } -# CHECK-NEXT: c: 00 c0 9d a0 a09dc000 { allocframe(#0x0) } -# CHECK-NEXT: 10: 00 c0 00 5a 5a00c000 { call 0x10 <.text+0x10> } -# CHECK-NEXT: 14: 1e c0 1e 96 961ec01e { dealloc_return } diff --git a/llvm/test/tools/llvm-objdump/ELF/Hexagon/hexagon-bundles.s b/llvm/test/tools/llvm-objdump/ELF/Hexagon/hexagon-bundles.s new file mode 100644 index 0000000000000..19b05999fe358 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/ELF/Hexagon/hexagon-bundles.s @@ -0,0 +1,47 @@ +/// Checks that various hexagon scenarios are handled correctly: +/// - branch targets +/// - endloops +/// - inline-relocs +/// - multi-insn bundles + +{ + r6 = sub(r1, r0) + r7 = and(r4, #0x0) + if (p1) jump:t target1 + if (p2) jump:nt target2 +} + +{ + r8 = r7 + r9 = add(r8, #0) + r10 = memw(r9) +} :endloop0 + +{ jump ##sym } + +target1: + nop + +target2: + nop + +// RUN: llvm-mc %s --triple=hexagon -filetype=obj | llvm-objdump -d -r - | FileCheck %s + +// CHECK: 00000000 <.text>: +// CHECK-NEXT: 0: 12 51 00 5c 5c005112 { if (p1) jump:t 0x24 +// CHECK-NEXT: 4: 14 42 00 5c 5c004214 if (p2) jump:nt 0x28 +// CHECK-NEXT: 8: 06 41 20 f3 f3204106 r6 = sub(r1,r0) +// CHECK-NEXT: c: 07 c0 04 76 7604c007 r7 = and(r4,#0x0) } +// CHECK-NEXT: 10: 08 80 67 70 70678008 { r8 = r7 +// CHECK-NEXT: 14: 09 40 08 b0 b0084009 r9 = add(r8,#0x0) +// CHECK-NEXT: 18: 0a c0 89 91 9189c00a r10 = memw(r9+#0x0) } :endloop0 +// CHECK-NEXT: 1c: 00 40 00 00 00004000 { immext(#0x0) +// CHECK-NEXT: 0000001c: R_HEX_B32_PCREL_X sym +// CHECK-NEXT: 20: 00 c0 00 58 5800c000 jump 0x1c <.text+0x1c> } +// CHECK-NEXT: 00000020: R_HEX_B22_PCREL_X sym+0x4 +// CHECK-EMPTY: +// CHECK-NEXT: 00000024 : +// CHECK-NEXT: 24: 00 c0 00 7f 7f00c000 { nop } +// CHECK-NEXT: +// CHECK-NEXT: 00000028 : +// CHECK-NEXT: 28: 00 c0 00 7f 7f00c000 { nop } diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp index 612a7a92ea378..74eb9033c8e2c 100644 --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -694,8 +694,6 @@ class PrettyPrinter { OS << "\t"; } - virtual std::string getInstructionSeparator() const { return "\n"; } - virtual void emitPostInstructionInfo(formatted_raw_ostream &FOS, const MCAsmInfo &MAI, const MCSubtargetInfo &STI, @@ -715,7 +713,7 @@ class PrettyPrinter { FOS << MAI.getCommentString() << ' ' << Comment; } LVP.printAfterInst(FOS); - FOS << getInstructionSeparator(); + FOS << "\n"; } while (!Comments.empty()); FOS.flush(); } @@ -741,7 +739,7 @@ class HexagonPrettyPrinter : public PrettyPrinter { } } - std::string getInstructionSeparator() const override { + std::string getInstructionSeparator() const { SmallString<40> Separator; raw_svector_ostream OS(Separator); if (ShouldClosePacket) { @@ -760,8 +758,11 @@ class HexagonPrettyPrinter : public PrettyPrinter { void emitPostInstructionInfo(formatted_raw_ostream &FOS, const MCAsmInfo &MAI, const MCSubtargetInfo &STI, StringRef Comments, LiveVariablePrinter &LVP) override { - - PrettyPrinter::emitPostInstructionInfo(FOS, MAI, STI, Comments, LVP); + // Hexagon does not write anything to the comment stream, so we can just + // print the separator. + LVP.printAfterInst(FOS); + FOS << getInstructionSeparator(); + FOS.flush(); if (ShouldClosePacket) reset(); } From c5953e6543ea194fc0f25f4fd806980f043a8362 Mon Sep 17 00:00:00 2001 From: quic-areg Date: Thu, 3 Jul 2025 12:16:01 -0700 Subject: [PATCH 5/5] fix empty check-next --- llvm/test/tools/llvm-objdump/ELF/Hexagon/hexagon-bundles.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/test/tools/llvm-objdump/ELF/Hexagon/hexagon-bundles.s b/llvm/test/tools/llvm-objdump/ELF/Hexagon/hexagon-bundles.s index 19b05999fe358..6a4927e4af2a4 100644 --- a/llvm/test/tools/llvm-objdump/ELF/Hexagon/hexagon-bundles.s +++ b/llvm/test/tools/llvm-objdump/ELF/Hexagon/hexagon-bundles.s @@ -42,6 +42,6 @@ target2: // CHECK-EMPTY: // CHECK-NEXT: 00000024 : // CHECK-NEXT: 24: 00 c0 00 7f 7f00c000 { nop } -// CHECK-NEXT: +// CHECK-EMPTY: // CHECK-NEXT: 00000028 : // CHECK-NEXT: 28: 00 c0 00 7f 7f00c000 { nop }