46
46
// YKFIXME: The control point cannot yet be used in an interpreter using
47
47
// threaded dispatch.
48
48
//
49
- // YKFIXME: The tracing logic is currently over-simplified:
49
+ // YKFIXME: The tracing logic is currently over-simplified. The following items
50
+ // need to be fixed:
50
51
//
51
- // - A JIT location is assumed to be a simple integer program counter. It
52
- // should be a `ykrt::Location` .
52
+ // - The address of `YkLocation` instances are used for identity, but they are
53
+ // intended to be freely moved by the user .
53
54
//
54
55
// - Tracing starts when we encounter a location for which we have no machine
55
56
// code. A hot counter should be used instead.
78
79
#include " llvm/IR/Function.h"
79
80
#include " llvm/IR/Instructions.h"
80
81
#include " llvm/IR/Module.h"
82
+ #include " llvm/InitializePasses.h"
81
83
#include " llvm/Pass.h"
82
84
#include < llvm/IR/Dominators.h>
83
85
#include < llvm/IR/IRBuilder.h>
@@ -123,7 +125,7 @@ void createJITStatePrint(IRBuilder<> &Builder, Module *Mod, std::string Str) {
123
125
// / Generates the new control point, which includes all logic to start/stop
124
126
// / tracing and to compile/execute traces.
125
127
void createControlPoint (Module &Mod, Function *F, std::vector<Value *> LiveVars,
126
- StructType *YkCtrlPointStruct) {
128
+ StructType *YkCtrlPointStruct, Type *YkLocTy ) {
127
129
auto &Context = Mod.getContext ();
128
130
129
131
// Create control point blocks and setup the IRBuilder.
@@ -166,9 +168,8 @@ void createControlPoint(Module &Mod, Function *F, std::vector<Value *> LiveVars,
166
168
PtNull, " compiled_trace" , (GlobalVariable *)nullptr );
167
169
168
170
GlobalVariable *GVStartLoc = new GlobalVariable (
169
- Mod, Type::getInt32Ty (Context), false , GlobalVariable::InternalLinkage,
170
- ConstantInt::get (Context, APInt (32 , -1 )), " start_loc" ,
171
- (GlobalVariable *)nullptr );
171
+ Mod, YkLocTy, false , GlobalVariable::InternalLinkage,
172
+ Constant::getNullValue (YkLocTy), " start_loc" , (GlobalVariable *)nullptr );
172
173
173
174
// Create control point entry block. Checks if we are currently tracing.
174
175
Value *GVTracingVal = Builder.CreateLoad (Type::getInt8Ty (Context), GVTracing);
@@ -196,8 +197,7 @@ void createControlPoint(Module &Mod, Function *F, std::vector<Value *> LiveVars,
196
197
// Create block that checks if we've reached the same location again so we
197
198
// can execute a compiled trace.
198
199
Builder.SetInsertPoint (BBHasTrace);
199
- Value *ValStartLoc =
200
- Builder.CreateLoad (Type::getInt32Ty (Context), GVStartLoc);
200
+ Value *ValStartLoc = Builder.CreateLoad (YkLocTy, GVStartLoc);
201
201
Value *ExecTraceCond = Builder.CreateICmp (CmpInst::Predicate::ICMP_EQ,
202
202
ValStartLoc, F->getArg (0 ));
203
203
Builder.CreateCondBr (ExecTraceCond, BBExecuteTrace, BBReturn);
@@ -220,8 +220,7 @@ void createControlPoint(Module &Mod, Function *F, std::vector<Value *> LiveVars,
220
220
221
221
// Create block that decides when to stop tracing.
222
222
Builder.SetInsertPoint (BBTracing);
223
- Value *ValStartLoc2 =
224
- Builder.CreateLoad (Type::getInt32Ty (Context), GVStartLoc);
223
+ Value *ValStartLoc2 = Builder.CreateLoad (YkLocTy, GVStartLoc);
225
224
Value *StopTracingCond = Builder.CreateICmp (CmpInst::Predicate::ICMP_EQ,
226
225
ValStartLoc2, F->getArg (0 ));
227
226
Builder.CreateCondBr (StopTracingCond, BBStopTracing, BBReturn);
@@ -268,86 +267,103 @@ std::vector<Value *> getLiveVars(DominatorTree &DT, CallInst *OldCtrlPoint) {
268
267
return Vec;
269
268
}
270
269
271
- YkControlPointPass::YkControlPointPass () {}
272
-
273
- PreservedAnalyses YkControlPointPass::run (Module &M,
274
- ModuleAnalysisManager &AM) {
275
- LLVMContext &Context = M.getContext ();
270
+ namespace llvm {
271
+ void initializeYkControlPointPass (PassRegistry &);
272
+ }
276
273
277
- // Locate the "dummy" control point provided by the user.
278
- CallInst *OldCtrlPointCall = findControlPointCall (M);
279
- if (OldCtrlPointCall == nullptr ) {
280
- Context.emitError (" ykllvm couldn't find the call to `yk_control_point()`" );
281
- return PreservedAnalyses::all ();
274
+ namespace {
275
+ class YkControlPoint : public ModulePass {
276
+ public:
277
+ static char ID;
278
+ YkControlPoint () : ModulePass(ID) {
279
+ initializeYkControlPointPass (*PassRegistry::getPassRegistry ());
282
280
}
283
281
284
- // Replace old control point call.
285
- IRBuilder<> Builder (OldCtrlPointCall);
286
-
287
- // Get function containing the control point.
288
- Function *Caller = OldCtrlPointCall->getFunction ();
289
-
290
- // Find all live variables just before the call to the control point.
291
- DominatorTree DT (*Caller);
292
- std::vector<Value *> LiveVals = getLiveVars (DT, OldCtrlPointCall);
293
- if (LiveVals.size () == 0 ) {
294
- Context.emitError (
295
- " The interpreter loop has no live variables!\n "
296
- " ykllvm doesn't support this scenario, as such an interpreter would "
297
- " make little sense." );
298
- return PreservedAnalyses::all ();
299
- }
282
+ bool runOnModule (Module &M) override {
283
+ LLVMContext &Context = M.getContext ();
300
284
301
- // Generate the YkCtrlPointVars struct. This struct is used to package up a
302
- // copy of all LLVM variables that are live just before the call to the
303
- // control point. These are passed in to the patched control point so that
304
- // they can be used as inputs and outputs to JITted trace code. The control
305
- // point returns a new YkCtrlPointVars whose members may have been mutated
306
- // by JITted trace code (if a trace was executed).
307
- std::vector<Type *> TypeParams;
308
- for (Value *V : LiveVals) {
309
- TypeParams.push_back (V->getType ());
310
- }
311
- StructType *CtrlPointReturnTy =
312
- StructType::create (TypeParams, " YkCtrlPointVars" );
313
-
314
- // Create the new control point.
315
- FunctionType *FType = FunctionType::get (
316
- CtrlPointReturnTy, {Type::getInt32Ty (Context), CtrlPointReturnTy}, false );
317
- Function *NF = Function::Create (FType, GlobalVariable::ExternalLinkage,
318
- YK_NEW_CONTROL_POINT, M);
319
-
320
- // Instantiate the YkCtrlPointStruct to pass in to the control point.
321
- Value *InputStruct = cast<Value>(Constant::getNullValue (CtrlPointReturnTy));
322
- unsigned LvIdx = 0 ;
323
- for (Value *LV : LiveVals) {
324
- InputStruct = Builder.CreateInsertValue (InputStruct, LV, LvIdx);
325
- assert (LvIdx != UINT_MAX);
326
- LvIdx++;
327
- }
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
+ }
328
292
329
- // Insert call to the new control point.
330
- CallInst *CtrlPointRet =
331
- Builder. CreateCall (NF, {OldCtrlPointCall-> getArgOperand ( 0 ), InputStruct});
332
-
333
- // Once the control point returns we need to extract the (potentially
334
- // mutated) values from the returned YkCtrlPointStruct and reassign them to
335
- // their corresponding live variables. In LLVM IR we can do this by simply
336
- // replacing all future references with the new values.
337
- LvIdx = 0 ;
338
- for (Value *LV : LiveVals) {
339
- Value *New = Builder. CreateExtractValue (cast<Value>(CtrlPointRet), LvIdx);
340
- LV-> replaceUsesWithIf (
341
- New, [&](Use &U) { return DT. dominates (CtrlPointRet, U); });
342
- assert (LvIdx != UINT_MAX );
343
- LvIdx++ ;
344
- }
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
+ }
345
309
346
- // Replace the call to the dummy control point.
347
- OldCtrlPointCall->eraseFromParent ();
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
+ }
348
338
349
- // Generate new control point logic.
350
- createControlPoint (M, NF, LiveVals, CtrlPointReturnTy);
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
+ }
351
355
352
- return PreservedAnalyses::none ();
353
- }
356
+ // Replace the call to the dummy control point.
357
+ OldCtrlPointCall->eraseFromParent ();
358
+
359
+ // Generate new control point logic.
360
+ createControlPoint (M, NF, LiveVals, CtrlPointReturnTy, YkLocTy);
361
+ return true ;
362
+ }
363
+ };
364
+ } // namespace
365
+
366
+ char YkControlPoint::ID = 0 ;
367
+ INITIALIZE_PASS (YkControlPoint, DEBUG_TYPE, " yk control point" , false , false )
368
+
369
+ ModulePass *llvm::createYkControlPointPass() { return new YkControlPoint (); }
0 commit comments