4646// YKFIXME: The control point cannot yet be used in an interpreter using
4747// threaded dispatch.
4848//
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:
5051//
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 .
5354//
5455// - Tracing starts when we encounter a location for which we have no machine
5556// code. A hot counter should be used instead.
7879#include " llvm/IR/Function.h"
7980#include " llvm/IR/Instructions.h"
8081#include " llvm/IR/Module.h"
82+ #include " llvm/InitializePasses.h"
8183#include " llvm/Pass.h"
8284#include < llvm/IR/Dominators.h>
8385#include < llvm/IR/IRBuilder.h>
@@ -123,7 +125,7 @@ void createJITStatePrint(IRBuilder<> &Builder, Module *Mod, std::string Str) {
123125// / Generates the new control point, which includes all logic to start/stop
124126// / tracing and to compile/execute traces.
125127void createControlPoint (Module &Mod, Function *F, std::vector<Value *> LiveVars,
126- StructType *YkCtrlPointStruct) {
128+ StructType *YkCtrlPointStruct, Type *YkLocTy ) {
127129 auto &Context = Mod.getContext ();
128130
129131 // Create control point blocks and setup the IRBuilder.
@@ -166,9 +168,8 @@ void createControlPoint(Module &Mod, Function *F, std::vector<Value *> LiveVars,
166168 PtNull, " compiled_trace" , (GlobalVariable *)nullptr );
167169
168170 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 );
172173
173174 // Create control point entry block. Checks if we are currently tracing.
174175 Value *GVTracingVal = Builder.CreateLoad (Type::getInt8Ty (Context), GVTracing);
@@ -196,8 +197,7 @@ void createControlPoint(Module &Mod, Function *F, std::vector<Value *> LiveVars,
196197 // Create block that checks if we've reached the same location again so we
197198 // can execute a compiled trace.
198199 Builder.SetInsertPoint (BBHasTrace);
199- Value *ValStartLoc =
200- Builder.CreateLoad (Type::getInt32Ty (Context), GVStartLoc);
200+ Value *ValStartLoc = Builder.CreateLoad (YkLocTy, GVStartLoc);
201201 Value *ExecTraceCond = Builder.CreateICmp (CmpInst::Predicate::ICMP_EQ,
202202 ValStartLoc, F->getArg (0 ));
203203 Builder.CreateCondBr (ExecTraceCond, BBExecuteTrace, BBReturn);
@@ -220,8 +220,7 @@ void createControlPoint(Module &Mod, Function *F, std::vector<Value *> LiveVars,
220220
221221 // Create block that decides when to stop tracing.
222222 Builder.SetInsertPoint (BBTracing);
223- Value *ValStartLoc2 =
224- Builder.CreateLoad (Type::getInt32Ty (Context), GVStartLoc);
223+ Value *ValStartLoc2 = Builder.CreateLoad (YkLocTy, GVStartLoc);
225224 Value *StopTracingCond = Builder.CreateICmp (CmpInst::Predicate::ICMP_EQ,
226225 ValStartLoc2, F->getArg (0 ));
227226 Builder.CreateCondBr (StopTracingCond, BBStopTracing, BBReturn);
@@ -268,86 +267,103 @@ std::vector<Value *> getLiveVars(DominatorTree &DT, CallInst *OldCtrlPoint) {
268267 return Vec;
269268}
270269
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+ }
276273
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 ());
282280 }
283281
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 ();
300284
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+ }
328292
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+ }
345309
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+ }
348338
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+ }
351355
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