Skip to content

Commit dc44b12

Browse files
committed
There is no need to generate parts of the control point in IR now.
Since we are now passing the control point's live variables about via opaque pointer, there is no need for the control point internals to have explicit knowledge about the shape of the live variables struct. This means that all of the control point internals can now be normal Rust code, as implemented in: ykjit/yk#454
1 parent 64af73c commit dc44b12

File tree

2 files changed

+7
-161
lines changed

2 files changed

+7
-161
lines changed

llvm/include/llvm/Transforms/Yk/ControlPoint.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#define YK_DUMMY_CONTROL_POINT "yk_control_point"
99

1010
// The name of the new control point replacing the user's dummy control point.
11-
#define YK_NEW_CONTROL_POINT "yk_new_control_point"
11+
#define YK_NEW_CONTROL_POINT "__ykrt_control_point"
1212

1313
namespace llvm {
1414
ModulePass *createYkControlPointPass();

llvm/lib/Transforms/Yk/ControlPoint.cpp

Lines changed: 6 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -27,52 +27,22 @@
2727
// size_t pc;
2828
// }
2929
//
30+
// struct YkCtrlPointStruct cp_vars;
3031
// pc = 0;
3132
// while (...) {
32-
// struct YkCtrlPointStruct cp_in = { pc };
3333
// // 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;
3637
// bc = program[pc];
3738
// switch (bc) {
3839
// // bytecode handlers here.
3940
// }
4041
// }
4142
// ```
4243
//
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.
7646

7747
#include "llvm/Transforms/Yk/ControlPoint.h"
7848
#include "llvm/IR/BasicBlock.h"
@@ -88,11 +58,6 @@
8858
#define DEBUG_TYPE "yk-control-point"
8959
#define JIT_STATE_PREFIX "jit-state: "
9060

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-
9661
using namespace llvm;
9762

9863
/// Find the call to the dummy control point that we want to patch.
@@ -113,124 +78,6 @@ CallInst *findControlPointCall(Module &M) {
11378
return cast<CallInst>(*U);
11479
}
11580

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-
23481
/// Extract all live variables that need to be passed into the control point.
23582
std::vector<Value *> getLiveVars(DominatorTree &DT, CallInst *OldCtrlPoint) {
23683
std::vector<Value *> Vec;
@@ -347,7 +194,6 @@ class YkControlPoint : public ModulePass {
347194
OldCtrlPointCall->eraseFromParent();
348195

349196
// Generate new control point logic.
350-
createControlPoint(M, NF, LiveVals, CtrlPointVarsTy, YkLocTy);
351197
return true;
352198
}
353199
};

0 commit comments

Comments
 (0)