@@ -1348,6 +1348,21 @@ void emitYkBBAddrMapSymbol(MCContext &MCtxt, MCStreamer &OutStreamer,
1348
1348
OutStreamer.emitLabel (Sym);
1349
1349
}
1350
1350
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
+
1351
1366
void AsmPrinter::emitBBAddrMapSection (const MachineFunction &MF) {
1352
1367
MCSection *BBAddrMapSection =
1353
1368
getObjFileLowering ().getBBAddrMapSection (*MF.getSection ());
@@ -1408,6 +1423,9 @@ void AsmPrinter::emitBBAddrMapSection(const MachineFunction &MF) {
1408
1423
MergedBBs.erase (BB);
1409
1424
}
1410
1425
}
1426
+
1427
+ const TargetInstrInfo *TI = MF.getSubtarget ().getInstrInfo ();
1428
+
1411
1429
// Emit BB Information for each basic block in the funciton.
1412
1430
for (const MachineBasicBlock &MBB : MF) {
1413
1431
const MCSymbol *MBBSymbol =
@@ -1456,6 +1474,107 @@ void AsmPrinter::emitBBAddrMapSection(const MachineFunction &MF) {
1456
1474
OutContext.reportError (SMLoc (), " Couldn't find the block's index" );
1457
1475
OutStreamer->emitULEB128IntValue (I);
1458
1476
}
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
+ }
1459
1578
}
1460
1579
1461
1580
OutStreamer->popSection ();
@@ -1577,6 +1696,9 @@ void AsmPrinter::emitFunctionBody() {
1577
1696
for (auto &MBB : *MF) {
1578
1697
// Print a label for the basic block.
1579
1698
emitBasicBlockStart (MBB);
1699
+
1700
+ YkCallMarkerSyms.insert ({&MBB, {}});
1701
+
1580
1702
DenseMap<StringRef, unsigned > MnemonicCounts;
1581
1703
for (auto &MI : MBB) {
1582
1704
// Print the assembly for the instruction.
@@ -1651,6 +1773,24 @@ void AsmPrinter::emitFunctionBody() {
1651
1773
OutStreamer->emitRawComment (" ARITH_FENCE" );
1652
1774
break ;
1653
1775
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
+
1654
1794
emitInstruction (&MI);
1655
1795
if (CanDoExtraAnalysis) {
1656
1796
MCInst MCI;
0 commit comments