[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>:
|
# DIS: <_start>:
|
||||||
## Direct call
|
## Direct call
|
||||||
## Call foo directly
|
## Call foo directly
|
||||||
# DIS-NEXT: { call 0x2003c }
|
# DIS-NEXT: { call 0x2003c <foo> }
|
||||||
## Call bar via plt
|
## Call bar via plt
|
||||||
# DIS-NEXT: { call 0x20060 }
|
# DIS-NEXT: { call 0x20060 <bar@plt> }
|
||||||
## Call weak via plt
|
## Call weak via plt
|
||||||
# DIS-NEXT: { call 0x20070 }
|
# DIS-NEXT: { call 0x20070 <weak@plt> }
|
||||||
# DIS-NEXT: { immext(#0)
|
# DIS-NEXT: { immext(#0)
|
||||||
|
|
||||||
## Call foo directly
|
## Call foo directly
|
||||||
# DIS-NEXT: if (p0) jump:nt 0x2003c }
|
# DIS-NEXT: if (p0) jump:nt 0x2003c <foo> }
|
||||||
# DIS-NEXT: { immext(#64)
|
# DIS-NEXT: { immext(#64)
|
||||||
## Call bar via plt
|
## Call bar via plt
|
||||||
# DIS-NEXT: if (p0) jump:nt 0x20060 }
|
# DIS-NEXT: if (p0) jump:nt 0x20060 <bar@plt> }
|
||||||
# DIS-NEXT: { immext(#64)
|
# DIS-NEXT: { immext(#64)
|
||||||
## Call weak via plt
|
## Call weak via plt
|
||||||
# DIS-NEXT: if (p0) jump:nt 0x20070 }
|
# DIS-NEXT: if (p0) jump:nt 0x20070 <weak@plt> }
|
||||||
# DIS-NEXT: { immext(#0)
|
# DIS-NEXT: { immext(#0)
|
||||||
|
|
||||||
## Call foo directly
|
## Call foo directly
|
||||||
# DIS-NEXT: r0 = #0 ; jump 0x2003c }
|
# DIS-NEXT: r0 = #0 ; jump 0x2003c <foo> }
|
||||||
# DIS-NEXT: { immext(#0)
|
# DIS-NEXT: { immext(#0)
|
||||||
## Call bar via plt
|
## Call bar via plt
|
||||||
# DIS-NEXT: r0 = #0 ; jump 0x20060 }
|
# DIS-NEXT: r0 = #0 ; jump 0x20060 <bar@plt> }
|
||||||
# DIS-NEXT: { immext(#0)
|
# DIS-NEXT: { immext(#0)
|
||||||
## Call weak via plt
|
## Call weak via plt
|
||||||
# DIS-NEXT: r0 = #0 ; jump 0x20070 }
|
# DIS-NEXT: r0 = #0 ; jump 0x20070 <weak@plt> }
|
||||||
|
|
||||||
# DIS: <foo>:
|
# DIS: <foo>:
|
||||||
# DIS-NEXT: 2003c:
|
# DIS-NEXT: 2003c:
|
||||||
|
@ -88,7 +88,7 @@ pvar:
|
|||||||
# PLT-NEXT: jumpr r28 }
|
# PLT-NEXT: jumpr r28 }
|
||||||
|
|
||||||
# TEXT: bc 00 01 00 000100bc
|
# TEXT: bc 00 01 00 000100bc
|
||||||
# TEXT: { call 0x10300 }
|
# TEXT: { call 0x10300 <bar@plt> }
|
||||||
# TEXT: if (p0) jump:nt 0x10300
|
# TEXT: if (p0) jump:nt 0x10300
|
||||||
# TEXT: r0 = #0 ; jump 0x10300
|
# TEXT: r0 = #0 ; jump 0x10300
|
||||||
# TEXT: r0 = add(r1,##-65548)
|
# TEXT: r0 = add(r1,##-65548)
|
||||||
|
@ -18,10 +18,10 @@
|
|||||||
_start:
|
_start:
|
||||||
.ifdef GDPLT
|
.ifdef GDPLT
|
||||||
call x@gdplt
|
call x@gdplt
|
||||||
# CHECK_GDPLT: 101ec: { call 0x10220 }
|
# CHECK_GDPLT: 101ec: { call 0x10220 <__tls_get_addr@plt> }
|
||||||
.else
|
.else
|
||||||
call x
|
call x
|
||||||
# CHECK: 101b8: { call 0x101e0 }
|
# CHECK: 101b8: { call 0x101e0 <x@plt> }
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
# CHECK_GDPLT: 10220: { immext(#0x20040)
|
# CHECK_GDPLT: 10220: { immext(#0x20040)
|
||||||
|
@ -136,6 +136,18 @@ public:
|
|||||||
ArrayRef<uint8_t> Bytes, uint64_t Address,
|
ArrayRef<uint8_t> Bytes, uint64_t Address,
|
||||||
raw_ostream &CStream) const = 0;
|
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
|
/// Used to perform separate target specific disassembly for a particular
|
||||||
/// symbol. May parse any prelude that precedes instructions after the
|
/// symbol. May parse any prelude that precedes instructions after the
|
||||||
/// start of a symbol, or the entire symbol.
|
/// start of a symbol, or the entire symbol.
|
||||||
|
@ -43,12 +43,12 @@ namespace {
|
|||||||
class HexagonDisassembler : public MCDisassembler {
|
class HexagonDisassembler : public MCDisassembler {
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<MCInstrInfo const> const MCII;
|
std::unique_ptr<MCInstrInfo const> const MCII;
|
||||||
std::unique_ptr<MCInst *> CurrentBundle;
|
mutable std::unique_ptr<MCInst> CurrentBundle;
|
||||||
mutable MCInst const *CurrentExtender;
|
mutable MCInst const *CurrentExtender;
|
||||||
|
|
||||||
HexagonDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx,
|
HexagonDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx,
|
||||||
MCInstrInfo const *MCII)
|
MCInstrInfo const *MCII)
|
||||||
: MCDisassembler(STI, Ctx), MCII(MCII), CurrentBundle(new MCInst *),
|
: MCDisassembler(STI, Ctx), MCII(MCII), CurrentBundle(nullptr),
|
||||||
CurrentExtender(nullptr) {}
|
CurrentExtender(nullptr) {}
|
||||||
|
|
||||||
DecodeStatus getSingleInstruction(MCInst &Instr, MCInst &MCB,
|
DecodeStatus getSingleInstruction(MCInst &Instr, MCInst &MCB,
|
||||||
@ -57,7 +57,23 @@ public:
|
|||||||
DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
|
DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
|
||||||
ArrayRef<uint8_t> Bytes, uint64_t Address,
|
ArrayRef<uint8_t> Bytes, uint64_t Address,
|
||||||
raw_ostream &CStream) const override;
|
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;
|
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,
|
static uint64_t fullValue(HexagonDisassembler const &Disassembler, MCInst &MI,
|
||||||
@ -171,43 +187,88 @@ LLVMInitializeHexagonDisassembler() {
|
|||||||
createHexagonDisassembler);
|
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,
|
DecodeStatus HexagonDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
|
||||||
ArrayRef<uint8_t> Bytes,
|
ArrayRef<uint8_t> Bytes,
|
||||||
uint64_t Address,
|
uint64_t Address,
|
||||||
raw_ostream &CS) const {
|
raw_ostream &CS) const {
|
||||||
CommentStream = &CS;
|
CommentStream = &CS;
|
||||||
|
|
||||||
DecodeStatus Result = DecodeStatus::Success;
|
|
||||||
bool Complete = false;
|
|
||||||
Size = 0;
|
Size = 0;
|
||||||
|
uint64_t BytesToSkip = 0;
|
||||||
|
|
||||||
*CurrentBundle = &MI;
|
if (!CurrentBundle) {
|
||||||
MI.setOpcode(Hexagon::BUNDLE);
|
if (!makeBundle(Bytes, Address, BytesToSkip, CS)) {
|
||||||
MI.addOperand(MCOperand::createImm(0));
|
Size = BytesToSkip;
|
||||||
while (Result == Success && !Complete) {
|
resetBundle();
|
||||||
if (Bytes.size() < HEXAGON_INSTR_SIZE)
|
|
||||||
return MCDisassembler::Fail;
|
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);
|
|
||||||
}
|
}
|
||||||
if (Result == MCDisassembler::Fail)
|
CurrentInstruction = (CurrentBundle->begin() + 1);
|
||||||
return Result;
|
}
|
||||||
if (Size > HEXAGON_MAX_PACKET_SIZE)
|
|
||||||
return MCDisassembler::Fail;
|
|
||||||
|
|
||||||
const auto ArchSTI = Hexagon_MC::getArchSubtarget(&STI);
|
MI = *(CurrentInstruction->getInst());
|
||||||
const auto STI_ = (ArchSTI != nullptr) ? *ArchSTI : STI;
|
Size = HEXAGON_INSTR_SIZE;
|
||||||
HexagonMCChecker Checker(getContext(), *MCII, STI_, MI,
|
if (++CurrentInstruction == CurrentBundle->end())
|
||||||
*getContext().getRegisterInfo(), false);
|
resetBundle();
|
||||||
if (!Checker.check())
|
|
||||||
return MCDisassembler::Fail;
|
|
||||||
remapInstruction(MI);
|
|
||||||
return MCDisassembler::Success;
|
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 {
|
void HexagonDisassembler::remapInstruction(MCInst &Instr) const {
|
||||||
for (auto I: HexagonMCInstrInfo::bundleInstructions(Instr)) {
|
for (auto I: HexagonMCInstrInfo::bundleInstructions(Instr)) {
|
||||||
auto &MI = const_cast<MCInst &>(*I.getInst());
|
auto &MI = const_cast<MCInst &>(*I.getInst());
|
||||||
@ -482,7 +543,7 @@ DecodeStatus HexagonDisassembler::getSingleInstruction(MCInst &MI, MCInst &MCB,
|
|||||||
unsigned Offset = 1;
|
unsigned Offset = 1;
|
||||||
bool Vector = HexagonMCInstrInfo::isVector(*MCII, MI);
|
bool Vector = HexagonMCInstrInfo::isVector(*MCII, MI);
|
||||||
bool PrevVector = false;
|
bool PrevVector = false;
|
||||||
auto Instructions = HexagonMCInstrInfo::bundleInstructions(**CurrentBundle);
|
auto Instructions = HexagonMCInstrInfo::bundleInstructions(*CurrentBundle);
|
||||||
auto i = Instructions.end() - 1;
|
auto i = Instructions.end() - 1;
|
||||||
for (auto n = Instructions.begin() - 1;; --i, ++Offset) {
|
for (auto n = Instructions.begin() - 1;; --i, ++Offset) {
|
||||||
if (i == n)
|
if (i == n)
|
||||||
|
@ -33,30 +33,18 @@ void HexagonInstPrinter::printRegName(raw_ostream &O, MCRegister Reg) {
|
|||||||
void HexagonInstPrinter::printInst(const MCInst *MI, uint64_t Address,
|
void HexagonInstPrinter::printInst(const MCInst *MI, uint64_t Address,
|
||||||
StringRef Annot, const MCSubtargetInfo &STI,
|
StringRef Annot, const MCSubtargetInfo &STI,
|
||||||
raw_ostream &OS) {
|
raw_ostream &OS) {
|
||||||
assert(HexagonMCInstrInfo::isBundle(*MI));
|
if (HexagonMCInstrInfo::isDuplex(MII, *MI)) {
|
||||||
assert(HexagonMCInstrInfo::bundleSize(*MI) <= HEXAGON_PACKET_SIZE);
|
printInstruction(MI->getOperand(1).getInst(), Address, OS);
|
||||||
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';
|
OS << '\v';
|
||||||
HasExtender = false;
|
HasExtender = false;
|
||||||
printInstruction(MCI.getOperand(0).getInst(), Address, OS);
|
printInstruction(MI->getOperand(0).getInst(), Address, OS);
|
||||||
} else
|
} else {
|
||||||
printInstruction(&MCI, Address, OS);
|
printInstruction(MI, 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";
|
|
||||||
}
|
}
|
||||||
|
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,
|
void HexagonInstPrinter::printOperand(MCInst const *MI, unsigned OpNo,
|
||||||
|
@ -252,8 +252,21 @@ public:
|
|||||||
std::string Buffer;
|
std::string Buffer;
|
||||||
{
|
{
|
||||||
raw_string_ostream TempStream(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);
|
StringRef Contents(Buffer);
|
||||||
auto PacketBundle = Contents.rsplit('\n');
|
auto PacketBundle = Contents.rsplit('\n');
|
||||||
auto HeadTail = PacketBundle.first.split('\n');
|
auto HeadTail = PacketBundle.first.split('\n');
|
||||||
@ -275,9 +288,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (HexagonMCInstrInfo::isMemReorderDisabled(Inst))
|
if (HexagonMCInstrInfo::isMemReorderDisabled(Inst))
|
||||||
OS << "\n\t} :mem_noshuf" << PacketBundle.second;
|
OS << "\n\t} :mem_noshuf" << LoopString;
|
||||||
else
|
else
|
||||||
OS << "\t}" << PacketBundle.second;
|
OS << "\t}" << LoopString;
|
||||||
}
|
}
|
||||||
|
|
||||||
void finish() override { finishAttributeSection(); }
|
void finish() override { finishAttributeSection(); }
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
if (!p1) call foo_b
|
if (!p1) call foo_b
|
||||||
}
|
}
|
||||||
# CHECK: 00004000 { immext(#0)
|
# CHECK: 00004000 { immext(#0)
|
||||||
# CHECK: 5d004100 if (p1) call 0x0
|
# CHECK: 5d004100 if (p1) call 0x0 <.text>
|
||||||
# CHECK: 00004000 immext(#0)
|
# 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,6 +45,10 @@ static bool PrintInsts(const MCDisassembler &DisAsm, const ByteArrayTy &Bytes,
|
|||||||
MCInst Inst;
|
MCInst Inst;
|
||||||
|
|
||||||
MCDisassembler::DecodeStatus S;
|
MCDisassembler::DecodeStatus S;
|
||||||
|
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());
|
S = DisAsm.getInstruction(Inst, Size, Data.slice(Index), Index, nulls());
|
||||||
switch (S) {
|
switch (S) {
|
||||||
case MCDisassembler::Fail:
|
case MCDisassembler::Fail:
|
||||||
|
@ -693,6 +693,30 @@ public:
|
|||||||
} else
|
} else
|
||||||
OS << "\t<unknown>";
|
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;
|
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,
|
void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
|
||||||
object::SectionedAddress Address, formatted_raw_ostream &OS,
|
object::SectionedAddress Address, formatted_raw_ostream &OS,
|
||||||
StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
|
StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
|
||||||
@ -724,60 +777,64 @@ public:
|
|||||||
if (!MI) {
|
if (!MI) {
|
||||||
printLead(Bytes, Address.Address, OS);
|
printLead(Bytes, Address.Address, OS);
|
||||||
OS << " <unknown>";
|
OS << " <unknown>";
|
||||||
|
reset();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::string Buffer;
|
|
||||||
{
|
|
||||||
raw_string_ostream TempStream(Buffer);
|
|
||||||
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
|
StringRef Preamble = IsStartOfBundle ? " { " : " ";
|
||||||
// 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))
|
if (SP && (PrintSource || PrintLines))
|
||||||
SP->printSourceLine(OS, Address, ObjectFilename, LVP, "");
|
SP->printSourceLine(OS, Address, ObjectFilename, LVP, "");
|
||||||
printLead(Bytes, Address.Address, OS);
|
printLead(Bytes, Address.Address, OS);
|
||||||
OS << Preamble;
|
OS << Preamble;
|
||||||
Preamble = " ";
|
std::string Buf;
|
||||||
StringRef Inst;
|
{
|
||||||
auto Duplex = HeadTail.first.split('\v');
|
raw_string_ostream TempStream(Buf);
|
||||||
if (!Duplex.second.empty()) {
|
IP.printInst(MI, Address.Address, "", STI, TempStream);
|
||||||
|
}
|
||||||
|
StringRef Contents(Buf);
|
||||||
|
|
||||||
|
auto Duplex = Contents.split('\v');
|
||||||
|
bool HasDuplex = !Duplex.second.empty();
|
||||||
|
if (HasDuplex) {
|
||||||
OS << Duplex.first;
|
OS << Duplex.first;
|
||||||
OS << "; ";
|
OS << "; ";
|
||||||
Inst = Duplex.second;
|
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
|
else
|
||||||
Inst = HeadTail.first;
|
IsLoop1 = true;
|
||||||
OS << Inst;
|
|
||||||
HeadTail = HeadTail.second.split('\n');
|
|
||||||
if (HeadTail.first.empty())
|
|
||||||
OS << " } " << PacketBundle.second;
|
|
||||||
PrintReloc();
|
|
||||||
Bytes = Bytes.slice(4);
|
|
||||||
Address.Address += 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
HexagonPrettyPrinter HexagonPrettyPrinterInst;
|
||||||
@ -1610,29 +1667,6 @@ static StringRef getSegmentName(const MachOObjectFile *MachO,
|
|||||||
return "";
|
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) {
|
static void createFakeELFSections(ObjectFile &Obj) {
|
||||||
assert(Obj.isELF());
|
assert(Obj.isELF());
|
||||||
if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(&Obj))
|
if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(&Obj))
|
||||||
@ -2526,15 +2560,15 @@ disassembleObject(ObjectFile &Obj, const ObjectFile &DbgObj,
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(DT->Context->getAsmInfo());
|
assert(DT->Context->getAsmInfo());
|
||||||
emitPostInstructionInfo(FOS, *DT->Context->getAsmInfo(),
|
DT->Printer->emitPostInstructionInfo(FOS, *DT->Context->getAsmInfo(),
|
||||||
*DT->SubtargetInfo, CommentStream.str(), LVP);
|
*DT->SubtargetInfo,
|
||||||
|
CommentStream.str(), LVP);
|
||||||
Comments.clear();
|
Comments.clear();
|
||||||
|
|
||||||
if (BTF)
|
if (BTF)
|
||||||
printBTFRelocation(FOS, *BTF, {Index, Section.getIndex()}, LVP);
|
printBTFRelocation(FOS, *BTF, {Index, Section.getIndex()}, LVP);
|
||||||
|
|
||||||
// Hexagon handles relocs in pretty printer
|
if (InlineRelocs) {
|
||||||
if (InlineRelocs && Obj.getArch() != Triple::hexagon) {
|
|
||||||
while (findRel()) {
|
while (findRel()) {
|
||||||
// When --adjust-vma is used, update the address printed.
|
// When --adjust-vma is used, update the address printed.
|
||||||
printRelocation(FOS, Obj.getFileName(), *RelCur,
|
printRelocation(FOS, Obj.getFileName(), *RelCur,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user