|
79 | 79 | #include "llvm/IR/Function.h" |
80 | 80 | #include "llvm/IR/Instructions.h" |
81 | 81 | #include "llvm/IR/Module.h" |
| 82 | +#include "llvm/InitializePasses.h" |
82 | 83 | #include "llvm/Pass.h" |
83 | 84 | #include <llvm/IR/Dominators.h> |
84 | 85 | #include <llvm/IR/IRBuilder.h> |
@@ -266,87 +267,103 @@ std::vector<Value *> getLiveVars(DominatorTree &DT, CallInst *OldCtrlPoint) { |
266 | 267 | return Vec; |
267 | 268 | } |
268 | 269 |
|
269 | | -YkControlPointPass::YkControlPointPass() {} |
270 | | - |
271 | | -PreservedAnalyses YkControlPointPass::run(Module &M, |
272 | | - ModuleAnalysisManager &AM) { |
273 | | - LLVMContext &Context = M.getContext(); |
| 270 | +namespace llvm { |
| 271 | +void initializeYkControlPointPass(PassRegistry &); |
| 272 | +} |
274 | 273 |
|
275 | | - // Locate the "dummy" control point provided by the user. |
276 | | - CallInst *OldCtrlPointCall = findControlPointCall(M); |
277 | | - if (OldCtrlPointCall == nullptr) { |
278 | | - Context.emitError("ykllvm couldn't find the call to `yk_control_point()`"); |
279 | | - return PreservedAnalyses::all(); |
| 274 | +namespace { |
| 275 | +class YkControlPoint : public ModulePass { |
| 276 | +public: |
| 277 | + static char ID; |
| 278 | + YkControlPoint() : ModulePass(ID) { |
| 279 | + initializeYkControlPointPass(*PassRegistry::getPassRegistry()); |
280 | 280 | } |
281 | 281 |
|
282 | | - // Replace old control point call. |
283 | | - IRBuilder<> Builder(OldCtrlPointCall); |
284 | | - |
285 | | - // Get function containing the control point. |
286 | | - Function *Caller = OldCtrlPointCall->getFunction(); |
287 | | - |
288 | | - // Find all live variables just before the call to the control point. |
289 | | - DominatorTree DT(*Caller); |
290 | | - std::vector<Value *> LiveVals = getLiveVars(DT, OldCtrlPointCall); |
291 | | - if (LiveVals.size() == 0) { |
292 | | - Context.emitError( |
293 | | - "The interpreter loop has no live variables!\n" |
294 | | - "ykllvm doesn't support this scenario, as such an interpreter would " |
295 | | - "make little sense."); |
296 | | - return PreservedAnalyses::all(); |
297 | | - } |
| 282 | + bool runOnModule(Module &M) override { |
| 283 | + LLVMContext &Context = M.getContext(); |
298 | 284 |
|
299 | | - // Generate the YkCtrlPointVars struct. This struct is used to package up a |
300 | | - // copy of all LLVM variables that are live just before the call to the |
301 | | - // control point. These are passed in to the patched control point so that |
302 | | - // they can be used as inputs and outputs to JITted trace code. The control |
303 | | - // point returns a new YkCtrlPointVars whose members may have been mutated |
304 | | - // by JITted trace code (if a trace was executed). |
305 | | - std::vector<Type *> TypeParams; |
306 | | - for (Value *V : LiveVals) { |
307 | | - TypeParams.push_back(V->getType()); |
308 | | - } |
309 | | - StructType *CtrlPointReturnTy = |
310 | | - StructType::create(TypeParams, "YkCtrlPointVars"); |
| 285 | + // Locate the "dummy" control point provided by the user. |
| 286 | + CallInst *OldCtrlPointCall = findControlPointCall(M); |
| 287 | + if (OldCtrlPointCall == nullptr) { |
| 288 | + Context.emitError( |
| 289 | + "ykllvm couldn't find the call to `yk_control_point()`"); |
| 290 | + return false; |
| 291 | + } |
311 | 292 |
|
312 | | - // Create the new control point. |
313 | | - Type *YkLocTy = OldCtrlPointCall->getArgOperand(0)->getType(); |
314 | | - FunctionType *FType = |
315 | | - FunctionType::get(CtrlPointReturnTy, {YkLocTy, CtrlPointReturnTy}, false); |
316 | | - Function *NF = Function::Create(FType, GlobalVariable::ExternalLinkage, |
317 | | - YK_NEW_CONTROL_POINT, M); |
318 | | - |
319 | | - // Instantiate the YkCtrlPointStruct to pass in to the control point. |
320 | | - Value *InputStruct = cast<Value>(Constant::getNullValue(CtrlPointReturnTy)); |
321 | | - unsigned LvIdx = 0; |
322 | | - for (Value *LV : LiveVals) { |
323 | | - InputStruct = Builder.CreateInsertValue(InputStruct, LV, LvIdx); |
324 | | - assert(LvIdx != UINT_MAX); |
325 | | - LvIdx++; |
326 | | - } |
| 293 | + // Replace old control point call. |
| 294 | + IRBuilder<> Builder(OldCtrlPointCall); |
| 295 | + |
| 296 | + // Get function containing the control point. |
| 297 | + Function *Caller = OldCtrlPointCall->getFunction(); |
| 298 | + |
| 299 | + // Find all live variables just before the call to the control point. |
| 300 | + DominatorTree DT(*Caller); |
| 301 | + std::vector<Value *> LiveVals = getLiveVars(DT, OldCtrlPointCall); |
| 302 | + if (LiveVals.size() == 0) { |
| 303 | + Context.emitError( |
| 304 | + "The interpreter loop has no live variables!\n" |
| 305 | + "ykllvm doesn't support this scenario, as such an interpreter would " |
| 306 | + "make little sense."); |
| 307 | + return false; |
| 308 | + } |
327 | 309 |
|
328 | | - // Insert call to the new control point. |
329 | | - CallInst *CtrlPointRet = |
330 | | - Builder.CreateCall(NF, {OldCtrlPointCall->getArgOperand(0), InputStruct}); |
331 | | - |
332 | | - // Once the control point returns we need to extract the (potentially |
333 | | - // mutated) values from the returned YkCtrlPointStruct and reassign them to |
334 | | - // their corresponding live variables. In LLVM IR we can do this by simply |
335 | | - // replacing all future references with the new values. |
336 | | - LvIdx = 0; |
337 | | - for (Value *LV : LiveVals) { |
338 | | - Value *New = Builder.CreateExtractValue(cast<Value>(CtrlPointRet), LvIdx); |
339 | | - LV->replaceUsesWithIf( |
340 | | - New, [&](Use &U) { return DT.dominates(CtrlPointRet, U); }); |
341 | | - assert(LvIdx != UINT_MAX); |
342 | | - LvIdx++; |
343 | | - } |
| 310 | + // Generate the YkCtrlPointVars struct. This struct is used to package up a |
| 311 | + // copy of all LLVM variables that are live just before the call to the |
| 312 | + // control point. These are passed in to the patched control point so that |
| 313 | + // they can be used as inputs and outputs to JITted trace code. The control |
| 314 | + // point returns a new YkCtrlPointVars whose members may have been mutated |
| 315 | + // by JITted trace code (if a trace was executed). |
| 316 | + std::vector<Type *> TypeParams; |
| 317 | + for (Value *V : LiveVals) { |
| 318 | + TypeParams.push_back(V->getType()); |
| 319 | + } |
| 320 | + StructType *CtrlPointReturnTy = |
| 321 | + StructType::create(TypeParams, "YkCtrlPointVars"); |
| 322 | + |
| 323 | + // Create the new control point. |
| 324 | + Type *YkLocTy = OldCtrlPointCall->getArgOperand(0)->getType(); |
| 325 | + FunctionType *FType = FunctionType::get( |
| 326 | + CtrlPointReturnTy, {YkLocTy, CtrlPointReturnTy}, false); |
| 327 | + Function *NF = Function::Create(FType, GlobalVariable::ExternalLinkage, |
| 328 | + YK_NEW_CONTROL_POINT, M); |
| 329 | + |
| 330 | + // Instantiate the YkCtrlPointStruct to pass in to the control point. |
| 331 | + Value *InputStruct = cast<Value>(Constant::getNullValue(CtrlPointReturnTy)); |
| 332 | + unsigned LvIdx = 0; |
| 333 | + for (Value *LV : LiveVals) { |
| 334 | + InputStruct = Builder.CreateInsertValue(InputStruct, LV, LvIdx); |
| 335 | + assert(LvIdx != UINT_MAX); |
| 336 | + LvIdx++; |
| 337 | + } |
| 338 | + |
| 339 | + // Insert call to the new control point. |
| 340 | + CallInst *CtrlPointRet = Builder.CreateCall( |
| 341 | + NF, {OldCtrlPointCall->getArgOperand(0), InputStruct}); |
| 342 | + |
| 343 | + // Once the control point returns we need to extract the (potentially |
| 344 | + // mutated) values from the returned YkCtrlPointStruct and reassign them to |
| 345 | + // their corresponding live variables. In LLVM IR we can do this by simply |
| 346 | + // replacing all future references with the new values. |
| 347 | + LvIdx = 0; |
| 348 | + for (Value *LV : LiveVals) { |
| 349 | + Value *New = Builder.CreateExtractValue(cast<Value>(CtrlPointRet), LvIdx); |
| 350 | + LV->replaceUsesWithIf( |
| 351 | + New, [&](Use &U) { return DT.dominates(CtrlPointRet, U); }); |
| 352 | + assert(LvIdx != UINT_MAX); |
| 353 | + LvIdx++; |
| 354 | + } |
| 355 | + |
| 356 | + // Replace the call to the dummy control point. |
| 357 | + OldCtrlPointCall->eraseFromParent(); |
344 | 358 |
|
345 | | - // Replace the call to the dummy control point. |
346 | | - OldCtrlPointCall->eraseFromParent(); |
| 359 | + // Generate new control point logic. |
| 360 | + createControlPoint(M, NF, LiveVals, CtrlPointReturnTy, YkLocTy); |
| 361 | + return true; |
| 362 | + } |
| 363 | +}; |
| 364 | +} // namespace |
347 | 365 |
|
348 | | - // Generate new control point logic. |
349 | | - createControlPoint(M, NF, LiveVals, CtrlPointReturnTy, YkLocTy); |
| 366 | +char YkControlPoint::ID = 0; |
| 367 | +INITIALIZE_PASS(YkControlPoint, DEBUG_TYPE, "yk control point", false, false) |
350 | 368 |
|
351 | | - return PreservedAnalyses::none(); |
352 | | -} |
| 369 | +ModulePass *llvm::createYkControlPointPass() { return new YkControlPoint(); } |
0 commit comments