|
17 | 17 | #include "bolt/Utils/Utils.h"
|
18 | 18 | #include "llvm/Support/CommandLine.h"
|
19 | 19 | #include "llvm/Support/RWMutex.h"
|
| 20 | +#include <queue> |
20 | 21 | #include <stack>
|
| 22 | +#include <unordered_set> |
21 | 23 |
|
22 | 24 | #define DEBUG_TYPE "bolt-instrumentation"
|
23 | 25 |
|
@@ -86,33 +88,90 @@ cl::opt<bool> InstrumentCalls("instrument-calls",
|
86 | 88 | namespace llvm {
|
87 | 89 | namespace bolt {
|
88 | 90 |
|
89 |
| -static bool hasAArch64ExclusiveMemop(BinaryFunction &Function) { |
| 91 | +static bool hasAArch64ExclusiveMemop( |
| 92 | + BinaryFunction &Function, |
| 93 | + std::unordered_set<const BinaryBasicBlock *> &BBToSkip) { |
90 | 94 | // FIXME ARMv8-a architecture reference manual says that software must avoid
|
91 | 95 | // having any explicit memory accesses between exclusive load and associated
|
92 |
| - // store instruction. So for now skip instrumentation for functions that have |
93 |
| - // these instructions, since it might lead to runtime deadlock. |
| 96 | + // store instruction. So for now skip instrumentation for basic blocks that |
| 97 | + // have these instructions, since it might lead to runtime deadlock. |
94 | 98 | BinaryContext &BC = Function.getBinaryContext();
|
95 |
| - for (const BinaryBasicBlock &BB : Function) |
96 |
| - for (const MCInst &Inst : BB) |
97 |
| - if (BC.MIB->isAArch64Exclusive(Inst)) { |
98 |
| - if (opts::Verbosity >= 1) |
99 |
| - BC.outs() << "BOLT-INSTRUMENTER: Function " << Function |
100 |
| - << " has exclusive instructions, skip instrumentation\n"; |
| 99 | + std::queue<std::pair<BinaryBasicBlock *, bool>> BBQueue; // {BB, isLoad} |
| 100 | + std::unordered_set<BinaryBasicBlock *> Visited; |
| 101 | + |
| 102 | + if (Function.getLayout().block_begin() == Function.getLayout().block_end()) |
| 103 | + return 0; |
| 104 | + |
| 105 | + BinaryBasicBlock *BBfirst = *Function.getLayout().block_begin(); |
| 106 | + BBQueue.push({BBfirst, false}); |
| 107 | + |
| 108 | + while (!BBQueue.empty()) { |
| 109 | + BinaryBasicBlock *BB = BBQueue.front().first; |
| 110 | + bool IsLoad = BBQueue.front().second; |
| 111 | + BBQueue.pop(); |
| 112 | + if (Visited.find(BB) != Visited.end()) |
| 113 | + continue; |
| 114 | + Visited.insert(BB); |
| 115 | + |
| 116 | + for (const MCInst &Inst : *BB) { |
| 117 | + // Two loads one after another - skip whole function |
| 118 | + if (BC.MIB->isAArch64ExclusiveLoad(Inst) && IsLoad) { |
| 119 | + if (opts::Verbosity >= 2) { |
| 120 | + outs() << "BOLT-INSTRUMENTER: function " << Function.getPrintName() |
| 121 | + << " has two exclusive loads. Ignoring the function.\n"; |
| 122 | + } |
101 | 123 | return true;
|
102 | 124 | }
|
103 | 125 |
|
104 |
| - return false; |
105 |
| -} |
| 126 | + if (BC.MIB->isAArch64ExclusiveLoad(Inst)) |
| 127 | + IsLoad = true; |
| 128 | + |
| 129 | + if (IsLoad && BBToSkip.find(BB) == BBToSkip.end()) { |
| 130 | + BBToSkip.insert(BB); |
| 131 | + if (opts::Verbosity >= 2) { |
| 132 | + outs() << "BOLT-INSTRUMENTER: skip BB " << BB->getName() |
| 133 | + << " due to exclusive instruction in function " |
| 134 | + << Function.getPrintName() << "\n"; |
| 135 | + } |
| 136 | + } |
| 137 | + |
| 138 | + if (!IsLoad && BC.MIB->isAArch64ExclusiveStore(Inst)) { |
| 139 | + if (opts::Verbosity >= 2) { |
| 140 | + outs() << "BOLT-INSTRUMENTER: function " << Function.getPrintName() |
| 141 | + << " has exclusive store without corresponding load. Ignoring " |
| 142 | + "the function.\n"; |
| 143 | + } |
| 144 | + return true; |
| 145 | + } |
| 146 | + |
| 147 | + if (IsLoad && (BC.MIB->isAArch64ExclusiveStore(Inst) || |
| 148 | + BC.MIB->isAArch64ExclusiveClear(Inst))) |
| 149 | + IsLoad = false; |
| 150 | + } |
106 | 151 |
|
107 |
| -uint32_t Instrumentation::getFunctionNameIndex(const BinaryFunction &Function) { |
108 |
| - auto Iter = FuncToStringIdx.find(&Function); |
109 |
| - if (Iter != FuncToStringIdx.end()) |
110 |
| - return Iter->second; |
111 |
| - size_t Idx = Summary->StringTable.size(); |
112 |
| - FuncToStringIdx.emplace(std::make_pair(&Function, Idx)); |
113 |
| - Summary->StringTable.append(getEscapedName(Function.getOneName())); |
114 |
| - Summary->StringTable.append(1, '\0'); |
115 |
| - return Idx; |
| 152 | + if (IsLoad && BB->succ_size() == 0) { |
| 153 | + if (opts::Verbosity >= 2) { |
| 154 | + outs() |
| 155 | + << "BOLT-INSTRUMENTER: function " << Function.getPrintName() |
| 156 | + << " has exclusive load in trailing BB. Ignoring the function.\n"; |
| 157 | + } |
| 158 | + return true; |
| 159 | + } |
| 160 | + |
| 161 | + for (BinaryBasicBlock *BBS : BB->successors()) |
| 162 | + BBQueue.push({BBS, IsLoad}); |
| 163 | + } |
| 164 | + |
| 165 | + if (BBToSkip.size() == Visited.size()) { |
| 166 | + if (opts::Verbosity >= 2) { |
| 167 | + outs() << "BOLT-INSTRUMENTER: all BBs are marked with true. Ignoring the " |
| 168 | + "function " |
| 169 | + << Function.getPrintName() << "\n"; |
| 170 | + } |
| 171 | + return true; |
| 172 | + } |
| 173 | + |
| 174 | + return false; |
116 | 175 | }
|
117 | 176 |
|
118 | 177 | bool Instrumentation::createCallDescription(FunctionDescription &FuncDesc,
|
@@ -307,7 +366,8 @@ void Instrumentation::instrumentFunction(BinaryFunction &Function,
|
307 | 366 | if (BC.isMachO() && Function.hasName("___GLOBAL_init_65535/1"))
|
308 | 367 | return;
|
309 | 368 |
|
310 |
| - if (BC.isAArch64() && hasAArch64ExclusiveMemop(Function)) |
| 369 | + std::unordered_set<const BinaryBasicBlock *> BBToSkip; |
| 370 | + if (BC.isAArch64() && hasAArch64ExclusiveMemop(Function, BBToSkip)) |
311 | 371 | return;
|
312 | 372 |
|
313 | 373 | SplitWorklistTy SplitWorklist;
|
@@ -389,6 +449,11 @@ void Instrumentation::instrumentFunction(BinaryFunction &Function,
|
389 | 449 |
|
390 | 450 | for (auto BBI = Function.begin(), BBE = Function.end(); BBI != BBE; ++BBI) {
|
391 | 451 | BinaryBasicBlock &BB = *BBI;
|
| 452 | + |
| 453 | + // Skip BBs with exclusive load/stores |
| 454 | + if (BBToSkip.find(&BB) != BBToSkip.end()) |
| 455 | + continue; |
| 456 | + |
392 | 457 | bool HasUnconditionalBranch = false;
|
393 | 458 | bool HasJumpTable = false;
|
394 | 459 | bool IsInvokeBlock = InvokeBlocks.count(&BB) > 0;
|
|
0 commit comments