Skip to content
This repository was archived by the owner on Sep 27, 2019. It is now read-only.

Commit e4fa959

Browse files
committed
Move state init flag to the end of the struct for byte-alignment
1 parent 5ba478e commit e4fa959

File tree

2 files changed

+49
-29
lines changed

2 files changed

+49
-29
lines changed

src/codegen/pipeline.cpp

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,11 @@ namespace codegen {
3131

3232
PipelineContext::PipelineContext(Pipeline &pipeline)
3333
: pipeline_(pipeline),
34+
init_flag_id_(0),
3435
thread_state_type_(nullptr),
3536
thread_state_(nullptr),
3637
thread_init_func_(nullptr),
37-
pipeline_func_(nullptr) {
38-
// Make room for the bool flag indicating validity
39-
CodeGen &codegen = pipeline.GetCompilationContext().GetCodeGen();
40-
state_components_.emplace_back("initialized", codegen.BoolType());
41-
}
38+
pipeline_func_(nullptr) {}
4239

4340
PipelineContext::Id PipelineContext::RegisterState(std::string name,
4441
llvm::Type *type) {
@@ -59,6 +56,9 @@ void PipelineContext::FinalizeState(CodeGen &codegen) {
5956
return;
6057
}
6158

59+
// Tag on the initialization flag at the end
60+
init_flag_id_ = RegisterState("initialized", codegen.BoolType());
61+
6262
// Pull out types
6363
std::vector<llvm::Type *> types;
6464
for (const auto &slot_info : state_components_) {
@@ -77,13 +77,13 @@ llvm::Value *PipelineContext::AccessThreadState(
7777
}
7878

7979
llvm::Value *PipelineContext::LoadFlag(CodeGen &codegen) const {
80-
return LoadState(codegen, kFlagOffset);
80+
return LoadState(codegen, init_flag_id_);
8181
}
8282

8383
void PipelineContext::StoreFlag(CodeGen &codegen, llvm::Value *flag) const {
8484
PL_ASSERT(flag->getType()->isIntegerTy(1) &&
8585
flag->getType() == codegen.BoolType());
86-
auto *flag_ptr = LoadStatePtr(codegen, kFlagOffset);
86+
auto *flag_ptr = LoadStatePtr(codegen, init_flag_id_);
8787
codegen->CreateStore(flag, flag_ptr);
8888
}
8989

@@ -455,7 +455,7 @@ void Pipeline::DoRun(
455455

456456
// If the pipeline is parallel, we need to call the generated init function
457457
if (IsParallel()) {
458-
thread_state = codegen->CreateBitOrPointerCast(
458+
thread_state = codegen->CreatePointerCast(
459459
thread_state, pipeline_context.GetThreadStateType()->getPointerTo());
460460

461461
auto *init_func = pipeline_context.thread_init_func_;
@@ -485,33 +485,45 @@ void Pipeline::DoRun(
485485
}
486486
pipeline_context.pipeline_func_ = func.GetFunction();
487487

488-
// The launch argument starts with QueryState and ThreadState. We pass in
489-
// NULL for serial execution pipelines.
490-
std::vector<llvm::Value *> new_dispatch_args = {codegen.GetState()};
488+
// The pipeline function we generated above encapsulates the logic for all
489+
// operators in the pipeline. If we're executing it serially then we directly
490+
// invoke the function now. If the pipeline is run in parallel then a dispatch
491+
// function must have been provided. Either way, we need to setup the call
492+
// now.
493+
//
494+
// In both cases, the pipeline function expects QueryState and ThreadState
495+
// pointers are the first two arguments. When run serially, we pass in a NULL
496+
// thread state pointer. When running in parallel (through a dispatch
497+
// function), we need to convert the QueryState type to a void * because it is
498+
// a runtime generated type (i.e., pre-compiled code doesn't know the layout
499+
// since it's dynamic)
500+
//
501+
// After this, the next arguments are whatever the caller provided to use.
502+
//
503+
// Finally, if the pipeline is run through a dispatcher function, the last
504+
// argument is a function pointer to the pipeline function we generated.
505+
506+
std::vector<llvm::Value *> invoke_args = {codegen.GetState()};
491507
if (IsParallel()) {
492508
auto &consumer = compilation_ctx_.GetExecutionConsumer();
493-
new_dispatch_args.push_back(consumer.GetThreadStatesPtr(compilation_ctx_));
509+
invoke_args.push_back(consumer.GetThreadStatesPtr(compilation_ctx_));
494510
} else {
495-
new_dispatch_args.push_back(codegen.NullPtr(codegen.CharPtrType()));
511+
invoke_args.push_back(codegen.NullPtr(codegen.CharPtrType()));
496512
}
497513

498-
// Now insert the arguments the caller wants
499-
new_dispatch_args.insert(new_dispatch_args.end(), dispatch_args.begin(),
500-
dispatch_args.end());
514+
invoke_args.insert(invoke_args.end(), dispatch_args.begin(),
515+
dispatch_args.end());
516+
501517
if (dispatch_func != nullptr) {
502-
// If we have a launch function, we need to cast the QueryState parameter
503-
// to a void*. This is because it is a JITed data-structure which
504-
// pre-compiled code has no notion of.
505-
//
506-
// We also append the pipeline function to the end of the arguments
507-
new_dispatch_args[0] = codegen->CreateBitOrPointerCast(
508-
new_dispatch_args[0], codegen.VoidPtrType());
509-
new_dispatch_args.push_back(
518+
// Convert QueryState to void *
519+
invoke_args[0] =
520+
codegen->CreateBitOrPointerCast(invoke_args[0], codegen.VoidPtrType());
521+
// Tag on the pipeline function
522+
invoke_args.push_back(
510523
codegen->CreateBitCast(func.GetFunction(), codegen.VoidPtrType()));
511-
codegen.CallFunc(dispatch_func, new_dispatch_args);
524+
codegen.CallFunc(dispatch_func, invoke_args);
512525
} else {
513-
// Immediately invoke the pipeline function
514-
codegen.CallFunc(func.GetFunction(), new_dispatch_args);
526+
codegen.CallFunc(func.GetFunction(), invoke_args);
515527
}
516528
}
517529

src/include/codegen/pipeline.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ class Pipeline;
3737
class PipelineContext {
3838
friend class Pipeline;
3939

40-
static const uint32_t kFlagOffset = 0;
41-
4240
public:
4341
using Id = uint32_t;
4442

@@ -94,10 +92,20 @@ class PipelineContext {
9492
private:
9593
// The pipeline
9694
Pipeline &pipeline_;
95+
96+
// The ID of the "initialized" flag in the thread state indicating if a
97+
// particular thread has initialized all state required for the pipeline
98+
Id init_flag_id_;
99+
97100
// The elements of the thread state for this pipeline
98101
std::vector<std::pair<std::string, llvm::Type *>> state_components_;
102+
103+
// The finalized LLVM type of the thread state
99104
llvm::Type *thread_state_type_;
105+
106+
// A runtime pointer to the current thread's state in the pipeline
100107
llvm::Value *thread_state_;
108+
101109
// The generate thread initialization function and pipeline function
102110
llvm::Function *thread_init_func_;
103111
llvm::Function *pipeline_func_;

0 commit comments

Comments
 (0)