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

Commit 1de8979

Browse files
authored
Support limit, offset, top-k serial and parallel versions in codegen (#1435)
* Initial limit commit * Cleanup OrderByPlan * Don't use SQL types for the result of the comparison when sorting * Sorting for Top-K works. Probably slow. * Optimize pop-then-push into single operation * Fix lang::If to allow injection of custom then and else blocks * Added early exit block to consumer context to allow operators to quick exit * More comments * Fast-exit limits * Cleanup comments. Enabled parallel sorting. * Fixed bytecode compilation. Added explicit call handlers for sorter to bytecode builder. Fixed parallel sorting top-k * Set limit and offset to 0 when no limit/offset provided * Fix offset * Fix sort test in optimize to have well-defined order (some sort values were equal producing non-deterministic outputs). Fixed order by translator test to push a limit plan on top. This wasn't there before because we didn't need a limit * Cleanup * Fix limit without order-by clause
1 parent 91c082d commit 1de8979

35 files changed

+1629
-441
lines changed

src/codegen/aggregation.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ void Aggregation::DoNullCheck(
417417
default: { break; }
418418
}
419419
}
420-
agg_is_null.ElseBlock("Agg.IfAggIsNotNull");
420+
agg_is_null.ElseBlock();
421421
{
422422
// (1)
423423
DoAdvanceValue(codegen, space, type, storage_index, update);

src/codegen/code_context.cpp

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,8 @@ namespace {
4343

4444
class PelotonMemoryManager : public llvm::SectionMemoryManager {
4545
public:
46-
explicit PelotonMemoryManager(
47-
const std::unordered_map<std::string,
48-
std::pair<llvm::Function *, CodeContext::FuncPtr>> &builtins)
46+
explicit PelotonMemoryManager(const std::unordered_map<
47+
std::string, std::pair<llvm::Function *, CodeContext::FuncPtr>> &builtins)
4948
: builtins_(builtins) {}
5049

5150
#if LLVM_VERSION_GE(4, 0)
@@ -93,8 +92,8 @@ class PelotonMemoryManager : public llvm::SectionMemoryManager {
9392
private:
9493
// The code context
9594
const std::unordered_map<std::string,
96-
std::pair<llvm::Function *, CodeContext::FuncPtr>>
97-
&builtins_;
95+
std::pair<llvm::Function *, CodeContext::FuncPtr>> &
96+
builtins_;
9897
};
9998

10099
////////////////////////////////////////////////////////////////////////////////
@@ -143,9 +142,9 @@ class InstructionCounts : public llvm::ModulePass {
143142

144143
void DumpStats() const {
145144
LOG_INFO("# functions: %" PRId64 " (%" PRId64
146-
" external), # blocks: %" PRId64 ", # instructions: %" PRId64,
147-
func_count_, external_func_count_, basic_block_count_,
148-
total_inst_counts_);
145+
" external), # blocks: %" PRId64 ", # instructions: %" PRId64,
146+
func_count_, external_func_count_, basic_block_count_,
147+
total_inst_counts_);
149148
for (const auto iter : counts_) {
150149
const char *inst_name = llvm::Instruction::getOpcodeName(iter.first);
151150
LOG_INFO("↳ %s: %" PRId64, inst_name, iter.second);
@@ -198,13 +197,13 @@ CodeContext::CodeContext()
198197
// references etc.
199198
std::unique_ptr<llvm::Module> m{module_};
200199
module_ = m.get();
201-
engine_.reset(
202-
llvm::EngineBuilder(std::move(m))
203-
.setEngineKind(llvm::EngineKind::JIT)
204-
.setMCJITMemoryManager(llvm::make_unique<PelotonMemoryManager>(builtins_))
205-
.setMCPU(llvm::sys::getHostCPUName())
206-
.setErrorStr(&err_str_)
207-
.create());
200+
engine_.reset(llvm::EngineBuilder(std::move(m))
201+
.setEngineKind(llvm::EngineKind::JIT)
202+
.setMCJITMemoryManager(
203+
llvm::make_unique<PelotonMemoryManager>(builtins_))
204+
.setMCPU(llvm::sys::getHostCPUName())
205+
.setErrorStr(&err_str_)
206+
.create());
208207
PELOTON_ASSERT(engine_ != nullptr);
209208

210209
// The set of optimization passes we include
@@ -272,9 +271,13 @@ void CodeContext::RegisterBuiltin(llvm::Function *func_decl,
272271
builtins_[name] = std::make_pair(func_decl, func_impl);
273272
}
274273

275-
std::pair<llvm::Function *, CodeContext::FuncPtr> CodeContext::LookupBuiltin(const std::string &name) const {
274+
std::pair<llvm::Function *, CodeContext::FuncPtr> CodeContext::LookupBuiltin(
275+
const std::string &name) const {
276276
auto iter = builtins_.find(name);
277-
return (iter == builtins_.end() ? std::make_pair<llvm::Function *, CodeContext::FuncPtr>(nullptr, nullptr) : iter->second);
277+
return (iter == builtins_.end()
278+
? std::make_pair<llvm::Function *, CodeContext::FuncPtr>(nullptr,
279+
nullptr)
280+
: iter->second);
278281
}
279282

280283
/// Verify all the functions that were created in this context
@@ -328,7 +331,6 @@ void CodeContext::Compile() {
328331
}
329332

330333
// Log the module
331-
LOG_TRACE("%s\n", GetIR().c_str());
332334
if (settings::SettingsManager::GetBool(settings::SettingId::dump_ir)) {
333335
LOG_DEBUG("%s\n", GetIR().c_str());
334336
}
@@ -351,7 +353,8 @@ size_t CodeContext::GetTypeAllocSizeInBits(llvm::Type *type) const {
351353
return GetDataLayout().getTypeAllocSizeInBits(type);
352354
}
353355

354-
size_t CodeContext::GetStructElementOffset(llvm::StructType *type, size_t index) const {
356+
size_t CodeContext::GetStructElementOffset(llvm::StructType *type,
357+
size_t index) const {
355358
return GetDataLayout().getStructLayout(type)->getElementOffset(index);
356359
}
357360

src/codegen/consumer_context.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,16 @@ namespace codegen {
2020
// Constructor
2121
ConsumerContext::ConsumerContext(CompilationContext &compilation_context,
2222
Pipeline &pipeline)
23-
: ConsumerContext(compilation_context, pipeline, nullptr) {}
23+
: ConsumerContext(compilation_context, pipeline, nullptr, nullptr) {}
2424

2525
ConsumerContext::ConsumerContext(CompilationContext &compilation_context,
2626
Pipeline &pipeline,
27-
PipelineContext *pipeline_context)
27+
PipelineContext *pipeline_context,
28+
llvm::BasicBlock *exit_block)
2829
: compilation_context_(compilation_context),
2930
pipeline_(pipeline),
30-
pipeline_context_(pipeline_context) {}
31+
pipeline_context_(pipeline_context),
32+
exit_block_(exit_block) {}
3133

3234
// Pass the row batch to the next operator in the pipeline
3335
void ConsumerContext::Consume(RowBatch &batch) {

src/codegen/expression/case_translator.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
//
77
// Identification: src/codegen/expression/case_translator.cpp
88
//
9-
// Copyright (c) 2015-2017, Carnegie Mellon University Database Group
9+
// Copyright (c) 2015-2018, Carnegie Mellon University Database Group
1010
//
1111
//===----------------------------------------------------------------------===//
1212

@@ -47,13 +47,20 @@ codegen::Value CaseTranslator::DeriveValue(CodeGen &codegen,
4747
codegen::Value ret;
4848
for (uint32_t i = 0; i < expr.GetWhenClauseSize(); i++) {
4949
codegen::Value cond = row.DeriveValue(codegen, *expr.GetWhenClauseCond(i));
50-
lang::If when{codegen, cond.GetValue(), "case" + std::to_string(i)};
50+
lang::If when(codegen, cond.GetValue(), "case" + std::to_string(i));
5151
{
52+
// Derive the value of this case expression
5253
ret = row.DeriveValue(codegen, *expr.GetWhenClauseResult(i));
54+
55+
// Collect the value in order to merge at the very end
5356
branch_vals.emplace_back(ret, codegen->GetInsertBlock());
57+
58+
// Branch (unconditionally) to the merging block
59+
codegen->CreateBr(merge_bb);
5460
}
55-
when.EndIf(merge_bb);
61+
when.EndIf();
5662
}
63+
5764
// Compute the default clause
5865
// default_ret will have the same type as one of the ret's from above
5966
codegen::Value default_ret =

src/codegen/function_builder.cpp

Lines changed: 77 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@ llvm::Function *ConstructFunction(
6161

6262
} // namespace
6363

64-
//===----------------------------------------------------------------------===//
65-
//
66-
// FunctionDeclaration
67-
//
68-
//===----------------------------------------------------------------------===//
64+
////////////////////////////////////////////////////////////////////////////////
65+
///
66+
/// FunctionDeclaration
67+
///
68+
////////////////////////////////////////////////////////////////////////////////
6969

7070
FunctionDeclaration::FunctionDeclaration(
7171
CodeContext &cc, const std::string &name,
@@ -84,11 +84,11 @@ FunctionDeclaration FunctionDeclaration::MakeDeclaration(
8484
return FunctionDeclaration(cc, name, visibility, ret_type, args);
8585
}
8686

87-
//===----------------------------------------------------------------------===//
88-
//
89-
// FunctionBuilder
90-
//
91-
//===----------------------------------------------------------------------===//
87+
////////////////////////////////////////////////////////////////////////////////
88+
///
89+
/// FunctionBuilder
90+
///
91+
////////////////////////////////////////////////////////////////////////////////
9292

9393
// We preserve the state of any ongoing function construction in order to be
9494
// able to restore it after this function has been fully completed. Thus,
@@ -101,7 +101,8 @@ FunctionBuilder::FunctionBuilder(CodeContext &cc, llvm::Function *func_decl)
101101
previous_insert_point_(cc.GetBuilder().GetInsertBlock()),
102102
func_(func_decl),
103103
overflow_bb_(nullptr),
104-
divide_by_zero_bb_(nullptr) {
104+
divide_by_zero_bb_(nullptr),
105+
return_bb_(nullptr) {
105106
// At this point, we've saved the current position during code generation and
106107
// we have a function declaration. Now:
107108
// 1. We define the "entry" block and attach it to the function. At this
@@ -175,10 +176,11 @@ llvm::BasicBlock *FunctionBuilder::GetOverflowBB() {
175176
return overflow_bb_;
176177
}
177178

178-
CodeGen codegen{code_context_};
179+
CodeGen codegen(code_context_);
179180

180181
// Save the current position so we can restore after we're done
181-
auto *curr_position = codegen->GetInsertBlock();
182+
auto *curr_block = codegen->GetInsertBlock();
183+
auto curr_pos = codegen->GetInsertPoint();
182184

183185
// Create the overflow block now, but don't attach to function just yet.
184186
overflow_bb_ = llvm::BasicBlock::Create(codegen.GetContext(), "overflow");
@@ -189,7 +191,7 @@ llvm::BasicBlock *FunctionBuilder::GetOverflowBB() {
189191
codegen->CreateUnreachable();
190192

191193
// Restore position
192-
codegen->SetInsertPoint(curr_position);
194+
codegen->SetInsertPoint(curr_block, curr_pos);
193195

194196
return overflow_bb_;
195197
}
@@ -204,10 +206,11 @@ llvm::BasicBlock *FunctionBuilder::GetDivideByZeroBB() {
204206
return divide_by_zero_bb_;
205207
}
206208

207-
CodeGen codegen{code_context_};
209+
CodeGen codegen(code_context_);
208210

209211
// Save the current position so we can restore after we're done
210-
auto *curr_position = codegen->GetInsertBlock();
212+
auto *curr_block = codegen->GetInsertBlock();
213+
auto curr_pos = codegen->GetInsertPoint();
211214

212215
// Create the overflow block now, but don't attach to function just yet.
213216
divide_by_zero_bb_ =
@@ -219,18 +222,42 @@ llvm::BasicBlock *FunctionBuilder::GetDivideByZeroBB() {
219222
codegen->CreateUnreachable();
220223

221224
// Restore position
222-
codegen->SetInsertPoint(curr_position);
225+
codegen->SetInsertPoint(curr_block, curr_pos);
223226

224227
return divide_by_zero_bb_;
225228
}
226229

230+
llvm::BasicBlock *FunctionBuilder::GetExitBlock() {
231+
if (return_bb_ != nullptr) {
232+
return return_bb_;
233+
}
234+
235+
CodeGen codegen(code_context_);
236+
237+
// Save the current position so we can restore after we're done
238+
auto *curr_block = codegen->GetInsertBlock();
239+
auto curr_pos = codegen->GetInsertPoint();
240+
241+
// Create the overflow block now, but don't attach to function just yet.
242+
return_bb_ = llvm::BasicBlock::Create(codegen.GetContext(), "return");
243+
244+
// Quickly switch into the return block
245+
codegen->SetInsertPoint(return_bb_);
246+
codegen->CreateRetVoid();
247+
248+
// Restore position
249+
codegen->SetInsertPoint(curr_block, curr_pos);
250+
251+
return return_bb_;
252+
}
253+
227254
// Return the given value from the function and finish it
228255
void FunctionBuilder::ReturnAndFinish(llvm::Value *ret) {
229256
if (finished_) {
230257
return;
231258
}
232259

233-
CodeGen codegen{code_context_};
260+
CodeGen codegen(code_context_);
234261

235262
if (ret != nullptr) {
236263
codegen->CreateRet(ret);
@@ -239,12 +266,17 @@ void FunctionBuilder::ReturnAndFinish(llvm::Value *ret) {
239266
codegen->CreateRetVoid();
240267
}
241268

242-
// Add the overflow error block if it exists
269+
// Add the return block, if it exists
270+
if (return_bb_ != nullptr) {
271+
return_bb_->insertInto(func_);
272+
}
273+
274+
// Add the overflow error block, if it exists
243275
if (overflow_bb_ != nullptr) {
244276
overflow_bb_->insertInto(func_);
245277
}
246278

247-
// Add the divide-by-zero error block if it exists
279+
// Add the divide-by-zero error block, if it exists
248280
if (divide_by_zero_bb_ != nullptr) {
249281
divide_by_zero_bb_->insertInto(func_);
250282
}
@@ -261,23 +293,33 @@ void FunctionBuilder::ReturnAndFinish(llvm::Value *ret) {
261293
}
262294

263295
llvm::Value *FunctionBuilder::GetOrCacheVariable(
264-
const std::string &name, const std::function<llvm::Value *()> &func) {
265-
auto iter = cached_vars_.find(name);
266-
if (iter != cached_vars_.end()) {
267-
return iter->second;
268-
} else {
269-
CodeGen codegen{code_context_};
270-
auto pos = codegen->GetInsertPoint();
271-
if (entry_bb_->empty()) {
272-
codegen->SetInsertPoint(entry_bb_);
273-
} else {
274-
codegen->SetInsertPoint(&entry_bb_->back());
275-
}
276-
auto *val = func();
277-
codegen->SetInsertPoint(&*pos);
278-
cached_vars_.emplace(name, val);
296+
const std::string &name, const std::function<llvm::Value *()> &load_func) {
297+
llvm::Value *&val = cached_vars_[name];
298+
if (val != nullptr) {
279299
return val;
280300
}
301+
302+
CodeGen codegen(code_context_);
303+
304+
// Save current position
305+
auto *curr_block = codegen->GetInsertBlock();
306+
auto curr_pos = codegen->GetInsertPoint();
307+
308+
// Move to start of function
309+
if (entry_bb_->empty()) {
310+
codegen->SetInsertPoint(entry_bb_);
311+
} else {
312+
codegen->SetInsertPoint(&entry_bb_->back());
313+
}
314+
315+
// Generate loading code and save in cache
316+
val = load_func();
317+
318+
// Move back
319+
codegen->SetInsertPoint(curr_block, curr_pos);
320+
321+
// Return value
322+
return val;
281323
}
282324

283325
} // namespace codegen

0 commit comments

Comments
 (0)