Skip to content

Commit 3d636b0

Browse files
bors[bot]vext01
andauthored
13: Make the control point accept a `ykrt::Location` instead of an integer. r=ltratt a=vext01 Co-authored-by: Edd Barrett <[email protected]>
2 parents dfa2d98 + d72a8ea commit 3d636b0

File tree

5 files changed

+126
-104
lines changed

5 files changed

+126
-104
lines changed

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,7 @@
1111
#define YK_NEW_CONTROL_POINT "yk_new_control_point"
1212

1313
namespace llvm {
14-
class YkControlPointPass : public PassInfoMixin<YkControlPointPass> {
15-
public:
16-
explicit YkControlPointPass();
17-
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
18-
};
14+
ModulePass *createYkControlPointPass();
1915
} // namespace llvm
2016

2117
#endif

llvm/lib/CodeGen/TargetPassConfig.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include "llvm/Transforms/Utils.h"
5050
#include "llvm/Transforms/Utils/SymbolRewriter.h"
5151
#include "llvm/Transforms/Yk/BlockDisambiguate.h"
52+
#include "llvm/Transforms/Yk/ControlPoint.h"
5253
#include <cassert>
5354
#include <string>
5455

@@ -243,6 +244,11 @@ static cl::opt<bool> YkBlockDisambiguate(
243244
"yk-block-disambiguate", cl::init(false), cl::NotHidden,
244245
cl::desc("Disambiguate blocks for yk"));
245246

247+
static cl::opt<bool>
248+
YkPatchCtrlPoint("yk-patch-control-point",
249+
cl::init(false), cl::NotHidden,
250+
cl::desc("Patch yk_control_point()"));
251+
246252
/// Allow standard passes to be disabled by command line options. This supports
247253
/// simple binary flags that either suppress the pass or do nothing.
248254
/// i.e. -disable-mypass=false has no effect.
@@ -1067,8 +1073,22 @@ bool TargetPassConfig::addISelPasses() {
10671073
addPassesToHandleExceptions();
10681074
if (YkBlockDisambiguate)
10691075
addPass(createYkBlockDisambiguatePass());
1070-
addISelPrepare();
10711076

1077+
// We insert the yk control point pass as late as possible. It has to run
1078+
// before instruction selection (or the machine IR won't reflect our
1079+
// patching), but after other passes which mutate the IR (e.g.
1080+
// `CodegenPrepare` above).
1081+
//
1082+
// By running the pass late, we also ensure that no IR optimisation passes
1083+
// ever see our patched-in control point function. If optimisations were to
1084+
// be applied then this would be problematic as the interface to the control
1085+
// point could be changed, e.g. the control point's struct argument could be
1086+
// decomposed into scalar arguments. The JIT runtime relies on the interface
1087+
// *not* being changed.
1088+
if (YkPatchCtrlPoint)
1089+
addPass(createYkControlPointPass());
1090+
1091+
addISelPrepare();
10721092
return addCoreISelPasses();
10731093
}
10741094

llvm/lib/LTO/LTOBackend.cpp

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,6 @@ static cl::opt<bool> ThinLTOAssumeMerged(
7575
cl::desc("Assume the input has already undergone ThinLTO function "
7676
"importing and the other pre-optimization pipeline changes."));
7777

78-
static cl::opt<bool>
79-
YkPatchCtrlPoint("yk-patch-control-point",
80-
cl::init(false), cl::NotHidden,
81-
cl::desc("Patch yk_control_point()"));
82-
8378
LLVM_ATTRIBUTE_NORETURN static void reportOpenError(StringRef Path, Twine Msg) {
8479
errs() << "failed to open " << Path << ": " << Msg << '\n';
8580
errs().flush();
@@ -306,13 +301,6 @@ static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM,
306301
MPM.addPass(PB.buildLTODefaultPipeline(OL, ExportSummary));
307302
}
308303

309-
// We add the yk control point pass late in the pipeline (after all
310-
// optimisation and just before verification and codegen) so that no IR
311-
// optimisation passes have a chance to change the interface to the control
312-
// point. The JIT runtime relies on the signature not being changed.
313-
if (YkPatchCtrlPoint)
314-
MPM.addPass(YkControlPointPass());
315-
316304
if (!Conf.DisableVerify)
317305
MPM.addPass(VerifierPass());
318306

llvm/lib/Transforms/Yk/BlockDisambiguate.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ class YkBlockDisambiguate : public ModulePass {
204204
if (SuccBB == &BB) {
205205
BasicBlock *DBB = makeDisambiguationBB(Context, &BB, NewBBs);
206206
BI->setSuccessor(SuccIdx, DBB);
207+
BB.replacePhiUsesWith(&BB, DBB);
207208
}
208209
}
209210
} else if (isa<SwitchInst>(TI)) {
@@ -214,6 +215,7 @@ class YkBlockDisambiguate : public ModulePass {
214215
if (SuccBB == &BB) {
215216
BasicBlock *DBB = makeDisambiguationBB(Context, &BB, NewBBs);
216217
SI->setSuccessor(SuccIdx, DBB);
218+
BB.replacePhiUsesWith(&BB, DBB);
217219
}
218220
}
219221
}

llvm/lib/Transforms/Yk/ControlPoint.cpp

Lines changed: 102 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,11 @@
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.
@@ -78,6 +79,7 @@
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.
125127
void 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

Comments
 (0)