|
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