|
26 | 26 | #include "llvm/MC/MCInstrInfo.h"
|
27 | 27 | #include "llvm/MC/MCRegister.h"
|
28 | 28 | #include "llvm/MC/MCRegisterInfo.h"
|
| 29 | +#include "llvm/Support/CommandLine.h" |
29 | 30 | #include "llvm/Support/DataExtractor.h"
|
30 | 31 | #include "llvm/Support/Debug.h"
|
31 | 32 | #include "llvm/Support/ErrorHandling.h"
|
|
35 | 36 | using namespace llvm;
|
36 | 37 | using namespace bolt;
|
37 | 38 |
|
| 39 | +namespace opts { |
| 40 | +extern cl::OptionCategory BoltInstrCategory; |
| 41 | +static cl::opt<bool> NoLSEAtomics( |
| 42 | + "no-lse-atomics", |
| 43 | + cl::desc("generate instrumentation code sequence without using LSE atomic " |
| 44 | + "instruction"), |
| 45 | + cl::init(false), cl::Optional, cl::cat(BoltInstrCategory)); |
| 46 | +} // namespace opts |
| 47 | + |
38 | 48 | namespace {
|
39 | 49 |
|
40 | 50 | static void getSystemFlag(MCInst &Inst, MCPhysReg RegName) {
|
@@ -106,7 +116,7 @@ static void storeReg(MCInst &Inst, MCPhysReg From, MCPhysReg To) {
|
106 | 116 | }
|
107 | 117 |
|
108 | 118 | static void atomicAdd(MCInst &Inst, MCPhysReg RegTo, MCPhysReg RegCnt) {
|
109 |
| - // NOTE: Supports only ARM with LSE extension |
| 119 | + assert(!opts::NoLSEAtomics && "Supports only ARM with LSE extension"); |
110 | 120 | Inst.setOpcode(AArch64::LDADDX);
|
111 | 121 | Inst.clear();
|
112 | 122 | Inst.addOperand(MCOperand::createReg(AArch64::XZR));
|
@@ -135,6 +145,8 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
|
135 | 145 | public:
|
136 | 146 | using MCPlusBuilder::MCPlusBuilder;
|
137 | 147 |
|
| 148 | + BinaryFunction *InstrCounterIncrFunc{nullptr}; |
| 149 | + |
138 | 150 | std::unique_ptr<MCSymbolizer>
|
139 | 151 | createTargetSymbolizer(BinaryFunction &Function,
|
140 | 152 | bool CreateNewSymbols) const override {
|
@@ -2513,22 +2525,129 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
|
2513 | 2525 | return Insts;
|
2514 | 2526 | }
|
2515 | 2527 |
|
2516 |
| - InstructionListType |
2517 |
| - createInstrIncMemory(const MCSymbol *Target, MCContext *Ctx, bool IsLeaf, |
2518 |
| - unsigned CodePointerSize) const override { |
| 2528 | + // Instrumentation code sequence using LSE atomic instruction has a total of |
| 2529 | + // 6 instructions: |
| 2530 | + // |
| 2531 | + // stp x0, x1, [sp, #-0x10]! |
| 2532 | + // adrp x0, page_address(counter) |
| 2533 | + // add x0, x0, page_offset(counter) |
| 2534 | + // mov x1, #0x1 |
| 2535 | + // stadd x1, [x0] |
| 2536 | + // ldp x0, x1, [sp], #0x10 |
| 2537 | + // |
| 2538 | + // Instrumentation code sequence without using LSE atomic instruction has |
| 2539 | + // 8 instructions at instrumentation place, with 6 instructions in the helper: |
| 2540 | + // |
| 2541 | + // stp x0, x30, [sp, #-0x10]! |
| 2542 | + // stp x1, x2, [sp, #-0x10]! |
| 2543 | + // adrp x0, page_address(counter) |
| 2544 | + // add x0, x0, page_offset(counter) |
| 2545 | + // adrp x1, page_address(helper) |
| 2546 | + // add x1, x1, page_offset(helper) |
| 2547 | + // blr x1 |
| 2548 | + // ldp x0, x30, [sp], #0x10 |
| 2549 | + // |
| 2550 | + // <helper>: |
| 2551 | + // ldaxr x1, [x0] |
| 2552 | + // add x1, x1, #0x1 |
| 2553 | + // stlxr w2, x1, [x0] |
| 2554 | + // cbnz w2, <helper> |
| 2555 | + // ldp x1, x2, [sp], #0x10 |
| 2556 | + // ret |
| 2557 | + |
| 2558 | + void createInstrCounterIncrFunc(BinaryContext &BC) override { |
| 2559 | + assert(InstrCounterIncrFunc == nullptr && |
| 2560 | + "helper function of counter increment for instrumentation " |
| 2561 | + "has already been created"); |
| 2562 | + |
| 2563 | + if (!opts::NoLSEAtomics) |
| 2564 | + return; |
| 2565 | + |
| 2566 | + MCContext *Ctx = BC.Ctx.get(); |
| 2567 | + InstrCounterIncrFunc = BC.createInjectedBinaryFunction( |
| 2568 | + "__bolt_instr_counter_incr", /*IsSimple*/ false); |
| 2569 | + std::vector<std::unique_ptr<BinaryBasicBlock>> BBs; |
| 2570 | + |
| 2571 | + BBs.emplace_back(InstrCounterIncrFunc->createBasicBlock()); |
| 2572 | + InstructionListType Instrs(4); |
| 2573 | + Instrs[0].setOpcode(AArch64::LDAXRX); |
| 2574 | + Instrs[0].clear(); |
| 2575 | + Instrs[0].addOperand(MCOperand::createReg(AArch64::X1)); |
| 2576 | + Instrs[0].addOperand(MCOperand::createReg(AArch64::X0)); |
| 2577 | + Instrs[1].setOpcode(AArch64::ADDXri); |
| 2578 | + Instrs[1].clear(); |
| 2579 | + Instrs[1].addOperand(MCOperand::createReg(AArch64::X1)); |
| 2580 | + Instrs[1].addOperand(MCOperand::createReg(AArch64::X1)); |
| 2581 | + Instrs[1].addOperand(MCOperand::createImm(1)); |
| 2582 | + Instrs[1].addOperand(MCOperand::createImm(0)); |
| 2583 | + Instrs[2].setOpcode(AArch64::STLXRX); |
| 2584 | + Instrs[2].clear(); |
| 2585 | + Instrs[2].addOperand(MCOperand::createReg(AArch64::W2)); |
| 2586 | + Instrs[2].addOperand(MCOperand::createReg(AArch64::X1)); |
| 2587 | + Instrs[2].addOperand(MCOperand::createReg(AArch64::X0)); |
| 2588 | + Instrs[3].setOpcode(AArch64::CBNZW); |
| 2589 | + Instrs[3].clear(); |
| 2590 | + Instrs[3].addOperand(MCOperand::createReg(AArch64::W2)); |
| 2591 | + Instrs[3].addOperand(MCOperand::createExpr( |
| 2592 | + MCSymbolRefExpr::create(BBs.back()->getLabel(), *Ctx))); |
| 2593 | + BBs.back()->addInstructions(Instrs.begin(), Instrs.end()); |
| 2594 | + BBs.back()->setCFIState(0); |
| 2595 | + |
| 2596 | + BBs.emplace_back(InstrCounterIncrFunc->createBasicBlock()); |
| 2597 | + InstructionListType InstrsEpilog(2); |
| 2598 | + createPopRegisters(InstrsEpilog[0], AArch64::X1, AArch64::X2); |
| 2599 | + createReturn(InstrsEpilog[1]); |
| 2600 | + BBs.back()->addInstructions(InstrsEpilog.begin(), InstrsEpilog.end()); |
| 2601 | + BBs.back()->setCFIState(0); |
| 2602 | + |
| 2603 | + BBs[0]->addSuccessor(BBs[0].get()); |
| 2604 | + BBs[0]->addSuccessor(BBs[1].get()); |
| 2605 | + |
| 2606 | + InstrCounterIncrFunc->insertBasicBlocks(nullptr, std::move(BBs), |
| 2607 | + /*UpdateLayout*/ true, |
| 2608 | + /*UpdateCFIState*/ false); |
| 2609 | + InstrCounterIncrFunc->updateState(BinaryFunction::State::CFG_Finalized); |
| 2610 | + |
| 2611 | + LLVM_DEBUG({ |
| 2612 | + dbgs() << "BOLT-DEBUG: instrumentation counter increment helper:\n"; |
| 2613 | + InstrCounterIncrFunc->dump(); |
| 2614 | + }); |
| 2615 | + } |
| 2616 | + |
| 2617 | + InstructionListType createInstrIncMemory(const MCSymbol *Target, |
| 2618 | + MCContext *Ctx, bool IsLeaf, |
| 2619 | + unsigned CodePointerSize) override { |
2519 | 2620 | unsigned int I = 0;
|
2520 |
| - InstructionListType Instrs(6); |
| 2621 | + InstructionListType Instrs(opts::NoLSEAtomics ? 8 : 6); |
| 2622 | + |
| 2623 | + if (opts::NoLSEAtomics) { |
| 2624 | + createPushRegisters(Instrs[I++], AArch64::X0, AArch64::LR); |
| 2625 | + createPushRegisters(Instrs[I++], AArch64::X1, AArch64::X2); |
| 2626 | + } else { |
| 2627 | + createPushRegisters(Instrs[I++], AArch64::X0, AArch64::X1); |
| 2628 | + } |
2521 | 2629 |
|
2522 |
| - createPushRegisters(Instrs[I++], AArch64::X0, AArch64::X1); |
2523 | 2630 | InstructionListType Addr = materializeAddress(Target, Ctx, AArch64::X0);
|
2524 | 2631 | assert(Addr.size() == 2 && "Invalid Addr size");
|
2525 | 2632 | std::copy(Addr.begin(), Addr.end(), Instrs.begin() + I);
|
2526 | 2633 | I += Addr.size();
|
2527 |
| - InstructionListType Insts = createIncMemory(AArch64::X0, AArch64::X1); |
2528 |
| - assert(Insts.size() == 2 && "Invalid Insts size"); |
2529 |
| - std::copy(Insts.begin(), Insts.end(), Instrs.begin() + I); |
2530 |
| - I += Insts.size(); |
2531 |
| - createPopRegisters(Instrs[I++], AArch64::X0, AArch64::X1); |
| 2634 | + |
| 2635 | + if (opts::NoLSEAtomics) { |
| 2636 | + const MCSymbol *Helper = InstrCounterIncrFunc->getSymbol(); |
| 2637 | + InstructionListType HelperAddr = |
| 2638 | + materializeAddress(Helper, Ctx, AArch64::X1); |
| 2639 | + assert(HelperAddr.size() == 2 && "Invalid HelperAddr size"); |
| 2640 | + std::copy(HelperAddr.begin(), HelperAddr.end(), Instrs.begin() + I); |
| 2641 | + I += HelperAddr.size(); |
| 2642 | + createIndirectCallInst(Instrs[I++], /*IsTailCall*/ false, AArch64::X1); |
| 2643 | + } else { |
| 2644 | + InstructionListType Insts = createIncMemory(AArch64::X0, AArch64::X1); |
| 2645 | + assert(Insts.size() == 2 && "Invalid Insts size"); |
| 2646 | + std::copy(Insts.begin(), Insts.end(), Instrs.begin() + I); |
| 2647 | + I += Insts.size(); |
| 2648 | + } |
| 2649 | + createPopRegisters(Instrs[I++], AArch64::X0, |
| 2650 | + opts::NoLSEAtomics ? AArch64::LR : AArch64::X1); |
2532 | 2651 | return Instrs;
|
2533 | 2652 | }
|
2534 | 2653 |
|
|
0 commit comments