Skip to content

Commit 42490d3

Browse files
bors[bot]vext01
andauthored
50: Extend the .llvm_bb_addr_map section with PT decoding hints. r=ltratt a=vext01 Co-authored-by: Edd Barrett <[email protected]>
2 parents 9ea6491 + 3fad3f6 commit 42490d3

File tree

3 files changed

+151
-3
lines changed

3 files changed

+151
-3
lines changed

llvm/include/llvm/CodeGen/AsmPrinter.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,11 @@ class AsmPrinter : public MachineFunctionPass {
233233
/// The last `.llvm_bb_addr_map` section fragment that we handled (if any).
234234
MCSection *YkLastBBAddrMapSection = nullptr;
235235

236+
/// Symbols marking the call instructions of each block. Used for the Yk JIT.
237+
std::map<const MachineBasicBlock *,
238+
SmallVector<std::tuple<MCSymbol *, MCSymbol *>>>
239+
YkCallMarkerSyms;
240+
236241
protected:
237242
explicit AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer);
238243

llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,6 +1348,21 @@ void emitYkBBAddrMapSymbol(MCContext &MCtxt, MCStreamer &OutStreamer,
13481348
OutStreamer.emitLabel(Sym);
13491349
}
13501350

1351+
/// Returns the fallthrough block of `MBB`, or nullptr if there isn't one.
1352+
MachineBasicBlock *findFallthruBlock(const MachineBasicBlock *MBB) {
1353+
for (MachineBasicBlock *SBB : MBB->successors()) {
1354+
if (MBB->isLayoutSuccessor(SBB)) {
1355+
return SBB;
1356+
}
1357+
}
1358+
return nullptr;
1359+
}
1360+
1361+
inline const MCSymbol *BBSym(const MachineBasicBlock *MBB,
1362+
const MCSymbol *FuncSym) {
1363+
return MBB->isEntryBlock() ? FuncSym : MBB->getSymbol();
1364+
}
1365+
13511366
void AsmPrinter::emitBBAddrMapSection(const MachineFunction &MF) {
13521367
MCSection *BBAddrMapSection =
13531368
getObjFileLowering().getBBAddrMapSection(*MF.getSection());
@@ -1408,6 +1423,9 @@ void AsmPrinter::emitBBAddrMapSection(const MachineFunction &MF) {
14081423
MergedBBs.erase(BB);
14091424
}
14101425
}
1426+
1427+
const TargetInstrInfo *TI = MF.getSubtarget().getInstrInfo();
1428+
14111429
// Emit BB Information for each basic block in the funciton.
14121430
for (const MachineBasicBlock &MBB : MF) {
14131431
const MCSymbol *MBBSymbol =
@@ -1456,6 +1474,107 @@ void AsmPrinter::emitBBAddrMapSection(const MachineFunction &MF) {
14561474
OutContext.reportError(SMLoc(), "Couldn't find the block's index");
14571475
OutStreamer->emitULEB128IntValue(I);
14581476
}
1477+
1478+
// Emit call marker table for the Yk JIT.
1479+
//
1480+
// The table is a size header, followed by call instruction addresses.
1481+
//
1482+
// YKOPT: to save space, instead of using absolute symbol addresses, compute
1483+
// the distance from the start of the block and use uleb128 encoding.
1484+
const size_t NumCalls = YkCallMarkerSyms[&MBB].size();
1485+
OutStreamer->emitULEB128IntValue(NumCalls);
1486+
for (auto Tup : YkCallMarkerSyms[&MBB]) {
1487+
// Emit address of the call instruction.
1488+
OutStreamer->emitSymbolValue(std::get<0>(Tup), getPointerSize());
1489+
// Emit address of target if known, or 0.
1490+
MCSymbol *Target = std::get<1>(Tup);
1491+
if (Target)
1492+
OutStreamer->emitSymbolValue(Target, getPointerSize());
1493+
else
1494+
OutStreamer->emitIntValue(0, getPointerSize());
1495+
}
1496+
1497+
// Emit successor information.
1498+
//
1499+
// Each codegenned block gets a record indicating any statically known
1500+
// successors. The record starts with a `SuccessorKind` byte:
1501+
enum SuccessorKind {
1502+
// One successor.
1503+
Unconditional = 0,
1504+
// Choice of two successors.
1505+
Conditional = 1,
1506+
// A control flow edge known only at runtime, e.g. a return or an indirect
1507+
// branch.
1508+
Dynamic = 2,
1509+
};
1510+
1511+
// Then depending of the `SuccessorKind` there is a payload describing the
1512+
// successors:
1513+
//
1514+
// `Unconditional`: [target-address: u64]
1515+
// `Conditional`: [taken-address: u64, not-taken-address: u64]
1516+
// `Dynamic`: [] (i.e. nothing, because nothing is statically known)
1517+
1518+
MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
1519+
SmallVector<MachineOperand> Conds;
1520+
1521+
if (!TI->analyzeBranch(const_cast<MachineBasicBlock &>(MBB), TBB, FBB,
1522+
Conds)) {
1523+
// The block ends with a branch or a fall-thru.
1524+
if (!TBB && !FBB) {
1525+
// Both null: block has no terminator and either falls through or
1526+
// diverges.
1527+
OutStreamer->emitInt8(Unconditional);
1528+
MachineBasicBlock *ThruBB = findFallthruBlock(&MBB);
1529+
if (ThruBB) {
1530+
OutStreamer->emitSymbolValue(BBSym(ThruBB, FunctionSymbol),
1531+
getPointerSize());
1532+
} else {
1533+
OutStreamer->emitInt64(0); // Divergent.
1534+
}
1535+
} else if (TBB && !FBB) {
1536+
// Only FBB null: block either ends with an unconditional branch or a
1537+
// conditional branch whose false arm falls through or diverges.
1538+
if (Conds.empty()) {
1539+
// No conditions: unconditional branch.
1540+
OutStreamer->emitInt8(Unconditional);
1541+
OutStreamer->emitSymbolValue(BBSym(TBB, FunctionSymbol),
1542+
getPointerSize());
1543+
} else {
1544+
// Has conditions: conditional branch followed by fallthru or
1545+
// divergence.
1546+
MachineBasicBlock *ThruBB = findFallthruBlock(&MBB);
1547+
OutStreamer->emitInt8(Conditional);
1548+
OutStreamer->emitSymbolValue(BBSym(TBB, FunctionSymbol),
1549+
getPointerSize());
1550+
if (ThruBB) {
1551+
OutStreamer->emitSymbolValue(BBSym(ThruBB, FunctionSymbol),
1552+
getPointerSize());
1553+
} else {
1554+
OutStreamer->emitInt64(0); // Divergent.
1555+
}
1556+
}
1557+
} else {
1558+
// Conditional branch followed by an unconditional branch.
1559+
assert(TBB && FBB);
1560+
OutStreamer->emitInt8(Conditional);
1561+
OutStreamer->emitSymbolValue(BBSym(TBB, FunctionSymbol),
1562+
getPointerSize());
1563+
OutStreamer->emitSymbolValue(BBSym(FBB, FunctionSymbol),
1564+
getPointerSize());
1565+
}
1566+
} else {
1567+
// Wasn't a branch or a fall-thru. Must be a different kind of terminator.
1568+
const MachineInstr *LastI = &*MBB.instr_rbegin();
1569+
if (LastI->isReturn() || LastI->isIndirectBranch()) {
1570+
OutStreamer->emitInt8(Dynamic);
1571+
} else {
1572+
std::string Msg = "unhandled block terminator in block: ";
1573+
raw_string_ostream OS(Msg);
1574+
LastI->print(OS);
1575+
OutContext.reportError(SMLoc(), Msg);
1576+
}
1577+
}
14591578
}
14601579

14611580
OutStreamer->popSection();
@@ -1577,6 +1696,9 @@ void AsmPrinter::emitFunctionBody() {
15771696
for (auto &MBB : *MF) {
15781697
// Print a label for the basic block.
15791698
emitBasicBlockStart(MBB);
1699+
1700+
YkCallMarkerSyms.insert({&MBB, {}});
1701+
15801702
DenseMap<StringRef, unsigned> MnemonicCounts;
15811703
for (auto &MI : MBB) {
15821704
// Print the assembly for the instruction.
@@ -1651,6 +1773,24 @@ void AsmPrinter::emitFunctionBody() {
16511773
OutStreamer->emitRawComment("ARITH_FENCE");
16521774
break;
16531775
default:
1776+
1777+
if (YkAllocLLVMBBAddrMapSection && MI.isCall() &&
1778+
(MI.getOpcode() != TargetOpcode::STACKMAP) &&
1779+
(MI.getOpcode() != TargetOpcode::PATCHPOINT) &&
1780+
(MI.getOpcode() != TargetOpcode::STATEPOINT)) {
1781+
MCSymbol *YkPreCallSym =
1782+
MF->getContext().createTempSymbol("yk_precall", true);
1783+
OutStreamer->emitLabel(YkPreCallSym);
1784+
const MachineOperand CallOpnd = MI.getOperand(0);
1785+
MCSymbol *CallTargetSym = nullptr;
1786+
if (CallOpnd.isGlobal()) {
1787+
// Statically known function address.
1788+
CallTargetSym = getSymbol(CallOpnd.getGlobal());
1789+
}
1790+
assert(YkCallMarkerSyms.find(&MBB) != YkCallMarkerSyms.end());
1791+
YkCallMarkerSyms[&MBB].push_back({YkPreCallSym, CallTargetSym});
1792+
}
1793+
16541794
emitInstruction(&MI);
16551795
if (CanDoExtraAnalysis) {
16561796
MCInst MCI;

llvm/test/CodeGen/X86/basic-block-sections-labels.ll

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,21 @@ declare i32 @__gxx_personality_v0(...)
5555
; CHECK-NEXT: .byte 8
5656
; CHECK-NEXT: .byte 1
5757
; CHECK-NEXT: .byte 0
58-
; CHECK-NEXT: .uleb128 .LBB0_1-.LBB_END0_0
58+
; ...calls and successor info for Yk JIT...
59+
; CHECK: .uleb128 .LBB0_1-.LBB_END0_0
5960
; CHECK-NEXT: .uleb128 .LBB_END0_1-.LBB0_1
6061
; CHECK-NEXT: .byte 8
6162
; CHECK-NEXT: .byte 1
6263
; CHECK-NEXT: .byte 1
63-
; CHECK-NEXT: .uleb128 .LBB0_2-.LBB_END0_1
64+
; ...calls and successor info for Yk JIT...
65+
; CHECK: .uleb128 .LBB0_2-.LBB_END0_1
6466
; CHECK-NEXT: .uleb128 .LBB_END0_2-.LBB0_2
6567
; CHECK-NEXT: .byte 1
6668
; CHECK-NEXT: .byte 2
6769
; CHECK-NEXT: .byte 3
6870
; CHECK-NEXT: .byte 4
69-
; CHECK-NEXT: .uleb128 .LBB0_3-.LBB_END0_2
71+
; ...calls and successor info for Yk JIT...
72+
; CHECK: .uleb128 .LBB0_3-.LBB_END0_2
7073
; CHECK-NEXT: .uleb128 .LBB_END0_3-.LBB0_3
7174
; CHECK-NEXT: .byte 5
7275
; CHECK-NEXT: .byte 2

0 commit comments

Comments
 (0)