From dc44b12f928c1c5e17f687a778e00636ef5632f8 Mon Sep 17 00:00:00 2001 From: Edd Barrett Date: Fri, 17 Dec 2021 16:19:05 +0000 Subject: [PATCH] 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: https://github.com/ykjit/yk/pull/454 --- .../include/llvm/Transforms/Yk/ControlPoint.h | 2 +- llvm/lib/Transforms/Yk/ControlPoint.cpp | 166 +----------------- 2 files changed, 7 insertions(+), 161 deletions(-) diff --git a/llvm/include/llvm/Transforms/Yk/ControlPoint.h b/llvm/include/llvm/Transforms/Yk/ControlPoint.h index d89df59266c04..4c3ebf363b913 100644 --- a/llvm/include/llvm/Transforms/Yk/ControlPoint.h +++ b/llvm/include/llvm/Transforms/Yk/ControlPoint.h @@ -8,7 +8,7 @@ #define YK_DUMMY_CONTROL_POINT "yk_control_point" // The name of the new control point replacing the user's dummy control point. -#define YK_NEW_CONTROL_POINT "yk_new_control_point" +#define YK_NEW_CONTROL_POINT "__ykrt_control_point" namespace llvm { ModulePass *createYkControlPointPass(); diff --git a/llvm/lib/Transforms/Yk/ControlPoint.cpp b/llvm/lib/Transforms/Yk/ControlPoint.cpp index a4e694e0bc4a3..033bc495b8123 100644 --- a/llvm/lib/Transforms/Yk/ControlPoint.cpp +++ b/llvm/lib/Transforms/Yk/ControlPoint.cpp @@ -27,12 +27,13 @@ // size_t pc; // } // +// struct YkCtrlPointStruct cp_vars; // pc = 0; // while (...) { -// struct YkCtrlPointStruct cp_in = { pc }; // // Now we call the patched control point. -// YkCtrlPointStruct cp_out = yk_new_control_point(cp_in); -// pc = cp_out.pc; +// cp_vars.pc = pc; +// yk_new_control_point(&cp_vars); +// pc = cp_vars.pc; // bc = program[pc]; // switch (bc) { // // bytecode handlers here. @@ -40,39 +41,8 @@ // } // ``` // -// The call to the dummy control point must be the first thing that appears in -// an interpreter dispatch loop. -// -// YKFIXME: The control point cannot yet be used in an interpreter using -// threaded dispatch. -// -// YKFIXME: The tracing logic is currently over-simplified. The following items -// need to be fixed: -// -// - The address of `YkLocation` instances are used for identity, but they are -// intended to be freely moved by the user. -// -// - Tracing starts when we encounter a location for which we have no machine -// code. A hot counter should be used instead. -// -// - There can be only one compiled trace for now. There should be a code -// cache mapping from JIT locations to their machine code. -// -// - The interpreter is assumed to be single threaded. We should implement a -// synchronisation function in Rust code that synchronises many threads which -// are calling the control point concurrently. This function should return a -// value that indicates if we should start/stop tracing, or jump to machine -// code etc. -// -// - Guards are currently assumed to abort the program. -// https://github.com/ykjit/yk/issues/443 -// -// - The block that performs the call to JITted code branches back to itself -// to achieve rudimentary trace stitching. The looping should really be -// implemented in the JITted code itself so that it isn't necessary to -// repeatedly enter and exit the JITted code. -// https://github.com/ykjit/yk/issues/442 -//===----------------------------------------------------------------------===// +// Note that this transformation occurs at the LLVM IR level. The above example +// is shown as C code for easy comprehension. #include "llvm/Transforms/Yk/ControlPoint.h" #include "llvm/IR/BasicBlock.h" @@ -88,11 +58,6 @@ #define DEBUG_TYPE "yk-control-point" #define JIT_STATE_PREFIX "jit-state: " -// These constants mirror `ykrt::mt::JITACTION_*`. -const uintptr_t JITActionNop = 1; -const uintptr_t JITActionStartTracing = 2; -const uintptr_t JITActionStopTracing = 3; - using namespace llvm; /// Find the call to the dummy control point that we want to patch. @@ -113,124 +78,6 @@ CallInst *findControlPointCall(Module &M) { return cast(*U); } -/// Creates a call for printing debug information inside the control point. -void createJITStatePrint(IRBuilder<> &Builder, Module *Mod, std::string Str) { - if (std::getenv("YKD_PRINT_JITSTATE") == nullptr) - return; - LLVMContext &Context = Mod->getContext(); - FunctionCallee Puts = Mod->getOrInsertFunction( - "__yk_debug_print", - FunctionType::get(Type::getVoidTy(Context), - PointerType::get(Type::getInt8Ty(Context), 0), true)); - Value *PutsString = - Builder.CreateGlobalStringPtr(StringRef(JIT_STATE_PREFIX + Str)); - Builder.CreateCall(Puts, PutsString); -} - -/// Generates the new control point, which includes all logic to start/stop -/// tracing and to compile/execute traces. -void createControlPoint(Module &Mod, Function *F, std::vector LiveVars, - StructType *YkCtrlPointStruct, Type *YkLocTy) { - auto &Context = Mod.getContext(); - - // Create control point blocks and setup the IRBuilder. - BasicBlock *CtrlPointEntry = BasicBlock::Create(Context, "cpentry", F); - BasicBlock *BBExecuteTrace = BasicBlock::Create(Context, "bbhexectrace", F); - BasicBlock *BBStartTracing = BasicBlock::Create(Context, "bbstarttracing", F); - BasicBlock *BBReturn = BasicBlock::Create(Context, "bbreturn", F); - BasicBlock *BBStopTracing = BasicBlock::Create(Context, "bbstoptracing", F); - - // Get the type for a pointer-sized integer. - DataLayout DL(&Mod); - unsigned PtrBitSize = DL.getPointerSize() * 8; - IntegerType *PtrSizedInteger = IntegerType::getIntNTy(Context, PtrBitSize); - - // Some frequently used constants. - ConstantInt *JActNop = ConstantInt::get(PtrSizedInteger, JITActionNop); - ConstantInt *JActStartTracing = - ConstantInt::get(PtrSizedInteger, JITActionStartTracing); - ConstantInt *JActStopTracing = - ConstantInt::get(PtrSizedInteger, JITActionStopTracing); - - // Add definitions for __yk functions. - Function *FuncTransLoc = llvm::Function::Create( - FunctionType::get(PtrSizedInteger, {Type::getInt8PtrTy(Context)}, false), - GlobalValue::ExternalLinkage, "__ykrt_transition_location", Mod); - - Function *FuncSetCodePtr = llvm::Function::Create( - FunctionType::get( - Type::getVoidTy(Context), - {Type::getInt8PtrTy(Context), Type::getInt8PtrTy(Context)}, false), - GlobalValue::ExternalLinkage, "__ykrt_set_loc_code_ptr", Mod); - - Function *FuncStartTracing = llvm::Function::Create( - FunctionType::get(Type::getVoidTy(Context), {Type::getInt64Ty(Context)}, - false), - GlobalValue::ExternalLinkage, "__yktrace_start_tracing", Mod); - - Function *FuncStopTracing = llvm::Function::Create( - FunctionType::get(Type::getInt8PtrTy(Context), {}, false), - GlobalValue::ExternalLinkage, "__yktrace_stop_tracing", Mod); - - Function *FuncCompileTrace = llvm::Function::Create( - FunctionType::get(Type::getInt8PtrTy(Context), - {Type::getInt8PtrTy(Context)}, false), - GlobalValue::ExternalLinkage, "__yktrace_irtrace_compile", Mod); - - // Populate the entry block. This calls `__ykrt_transition_location()` to - // decide what to do next. - IRBuilder<> Builder(CtrlPointEntry); - Value *CastLoc = - Builder.CreateBitCast(F->getArg(0), Type::getInt8PtrTy(Context)); - Value *JITAction = Builder.CreateCall(FuncTransLoc->getFunctionType(), - FuncTransLoc, {CastLoc}); - SwitchInst *ActionSw = Builder.CreateSwitch(JITAction, BBExecuteTrace, 3); - ActionSw->addCase(JActNop, BBReturn); - ActionSw->addCase(JActStartTracing, BBStartTracing); - ActionSw->addCase(JActStopTracing, BBStopTracing); - - // Populate the block that starts tracing. - Builder.SetInsertPoint(BBStartTracing); - createJITStatePrint(Builder, &Mod, "start-tracing"); - Builder.CreateCall(FuncStartTracing->getFunctionType(), FuncStartTracing, - {ConstantInt::get(Context, APInt(64, 1))}); - Builder.CreateBr(BBReturn); - - // Populate the block that calls a compiled trace. If execution gets into - // this block then `JITAction` is a pointer to a compiled trace. - Builder.SetInsertPoint(BBExecuteTrace); - std::vector TypeParams; - for (Value *LV : LiveVars) { - TypeParams.push_back(LV->getType()); - } - FunctionType *FType = FunctionType::get( - Type::getVoidTy(Context), {YkCtrlPointStruct->getPointerTo()}, false); - Value *JITActionPtr = - Builder.CreateIntToPtr(JITAction, Type::getInt8PtrTy(Context)); - Value *CastTrace = Builder.CreateBitCast(JITActionPtr, FType->getPointerTo()); - createJITStatePrint(Builder, &Mod, "enter-jit-code"); - CallInst *CTResult = Builder.CreateCall(FType, CastTrace, F->getArg(1)); - createJITStatePrint(Builder, &Mod, "exit-jit-code"); - CTResult->setTailCall(true); - Builder.CreateBr(BBExecuteTrace); - - // Create block that stops tracing, compiles a trace, and stores it in a - // global variable. - Builder.SetInsertPoint(BBStopTracing); - Value *TR = - Builder.CreateCall(FuncStopTracing->getFunctionType(), FuncStopTracing); - Value *CT = Builder.CreateCall(FuncCompileTrace->getFunctionType(), - FuncCompileTrace, {TR}); - Builder.CreateCall(FuncSetCodePtr->getFunctionType(), FuncSetCodePtr, - {CastLoc, CT}); - createJITStatePrint(Builder, &Mod, "stop-tracing"); - Builder.CreateBr(BBReturn); - - // Populate the return block. - Builder.SetInsertPoint(BBReturn); - Builder.CreateRetVoid(); -} - /// Extract all live variables that need to be passed into the control point. std::vector getLiveVars(DominatorTree &DT, CallInst *OldCtrlPoint) { std::vector Vec; @@ -347,7 +194,6 @@ class YkControlPoint : public ModulePass { OldCtrlPointCall->eraseFromParent(); // Generate new control point logic. - createControlPoint(M, NF, LiveVals, CtrlPointVarsTy, YkLocTy); return true; } };