27
27
// size_t pc;
28
28
// }
29
29
//
30
+ // struct YkCtrlPointStruct cp_vars;
30
31
// pc = 0;
31
32
// while (...) {
32
- // struct YkCtrlPointStruct cp_in = { pc };
33
33
// // Now we call the patched control point.
34
- // YkCtrlPointStruct cp_out = yk_new_control_point(cp_in);
35
- // pc = cp_out.pc;
34
+ // cp_vars.pc = pc;
35
+ // yk_new_control_point(&cp_vars);
36
+ // pc = cp_vars.pc;
36
37
// bc = program[pc];
37
38
// switch (bc) {
38
39
// // bytecode handlers here.
39
40
// }
40
41
// }
41
42
// ```
42
43
//
43
- // The call to the dummy control point must be the first thing that appears in
44
- // an interpreter dispatch loop.
45
- //
46
- // YKFIXME: The control point cannot yet be used in an interpreter using
47
- // threaded dispatch.
48
- //
49
- // YKFIXME: The tracing logic is currently over-simplified. The following items
50
- // need to be fixed:
51
- //
52
- // - The address of `YkLocation` instances are used for identity, but they are
53
- // intended to be freely moved by the user.
54
- //
55
- // - Tracing starts when we encounter a location for which we have no machine
56
- // code. A hot counter should be used instead.
57
- //
58
- // - There can be only one compiled trace for now. There should be a code
59
- // cache mapping from JIT locations to their machine code.
60
- //
61
- // - The interpreter is assumed to be single threaded. We should implement a
62
- // synchronisation function in Rust code that synchronises many threads which
63
- // are calling the control point concurrently. This function should return a
64
- // value that indicates if we should start/stop tracing, or jump to machine
65
- // code etc.
66
- //
67
- // - Guards are currently assumed to abort the program.
68
- // https://github.com/ykjit/yk/issues/443
69
- //
70
- // - The block that performs the call to JITted code branches back to itself
71
- // to achieve rudimentary trace stitching. The looping should really be
72
- // implemented in the JITted code itself so that it isn't necessary to
73
- // repeatedly enter and exit the JITted code.
74
- // https://github.com/ykjit/yk/issues/442
75
- // ===----------------------------------------------------------------------===//
44
+ // Note that this transformation occurs at the LLVM IR level. The above example
45
+ // is shown as C code for easy comprehension.
76
46
77
47
#include " llvm/Transforms/Yk/ControlPoint.h"
78
48
#include " llvm/IR/BasicBlock.h"
88
58
#define DEBUG_TYPE " yk-control-point"
89
59
#define JIT_STATE_PREFIX " jit-state: "
90
60
91
- // These constants mirror `ykrt::mt::JITACTION_*`.
92
- const uintptr_t JITActionNop = 1 ;
93
- const uintptr_t JITActionStartTracing = 2 ;
94
- const uintptr_t JITActionStopTracing = 3 ;
95
-
96
61
using namespace llvm ;
97
62
98
63
// / Find the call to the dummy control point that we want to patch.
@@ -113,124 +78,6 @@ CallInst *findControlPointCall(Module &M) {
113
78
return cast<CallInst>(*U);
114
79
}
115
80
116
- // / Creates a call for printing debug information inside the control point.
117
- void createJITStatePrint (IRBuilder<> &Builder, Module *Mod, std::string Str) {
118
- if (std::getenv (" YKD_PRINT_JITSTATE" ) == nullptr )
119
- return ;
120
- LLVMContext &Context = Mod->getContext ();
121
- FunctionCallee Puts = Mod->getOrInsertFunction (
122
- " __yk_debug_print" ,
123
- FunctionType::get (Type::getVoidTy (Context),
124
- PointerType::get (Type::getInt8Ty (Context), 0 ), true ));
125
- Value *PutsString =
126
- Builder.CreateGlobalStringPtr (StringRef (JIT_STATE_PREFIX + Str));
127
- Builder.CreateCall (Puts, PutsString);
128
- }
129
-
130
- // / Generates the new control point, which includes all logic to start/stop
131
- // / tracing and to compile/execute traces.
132
- void createControlPoint (Module &Mod, Function *F, std::vector<Value *> LiveVars,
133
- StructType *YkCtrlPointStruct, Type *YkLocTy) {
134
- auto &Context = Mod.getContext ();
135
-
136
- // Create control point blocks and setup the IRBuilder.
137
- BasicBlock *CtrlPointEntry = BasicBlock::Create (Context, " cpentry" , F);
138
- BasicBlock *BBExecuteTrace = BasicBlock::Create (Context, " bbhexectrace" , F);
139
- BasicBlock *BBStartTracing = BasicBlock::Create (Context, " bbstarttracing" , F);
140
- BasicBlock *BBReturn = BasicBlock::Create (Context, " bbreturn" , F);
141
- BasicBlock *BBStopTracing = BasicBlock::Create (Context, " bbstoptracing" , F);
142
-
143
- // Get the type for a pointer-sized integer.
144
- DataLayout DL (&Mod);
145
- unsigned PtrBitSize = DL.getPointerSize () * 8 ;
146
- IntegerType *PtrSizedInteger = IntegerType::getIntNTy (Context, PtrBitSize);
147
-
148
- // Some frequently used constants.
149
- ConstantInt *JActNop = ConstantInt::get (PtrSizedInteger, JITActionNop);
150
- ConstantInt *JActStartTracing =
151
- ConstantInt::get (PtrSizedInteger, JITActionStartTracing);
152
- ConstantInt *JActStopTracing =
153
- ConstantInt::get (PtrSizedInteger, JITActionStopTracing);
154
-
155
- // Add definitions for __yk functions.
156
- Function *FuncTransLoc = llvm::Function::Create (
157
- FunctionType::get (PtrSizedInteger, {Type::getInt8PtrTy (Context)}, false ),
158
- GlobalValue::ExternalLinkage, " __ykrt_transition_location" , Mod);
159
-
160
- Function *FuncSetCodePtr = llvm::Function::Create (
161
- FunctionType::get (
162
- Type::getVoidTy (Context),
163
- {Type::getInt8PtrTy (Context), Type::getInt8PtrTy (Context)}, false ),
164
- GlobalValue::ExternalLinkage, " __ykrt_set_loc_code_ptr" , Mod);
165
-
166
- Function *FuncStartTracing = llvm::Function::Create (
167
- FunctionType::get (Type::getVoidTy (Context), {Type::getInt64Ty (Context)},
168
- false ),
169
- GlobalValue::ExternalLinkage, " __yktrace_start_tracing" , Mod);
170
-
171
- Function *FuncStopTracing = llvm::Function::Create (
172
- FunctionType::get (Type::getInt8PtrTy (Context), {}, false ),
173
- GlobalValue::ExternalLinkage, " __yktrace_stop_tracing" , Mod);
174
-
175
- Function *FuncCompileTrace = llvm::Function::Create (
176
- FunctionType::get (Type::getInt8PtrTy (Context),
177
- {Type::getInt8PtrTy (Context)}, false ),
178
- GlobalValue::ExternalLinkage, " __yktrace_irtrace_compile" , Mod);
179
-
180
- // Populate the entry block. This calls `__ykrt_transition_location()` to
181
- // decide what to do next.
182
- IRBuilder<> Builder (CtrlPointEntry);
183
- Value *CastLoc =
184
- Builder.CreateBitCast (F->getArg (0 ), Type::getInt8PtrTy (Context));
185
- Value *JITAction = Builder.CreateCall (FuncTransLoc->getFunctionType (),
186
- FuncTransLoc, {CastLoc});
187
- SwitchInst *ActionSw = Builder.CreateSwitch (JITAction, BBExecuteTrace, 3 );
188
- ActionSw->addCase (JActNop, BBReturn);
189
- ActionSw->addCase (JActStartTracing, BBStartTracing);
190
- ActionSw->addCase (JActStopTracing, BBStopTracing);
191
-
192
- // Populate the block that starts tracing.
193
- Builder.SetInsertPoint (BBStartTracing);
194
- createJITStatePrint (Builder, &Mod, " start-tracing" );
195
- Builder.CreateCall (FuncStartTracing->getFunctionType (), FuncStartTracing,
196
- {ConstantInt::get (Context, APInt (64 , 1 ))});
197
- Builder.CreateBr (BBReturn);
198
-
199
- // Populate the block that calls a compiled trace. If execution gets into
200
- // this block then `JITAction` is a pointer to a compiled trace.
201
- Builder.SetInsertPoint (BBExecuteTrace);
202
- std::vector<Type *> TypeParams;
203
- for (Value *LV : LiveVars) {
204
- TypeParams.push_back (LV->getType ());
205
- }
206
- FunctionType *FType = FunctionType::get (
207
- Type::getVoidTy (Context), {YkCtrlPointStruct->getPointerTo ()}, false );
208
- Value *JITActionPtr =
209
- Builder.CreateIntToPtr (JITAction, Type::getInt8PtrTy (Context));
210
- Value *CastTrace = Builder.CreateBitCast (JITActionPtr, FType->getPointerTo ());
211
- createJITStatePrint (Builder, &Mod, " enter-jit-code" );
212
- CallInst *CTResult = Builder.CreateCall (FType, CastTrace, F->getArg (1 ));
213
- createJITStatePrint (Builder, &Mod, " exit-jit-code" );
214
- CTResult->setTailCall (true );
215
- Builder.CreateBr (BBExecuteTrace);
216
-
217
- // Create block that stops tracing, compiles a trace, and stores it in a
218
- // global variable.
219
- Builder.SetInsertPoint (BBStopTracing);
220
- Value *TR =
221
- Builder.CreateCall (FuncStopTracing->getFunctionType (), FuncStopTracing);
222
- Value *CT = Builder.CreateCall (FuncCompileTrace->getFunctionType (),
223
- FuncCompileTrace, {TR});
224
- Builder.CreateCall (FuncSetCodePtr->getFunctionType (), FuncSetCodePtr,
225
- {CastLoc, CT});
226
- createJITStatePrint (Builder, &Mod, " stop-tracing" );
227
- Builder.CreateBr (BBReturn);
228
-
229
- // Populate the return block.
230
- Builder.SetInsertPoint (BBReturn);
231
- Builder.CreateRetVoid ();
232
- }
233
-
234
81
// / Extract all live variables that need to be passed into the control point.
235
82
std::vector<Value *> getLiveVars (DominatorTree &DT, CallInst *OldCtrlPoint) {
236
83
std::vector<Value *> Vec;
@@ -347,7 +194,6 @@ class YkControlPoint : public ModulePass {
347
194
OldCtrlPointCall->eraseFromParent ();
348
195
349
196
// Generate new control point logic.
350
- createControlPoint (M, NF, LiveVals, CtrlPointVarsTy, YkLocTy);
351
197
return true ;
352
198
}
353
199
};
0 commit comments