[Hexagon][llvm-objdump] Improve disassembly of Hexagon bundles (#145807)
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 <branch> } :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.
This commit is contained in:
parent
32f0fc597f
commit
ac7ceb3dab
@ -30,31 +30,31 @@
|
||||
# DIS: <_start>:
|
||||
## Direct call
|
||||
## Call foo directly
|
||||
# DIS-NEXT: { call 0x2003c }
|
||||
# DIS-NEXT: { call 0x2003c <foo> }
|
||||
## Call bar via plt
|
||||
# DIS-NEXT: { call 0x20060 }
|
||||
# DIS-NEXT: { call 0x20060 <bar@plt> }
|
||||
## Call weak via plt
|
||||
# DIS-NEXT: { call 0x20070 }
|
||||
# DIS-NEXT: { call 0x20070 <weak@plt> }
|
||||
# DIS-NEXT: { immext(#0)
|
||||
|
||||
## Call foo directly
|
||||
# DIS-NEXT: if (p0) jump:nt 0x2003c }
|
||||
# DIS-NEXT: if (p0) jump:nt 0x2003c <foo> }
|
||||
# DIS-NEXT: { immext(#64)
|
||||
## Call bar via plt
|
||||
# DIS-NEXT: if (p0) jump:nt 0x20060 }
|
||||
# DIS-NEXT: if (p0) jump:nt 0x20060 <bar@plt> }
|
||||
# DIS-NEXT: { immext(#64)
|
||||
## Call weak via plt
|
||||
# DIS-NEXT: if (p0) jump:nt 0x20070 }
|
||||
# DIS-NEXT: if (p0) jump:nt 0x20070 <weak@plt> }
|
||||
# DIS-NEXT: { immext(#0)
|
||||
|
||||
## Call foo directly
|
||||
# DIS-NEXT: r0 = #0 ; jump 0x2003c }
|
||||
# DIS-NEXT: r0 = #0 ; jump 0x2003c <foo> }
|
||||
# DIS-NEXT: { immext(#0)
|
||||
## Call bar via plt
|
||||
# DIS-NEXT: r0 = #0 ; jump 0x20060 }
|
||||
# DIS-NEXT: r0 = #0 ; jump 0x20060 <bar@plt> }
|
||||
# DIS-NEXT: { immext(#0)
|
||||
## Call weak via plt
|
||||
# DIS-NEXT: r0 = #0 ; jump 0x20070 }
|
||||
# DIS-NEXT: r0 = #0 ; jump 0x20070 <weak@plt> }
|
||||
|
||||
# DIS: <foo>:
|
||||
# DIS-NEXT: 2003c:
|
||||
|
@ -88,7 +88,7 @@ pvar:
|
||||
# PLT-NEXT: jumpr r28 }
|
||||
|
||||
# TEXT: bc 00 01 00 000100bc
|
||||
# TEXT: { call 0x10300 }
|
||||
# TEXT: { call 0x10300 <bar@plt> }
|
||||
# TEXT: if (p0) jump:nt 0x10300
|
||||
# TEXT: r0 = #0 ; jump 0x10300
|
||||
# TEXT: r0 = add(r1,##-65548)
|
||||
|
@ -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 <x@plt> }
|
||||
.endif
|
||||
|
||||
# CHECK_GDPLT: 10220: { immext(#0x20040)
|
||||
|
@ -136,6 +136,18 @@ public:
|
||||
ArrayRef<uint8_t> 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<uint8_t> 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.
|
||||
|
@ -43,12 +43,12 @@ namespace {
|
||||
class HexagonDisassembler : public MCDisassembler {
|
||||
public:
|
||||
std::unique_ptr<MCInstrInfo const> const MCII;
|
||||
std::unique_ptr<MCInst *> CurrentBundle;
|
||||
mutable std::unique_ptr<MCInst> 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 @@ public:
|
||||
DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
|
||||
ArrayRef<uint8_t> Bytes, uint64_t Address,
|
||||
raw_ostream &CStream) const override;
|
||||
|
||||
DecodeStatus getInstructionBundle(MCInst &Instr, uint64_t &Size,
|
||||
ArrayRef<uint8_t> Bytes, uint64_t Address,
|
||||
raw_ostream &CStream) const override;
|
||||
|
||||
void remapInstruction(MCInst &Instr) const;
|
||||
|
||||
private:
|
||||
bool makeBundle(ArrayRef<uint8_t> 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);
|
||||
}
|
||||
|
||||
bool HexagonDisassembler::makeBundle(ArrayRef<uint8_t> Bytes, uint64_t Address,
|
||||
uint64_t &BytesToSkip,
|
||||
raw_ostream &CS) const {
|
||||
bool Complete = false;
|
||||
DecodeStatus Result = DecodeStatus::Success;
|
||||
|
||||
CurrentBundle.reset(new MCInst);
|
||||
CurrentBundle->setOpcode(Hexagon::BUNDLE);
|
||||
CurrentBundle->addOperand(MCOperand::createImm(0));
|
||||
while (Result == Success && !Complete) {
|
||||
if (Bytes.size() < HEXAGON_INSTR_SIZE)
|
||||
return false;
|
||||
MCInst *Inst = getContext().createMCInst();
|
||||
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 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_, *CurrentBundle,
|
||||
*getContext().getRegisterInfo(), false);
|
||||
if (!Checker.check())
|
||||
return false;
|
||||
remapInstruction(*CurrentBundle);
|
||||
return true;
|
||||
}
|
||||
|
||||
DecodeStatus HexagonDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
|
||||
ArrayRef<uint8_t> Bytes,
|
||||
uint64_t Address,
|
||||
raw_ostream &CS) const {
|
||||
CommentStream = &CS;
|
||||
|
||||
DecodeStatus Result = DecodeStatus::Success;
|
||||
bool Complete = false;
|
||||
Size = 0;
|
||||
uint64_t BytesToSkip = 0;
|
||||
|
||||
*CurrentBundle = &MI;
|
||||
MI.setOpcode(Hexagon::BUNDLE);
|
||||
MI.addOperand(MCOperand::createImm(0));
|
||||
while (Result == Success && !Complete) {
|
||||
if (Bytes.size() < HEXAGON_INSTR_SIZE)
|
||||
if (!CurrentBundle) {
|
||||
if (!makeBundle(Bytes, Address, BytesToSkip, CS)) {
|
||||
Size = BytesToSkip;
|
||||
resetBundle();
|
||||
return MCDisassembler::Fail;
|
||||
MCInst *Inst = getContext().createMCInst();
|
||||
Result = getSingleInstruction(*Inst, MI, Bytes, Address, CS, Complete);
|
||||
MI.addOperand(MCOperand::createInst(Inst));
|
||||
Size += HEXAGON_INSTR_SIZE;
|
||||
Bytes = Bytes.slice(HEXAGON_INSTR_SIZE);
|
||||
}
|
||||
CurrentInstruction = (CurrentBundle->begin() + 1);
|
||||
}
|
||||
if (Result == MCDisassembler::Fail)
|
||||
return Result;
|
||||
if (Size > HEXAGON_MAX_PACKET_SIZE)
|
||||
return MCDisassembler::Fail;
|
||||
|
||||
const auto ArchSTI = Hexagon_MC::getArchSubtarget(&STI);
|
||||
const auto STI_ = (ArchSTI != nullptr) ? *ArchSTI : STI;
|
||||
HexagonMCChecker Checker(getContext(), *MCII, STI_, MI,
|
||||
*getContext().getRegisterInfo(), false);
|
||||
if (!Checker.check())
|
||||
return MCDisassembler::Fail;
|
||||
remapInstruction(MI);
|
||||
MI = *(CurrentInstruction->getInst());
|
||||
Size = HEXAGON_INSTR_SIZE;
|
||||
if (++CurrentInstruction == CurrentBundle->end())
|
||||
resetBundle();
|
||||
return MCDisassembler::Success;
|
||||
}
|
||||
|
||||
DecodeStatus HexagonDisassembler::getInstructionBundle(MCInst &MI,
|
||||
uint64_t &Size,
|
||||
ArrayRef<uint8_t> 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<MCInst &>(*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)
|
||||
|
@ -33,30 +33,18 @@ 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,
|
||||
|
@ -252,8 +252,21 @@ public:
|
||||
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 @@ public:
|
||||
}
|
||||
|
||||
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(); }
|
||||
|
@ -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> }
|
||||
|
||||
|
47
llvm/test/tools/llvm-objdump/ELF/Hexagon/hexagon-bundles.s
Normal file
47
llvm/test/tools/llvm-objdump/ELF/Hexagon/hexagon-bundles.s
Normal file
@ -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 <target1>
|
||||
// CHECK-NEXT: 4: 14 42 00 5c 5c004214 if (p2) jump:nt 0x28 <target2>
|
||||
// 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 <target1>:
|
||||
// CHECK-NEXT: 24: 00 c0 00 7f 7f00c000 { nop }
|
||||
// CHECK-EMPTY:
|
||||
// CHECK-NEXT: 00000028 <target2>:
|
||||
// CHECK-NEXT: 28: 00 c0 00 7f 7f00c000 { nop }
|
@ -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]),
|
||||
|
@ -693,6 +693,30 @@ public:
|
||||
} else
|
||||
OS << "\t<unknown>";
|
||||
}
|
||||
|
||||
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 << "\n";
|
||||
} while (!Comments.empty());
|
||||
FOS.flush();
|
||||
}
|
||||
};
|
||||
PrettyPrinter PrettyPrinterInst;
|
||||
|
||||
@ -714,6 +738,35 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string getInstructionSeparator() const {
|
||||
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 {
|
||||
// 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();
|
||||
}
|
||||
|
||||
void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
|
||||
object::SectionedAddress Address, formatted_raw_ostream &OS,
|
||||
StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
|
||||
@ -724,60 +777,64 @@ public:
|
||||
if (!MI) {
|
||||
printLead(Bytes, Address.Address, OS);
|
||||
OS << " <unknown>";
|
||||
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 = "";
|
||||
StringRef Contents(Buf);
|
||||
|
||||
// Hexagon's packets require relocations to be inline rather than
|
||||
// clustered at the end of the packet.
|
||||
std::vector<RelocationRef>::const_iterator RelCur = Rels->begin();
|
||||
std::vector<RelocationRef>::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;
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
auto Duplex = Contents.split('\v');
|
||||
bool HasDuplex = !Duplex.second.empty();
|
||||
if (HasDuplex) {
|
||||
OS << Duplex.first;
|
||||
OS << "; ";
|
||||
OS << Duplex.second;
|
||||
} else {
|
||||
OS << Duplex.first;
|
||||
}
|
||||
|
||||
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
|
||||
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 +1667,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<ELF32LEObjectFile>(&Obj))
|
||||
@ -2526,15 +2560,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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user