Skip to content

[Hexagon][llvm-objdump] Improve disassembly of Hexagon bundles #145807

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions lld/test/ELF/hexagon-plt.s
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion lld/test/ELF/hexagon-shared.s
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions lld/test/ELF/hexagon-tls-gd-xform.s
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
12 changes: 12 additions & 0 deletions llvm/include/llvm/MC/MCDisassembler/MCDisassembler.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,18 @@ class LLVM_ABI MCDisassembler {
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.
Expand Down
109 changes: 85 additions & 24 deletions llvm/lib/Target/Hexagon/Disassembler/HexagonDisassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -57,7 +57,23 @@ class HexagonDisassembler : public MCDisassembler {
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,
Expand Down Expand Up @@ -171,43 +187,88 @@ LLVMInitializeHexagonDisassembler() {
createHexagonDisassembler);
}

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 HexagonDisassembler::makeBundle(ArrayRef<uint8_t> 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;
Comment on lines +203 to +212
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BytesToSkip += HEXAGON_INSTR_SIZE; - is this right? Are you testing duplex instructions here too? If so that might not be the right constant to use here.

if (Bytes.size() < HEXAGON_INSTR_SIZE) is probably safe though.

Aside: we should probably define independent HEXAGON_MAX_PACKET_SIZE_BYTES and HEXAGON_MAX_PACKET_SIZE_INSTS to clear this up.


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<uint8_t> 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<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());
Expand Down Expand Up @@ -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)
Expand Down
34 changes: 11 additions & 23 deletions llvm/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
19 changes: 16 additions & 3 deletions llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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(); }
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/MC/Hexagon/two_ext.s
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 47 additions & 0 deletions llvm/test/tools/llvm-objdump/ELF/Hexagon/hexagon-bundles.s
Original file line number Diff line number Diff line change
@@ -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 }
6 changes: 5 additions & 1 deletion llvm/tools/llvm-mc/Disassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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]),
Expand Down
Loading