mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-13 18:02:24 +00:00
ba4174402a
Fixes the following use-of-uninitialized-value in llvm [1]: ==696==WARNING: MemorySanitizer: use-of-uninitialized-value 0 0x498141d9 in llvm::ilist_traits<llvm::MachineInstr>::removeNodeFromList(llvm::MachineInstr*) build_docker/../contrib/llvm/llvm/lib/CodeGen/MachineBasicBlock.cpp:155:24 1 0x498141d9 in llvm::iplist_impl<llvm::simple_ilist<llvm::MachineInstr, llvm::ilist_sentinel_tracking<true>>, llvm::ilist_traits<llvm::MachineInstr>>::remove(llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::MachineInstr, true, true, void>, false, false>&) build_docker/../contrib/llvm/llvm/include/llvm/ADT/ilist.h:253:11 2 0x498141d9 in llvm::iplist_impl<llvm::simple_ilist<llvm::MachineInstr, llvm::ilist_sentinel_tracking<true>>, llvm::ilist_traits<llvm::MachineInstr>>::erase(llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::MachineInstr, true, true, void>, false, false>) build_docker/../contrib/llvm/llvm/include/llvm/ADT/ilist.h:268:22 3 0x498141d9 in llvm::iplist_impl<llvm::simple_ilist<llvm::MachineInstr, llvm::ilist_sentinel_tracking<true>>, llvm::ilist_traits<llvm::MachineInstr>>::erase(llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::MachineInstr, true, true, void>, false, false>, llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::MachineInstr, true, true, void>, false, false>) build_docker/../contrib/llvm/llvm/include/llvm/ADT/ilist.h:305:15 4 0x498141d9 in llvm::iplist_impl<llvm::simple_ilist<llvm::MachineInstr, llvm::ilist_sentinel_tracking<true>>, llvm::ilist_traits<llvm::MachineInstr>>::clear() build_docker/../contrib/llvm/llvm/include/llvm/ADT/ilist.h:309:18 5 0x498141d9 in llvm::iplist_impl<llvm::simple_ilist<llvm::MachineInstr, llvm::ilist_sentinel_tracking<true>>, llvm::ilist_traits<llvm::MachineInstr>>::~iplist_impl() build_docker/../contrib/llvm/llvm/include/llvm/ADT/ilist.h:210:20 6 0x498145ff in llvm::MachineBasicBlock::~MachineBasicBlock() build_docker/../contrib/llvm/llvm/lib/CodeGen/MachineBasicBlock.cpp:56:1 7 0x49969c1f in llvm::MachineFunction::DeleteMachineBasicBlock(llvm::MachineBasicBlock*) build_docker/../contrib/llvm/llvm/lib/CodeGen/MachineFunction.cpp:426:8 8 0x49969c1f in llvm::ilist_alloc_traits<llvm::MachineBasicBlock>::deleteNode(llvm::MachineBasicBlock*) build_docker/../contrib/llvm/llvm/lib/CodeGen/MachineFunction.cpp:127:21 9 0x4983f4d6 in llvm::iplist_impl<llvm::simple_ilist<llvm::MachineBasicBlock>, llvm::ilist_traits<llvm::MachineBasicBlock>>::erase(llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::MachineBasicBlock, false, false, void>, false, false>) build_docker/../contrib/llvm/llvm/include/llvm/ADT/ilist.h:268:11 10 0x4983f4d6 in llvm::iplist_impl<llvm::simple_ilist<llvm::MachineBasicBlock>, llvm::ilist_traits<llvm::MachineBasicBlock>>::erase(llvm::MachineBasicBlock*) build_docker/../contrib/llvm/llvm/include/llvm/ADT/ilist.h:272:39 11 0x4983f4d6 in llvm::MachineFunction::erase(llvm::MachineBasicBlock*) build_docker/../contrib/llvm/llvm/include/llvm/CodeGen/MachineFunction.h:767:53 12 0x4983f4d6 in llvm::MachineBasicBlock::eraseFromParent() build_docker/../contrib/llvm/llvm/lib/CodeGen/MachineBasicBlock.cpp:1317:16 13 0x4a0c9a27 in llvm::TailDuplicator::removeDeadBlock(llvm::MachineBasicBlock*, llvm::function_ref<void (llvm::MachineBasicBlock*)>*) build_docker/../contrib/llvm/llvm/lib/CodeGen/TailDuplicator.cpp:1051:8 14 0x4a0c1e41 in llvm::TailDuplicator::tailDuplicateAndUpdate(bool, llvm::MachineBasicBlock*, llvm::MachineBasicBlock*, llvm::SmallVectorImpl<llvm::MachineBasicBlock*>*, llvm::function_ref<void (llvm::MachineBasicBlock*)>*, llvm::SmallVectorImpl<llvm::MachineBasicBlock*>*) build_docker/../contrib/llvm/llvm/lib/CodeGen/TailDuplicator.cpp:189:5 15 0x4a0ca16e in llvm::TailDuplicator::tailDuplicateBlocks() build_docker/../contrib/llvm/llvm/lib/CodeGen/TailDuplicator.cpp:288:19 16 0x4a0be9f9 in (anonymous namespace)::TailDuplicateBase::runOnMachineFunction(llvm::MachineFunction&) build_docker/../contrib/llvm/llvm/lib/CodeGen/TailDuplication.cpp:98:21 17 0x499a2777 in llvm::MachineFunctionPass::runOnFunction(llvm::Function&) build_docker/../contrib/llvm/llvm/lib/CodeGen/MachineFunctionPass.cpp:72:13 18 0x4dbba34d in llvm::FPPassManager::runOnFunction(llvm::Function&) build_docker/../contrib/llvm/llvm/lib/IR/LegacyPassManager.cpp:1435:27 19 0x4dbe3761 in llvm::FPPassManager::runOnModule(llvm::Module&) build_docker/../contrib/llvm/llvm/lib/IR/LegacyPassManager.cpp:1481:16 20 0x4dbbebbb in (anonymous namespace)::MPPassManager::runOnModule(llvm::Module&) build_docker/../contrib/llvm/llvm/lib/IR/LegacyPassManager.cpp:1550:27 21 0x4dbbebbb in llvm::legacy::PassManagerImpl::run(llvm::Module&) build_docker/../contrib/llvm/llvm/lib/IR/LegacyPassManager.cpp:541:44 22 0x4dbe454b in llvm::legacy::PassManager::run(llvm::Module&) build_docker/../contrib/llvm/llvm/lib/IR/LegacyPassManager.cpp:1677:14 23 0x414405df in DB::JITCompiler::compile(llvm::Module&) build_docker/../src/Interpreters/JIT/CHJIT.cpp:78:22 24 0x4143bb7d in DB::CHJIT::compileModule(std::__1::unique_ptr<llvm::Module, std::__1::default_delete<llvm::Module>>) build_docker/../src/Interpreters/JIT/CHJIT.cpp:378:29 25 0x4143aded in DB::CHJIT::compileModule(std::__1::function<void (llvm::Module&)>) build_docker/../src/Interpreters/JIT/CHJIT.cpp:359:24 26 0x4147b25e in DB::compileAggregateFunctions(DB::CHJIT&, std::__1::vector<DB::AggregateFunctionWithOffset, std::__1::allocator<DB::AggregateFunctionWithOffset>> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>) build_docker/../src/Interpreters/JIT/compileFunction.cpp:738:32 27 0x3de0a23a in DB::Aggregator::compileAggregateFunctionsIfNeeded()::$_0::operator()() const build_docker/../src/Interpreters/Aggregator.cpp:661:49 28 0x3de0a23a in std::__1::pair<std::__1::shared_ptr<DB::CompiledExpressionCacheEntry>, bool> DB::CacheBase<wide::integer<128ul, unsigned int>, DB::CompiledExpressionCacheEntry, UInt128Hash, DB::CompiledFunctionWeightFunction>::getOrSet<DB::Aggregator::compileAggregateFunctionsIfNeeded()::$_0>(wide::integer<128ul, unsigned int> const&, DB::Aggregator::compileAggregateFunctionsIfNeeded()::$_0&&) build_docker/../src/Common/CacheBase.h:125:24 29 0x3de0a23a in DB::Aggregator::compileAggregateFunctionsIfNeeded() build_docker/../src/Interpreters/Aggregator.cpp:657:70 Memory was marked as uninitialized 0 0xb988ded in __sanitizer_dtor_callback (/usr/bin/clickhouse+0xb988ded) (BuildId: c4a880b742797a1f37bc4f5ed869f055cc86486b) 1 0x498145da in llvm::MachineBasicBlock::~MachineBasicBlock() build_docker/../contrib/llvm/llvm/lib/CodeGen/MachineBasicBlock.cpp:56:1 2 0x49969c1f in llvm::MachineFunction::DeleteMachineBasicBlock(llvm::MachineBasicBlock*) build_docker/../contrib/llvm/llvm/lib/CodeGen/MachineFunction.cpp:426:8 3 0x49969c1f in llvm::ilist_alloc_traits<llvm::MachineBasicBlock>::deleteNode(llvm::MachineBasicBlock*) build_docker/../contrib/llvm/llvm/lib/CodeGen/MachineFunction.cpp:127:21 4 0x4983f4d6 in llvm::iplist_impl<llvm::simple_ilist<llvm::MachineBasicBlock>, llvm::ilist_traits<llvm::MachineBasicBlock>>::erase(llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::MachineBasicBlock, false, false, void>, false, false>) build_docker/../contrib/llvm/llvm/include/llvm/ADT/ilist.h:268:11 5 0x4983f4d6 in llvm::iplist_impl<llvm::simple_ilist<llvm::MachineBasicBlock>, llvm::ilist_traits<llvm::MachineBasicBlock>>::erase(llvm::MachineBasicBlock*) build_docker/../contrib/llvm/llvm/include/llvm/ADT/ilist.h:272:39 6 0x4983f4d6 in llvm::MachineFunction::erase(llvm::MachineBasicBlock*) build_docker/../contrib/llvm/llvm/include/llvm/CodeGen/MachineFunction.h:767:53 7 0x4983f4d6 in llvm::MachineBasicBlock::eraseFromParent() build_docker/../contrib/llvm/llvm/lib/CodeGen/MachineBasicBlock.cpp:1317:16 8 0x4a0c9a27 in llvm::TailDuplicator::removeDeadBlock(llvm::MachineBasicBlock*, llvm::function_ref<void (llvm::MachineBasicBlock*)>*) build_docker/../contrib/llvm/llvm/lib/CodeGen/TailDuplicator.cpp:1051:8 9 0x4a0c1e41 in llvm::TailDuplicator::tailDuplicateAndUpdate(bool, llvm::MachineBasicBlock*, llvm::MachineBasicBlock*, llvm::SmallVectorImpl<llvm::MachineBasicBlock*>*, llvm::function_ref<void (llvm::MachineBasicBlock*)>*, llvm::SmallVectorImpl<llvm::MachineBasicBlock*>*) build_docker/../contrib/llvm/llvm/lib/CodeGen/TailDuplicator.cpp:189:5 10 0x4a0ca16e in llvm::TailDuplicator::tailDuplicateBlocks() build_docker/../contrib/llvm/llvm/lib/CodeGen/TailDuplicator.cpp:288:19 11 0x4a0be9f9 in (anonymous namespace)::TailDuplicateBase::runOnMachineFunction(llvm::MachineFunction&) build_docker/../contrib/llvm/llvm/lib/CodeGen/TailDuplication.cpp:98:21 12 0x499a2777 in llvm::MachineFunctionPass::runOnFunction(llvm::Function&) build_docker/../contrib/llvm/llvm/lib/CodeGen/MachineFunctionPass.cpp:72:13 13 0x4dbba34d in llvm::FPPassManager::runOnFunction(llvm::Function&) build_docker/../contrib/llvm/llvm/lib/IR/LegacyPassManager.cpp:1435:27 14 0x4dbe3761 in llvm::FPPassManager::runOnModule(llvm::Module&) build_docker/../contrib/llvm/llvm/lib/IR/LegacyPassManager.cpp:1481:16 15 0x4dbbebbb in (anonymous namespace)::MPPassManager::runOnModule(llvm::Module&) build_docker/../contrib/llvm/llvm/lib/IR/LegacyPassManager.cpp:1550:27 16 0x4dbbebbb in llvm::legacy::PassManagerImpl::run(llvm::Module&) build_docker/../contrib/llvm/llvm/lib/IR/LegacyPassManager.cpp:541:44 17 0x4dbe454b in llvm::legacy::PassManager::run(llvm::Module&) build_docker/../contrib/llvm/llvm/lib/IR/LegacyPassManager.cpp:1677:14 18 0x414405df in DB::JITCompiler::compile(llvm::Module&) build_docker/../src/Interpreters/JIT/CHJIT.cpp:78:22 19 0x4143bb7d in DB::CHJIT::compileModule(std::__1::unique_ptr<llvm::Module, std::__1::default_delete<llvm::Module>>) build_docker/../src/Interpreters/JIT/CHJIT.cpp:378:29 20 0x4143aded in DB::CHJIT::compileModule(std::__1::function<void (llvm::Module&)>) build_docker/../src/Interpreters/JIT/CHJIT.cpp:359:24 21 0x4147b25e in DB::compileAggregateFunctions(DB::CHJIT&, std::__1::vector<DB::AggregateFunctionWithOffset, std::__1::allocator<DB::AggregateFunctionWithOffset>> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>) build_docker/../src/Interpreters/JIT/compileFunction.cpp:738:32 22 0x3de0a23a in DB::Aggregator::compileAggregateFunctionsIfNeeded()::$_0::operator()() const build_docker/../src/Interpreters/Aggregator.cpp:661:49 23 0x3de0a23a in std::__1::pair<std::__1::shared_ptr<DB::CompiledExpressionCacheEntry>, bool> DB::CacheBase<wide::integer<128ul, unsigned int>, DB::CompiledExpressionCacheEntry, UInt128Hash, DB::CompiledFunctionWeightFunction>::getOrSet<DB::Aggregator::compileAggregateFunctionsIfNeeded()::$_0>(wide::integer<128ul, unsigned int> const&, DB::Aggregator::compileAggregateFunctionsIfNeeded()::$_0&&) build_docker/../src/Common/CacheBase.h:125:24 24 0x3de0a23a in DB::Aggregator::compileAggregateFunctionsIfNeeded() build_docker/../src/Interpreters/Aggregator.cpp:657:70 [1]: https://s3.amazonaws.com/clickhouse-test-reports/41046/490a2c75610c4bc3191d55226f8454b3c3d3919a/stateful_tests__msan_.html Note, that it is safe to do, but only for this method, since it had been disabled anyway, back in #27574, and I guess this MSan report may be related. Signed-off-by: Azat Khuzhin <a.khuzhin@semrush.com>
911 lines
39 KiB
C++
911 lines
39 KiB
C++
#include "compileFunction.h"
|
|
|
|
#if USE_EMBEDDED_COMPILER
|
|
|
|
#include <llvm/IR/BasicBlock.h>
|
|
#include <llvm/IR/Function.h>
|
|
#include <llvm/IR/IRBuilder.h>
|
|
|
|
#include <Common/Stopwatch.h>
|
|
#include <Common/ProfileEvents.h>
|
|
#include <DataTypes/Native.h>
|
|
#include <Interpreters/JIT/CHJIT.h>
|
|
|
|
namespace
|
|
{
|
|
struct ColumnDataPlaceholder
|
|
{
|
|
llvm::Value * data_init = nullptr; /// first row
|
|
llvm::Value * null_init = nullptr;
|
|
llvm::PHINode * data = nullptr; /// current row
|
|
llvm::PHINode * null = nullptr;
|
|
};
|
|
}
|
|
|
|
namespace ProfileEvents
|
|
{
|
|
extern const Event CompileFunction;
|
|
extern const Event CompileExpressionsMicroseconds;
|
|
extern const Event CompileExpressionsBytes;
|
|
}
|
|
|
|
namespace DB
|
|
{
|
|
|
|
namespace ErrorCodes
|
|
{
|
|
extern const int LOGICAL_ERROR;
|
|
}
|
|
|
|
ColumnData getColumnData(const IColumn * column)
|
|
{
|
|
ColumnData result;
|
|
const bool is_const = isColumnConst(*column);
|
|
|
|
if (is_const)
|
|
throw Exception(ErrorCodes::LOGICAL_ERROR, "Input columns should not be constant");
|
|
|
|
if (const auto * nullable = typeid_cast<const ColumnNullable *>(column))
|
|
{
|
|
result.null_data = nullable->getNullMapColumn().getRawData().data();
|
|
column = & nullable->getNestedColumn();
|
|
}
|
|
|
|
result.data = column->getRawData().data();
|
|
|
|
return result;
|
|
}
|
|
|
|
static void compileFunction(llvm::Module & module, const IFunctionBase & function)
|
|
{
|
|
/** Algorithm is to create a loop that iterate over ColumnDataRowsSize size_t argument and
|
|
* over ColumnData data and null_data. On each step compiled expression from function
|
|
* will be executed over column data and null_data row.
|
|
*
|
|
* Example of preudocode of generated instructions of function with 1 input column.
|
|
* In case of multiple columns more column_i_data, column_i_null_data is created.
|
|
*
|
|
* void compiled_function(size_t rows_count, ColumnData * columns)
|
|
* {
|
|
* /// Initialize column values
|
|
*
|
|
* Column0Type * column_0_data = static_cast<Column0Type *>(columns[0].data);
|
|
* UInt8 * column_0_null_data = static_cast<UInt8>(columns[0].null_data);
|
|
*
|
|
* /// Initialize other input columns data with indexes < input_columns_count
|
|
*
|
|
* ResultType * result_column_data = static_cast<ResultType *>(columns[input_columns_count].data);
|
|
* UInt8 * result_column_null_data = static_cast<UInt8 *>(columns[input_columns_count].data);
|
|
*
|
|
* if (rows_count == 0)
|
|
* goto end;
|
|
*
|
|
* /// Loop
|
|
*
|
|
* size_t counter = 0;
|
|
*
|
|
* loop:
|
|
*
|
|
* /// Create column values tuple in case of non nullable type it is just column value
|
|
* /// In case of nullable type it is tuple of column value and is column row nullable
|
|
*
|
|
* Column0Tuple column_0_value;
|
|
* if (Column0Type is nullable)
|
|
* {
|
|
* value[0] = column_0_data;
|
|
* value[1] = static_cast<bool>(column_1_null_data);
|
|
* }
|
|
* else
|
|
* {
|
|
* value[0] = column_0_data
|
|
* }
|
|
*
|
|
* /// Initialize other input column values tuple with indexes < input_columns_count
|
|
* /// execute_compiled_expressions function takes input columns values and must return single result value
|
|
*
|
|
* if (ResultType is nullable)
|
|
* {
|
|
* (ResultType, bool) result_column_value = execute_compiled_expressions(column_0_value, ...);
|
|
* *result_column_data = result_column_value[0];
|
|
* *result_column_null_data = static_cast<UInt8>(result_column_value[1]);
|
|
* }
|
|
* else
|
|
* {
|
|
* ResultType result_column_value = execute_compiled_expressions(column_0_value, ...);
|
|
* *result_column_data = result_column_value;
|
|
* }
|
|
*
|
|
* /// Increment input and result column current row pointer
|
|
*
|
|
* ++column_0_data;
|
|
* if (Column 0 type is nullable)
|
|
* {
|
|
* ++column_0_null_data;
|
|
* }
|
|
*
|
|
* ++result_column_data;
|
|
* if (ResultType is nullable)
|
|
* {
|
|
* ++result_column_null_data;
|
|
* }
|
|
*
|
|
* /// Increment loop counter and check if we should exit.
|
|
*
|
|
* ++counter;
|
|
* if (counter == rows_count)
|
|
* goto end;
|
|
* else
|
|
* goto loop;
|
|
*
|
|
* /// End
|
|
* end:
|
|
* return;
|
|
* }
|
|
*/
|
|
|
|
const auto & arg_types = function.getArgumentTypes();
|
|
|
|
llvm::IRBuilder<> b(module.getContext());
|
|
auto * size_type = b.getIntNTy(sizeof(size_t) * 8);
|
|
auto * data_type = llvm::StructType::get(b.getInt8PtrTy(), b.getInt8PtrTy());
|
|
auto * func_type = llvm::FunctionType::get(b.getVoidTy(), { size_type, data_type->getPointerTo() }, /*isVarArg=*/false);
|
|
|
|
/// Create function in module
|
|
|
|
auto * func = llvm::Function::Create(func_type, llvm::Function::ExternalLinkage, function.getName(), module);
|
|
auto * args = func->args().begin();
|
|
llvm::Value * rows_count_arg = args++;
|
|
llvm::Value * columns_arg = args++;
|
|
|
|
/// Initialize ColumnDataPlaceholder llvm representation of ColumnData
|
|
|
|
auto * entry = llvm::BasicBlock::Create(b.getContext(), "entry", func);
|
|
b.SetInsertPoint(entry);
|
|
|
|
std::vector<ColumnDataPlaceholder> columns(arg_types.size() + 1);
|
|
for (size_t i = 0; i <= arg_types.size(); ++i)
|
|
{
|
|
const auto & type = i == arg_types.size() ? function.getResultType() : arg_types[i];
|
|
auto * data = b.CreateLoad(data_type, b.CreateConstInBoundsGEP1_64(data_type, columns_arg, i));
|
|
columns[i].data_init = b.CreatePointerCast(b.CreateExtractValue(data, {0}), toNativeType(b, removeNullable(type))->getPointerTo());
|
|
columns[i].null_init = type->isNullable() ? b.CreateExtractValue(data, {1}) : nullptr;
|
|
}
|
|
|
|
/// Initialize loop
|
|
|
|
auto * end = llvm::BasicBlock::Create(b.getContext(), "end", func);
|
|
auto * loop = llvm::BasicBlock::Create(b.getContext(), "loop", func);
|
|
b.CreateCondBr(b.CreateICmpEQ(rows_count_arg, llvm::ConstantInt::get(size_type, 0)), end, loop);
|
|
|
|
b.SetInsertPoint(loop);
|
|
|
|
auto * counter_phi = b.CreatePHI(rows_count_arg->getType(), 2);
|
|
counter_phi->addIncoming(llvm::ConstantInt::get(size_type, 0), entry);
|
|
|
|
for (auto & col : columns)
|
|
{
|
|
col.data = b.CreatePHI(col.data_init->getType(), 2);
|
|
col.data->addIncoming(col.data_init, entry);
|
|
if (col.null_init)
|
|
{
|
|
col.null = b.CreatePHI(col.null_init->getType(), 2);
|
|
col.null->addIncoming(col.null_init, entry);
|
|
}
|
|
}
|
|
|
|
/// Initialize column row values
|
|
|
|
Values arguments;
|
|
arguments.reserve(arg_types.size());
|
|
|
|
for (size_t i = 0; i < arg_types.size(); ++i)
|
|
{
|
|
auto & column = columns[i];
|
|
const auto & type = arg_types[i];
|
|
|
|
auto * value = b.CreateLoad(toNativeType(b, removeNullable(type)), column.data);
|
|
if (!type->isNullable())
|
|
{
|
|
arguments.emplace_back(value);
|
|
continue;
|
|
}
|
|
|
|
auto * is_null = b.CreateICmpNE(b.CreateLoad(b.getInt8Ty(), column.null), b.getInt8(0));
|
|
auto * nullable_unitilized = llvm::Constant::getNullValue(toNativeType(b, type));
|
|
auto * nullable_value = b.CreateInsertValue(b.CreateInsertValue(nullable_unitilized, value, {0}), is_null, {1});
|
|
arguments.emplace_back(nullable_value);
|
|
}
|
|
|
|
/// Compile values for column rows and store compiled value in result column
|
|
|
|
auto * result = function.compile(b, std::move(arguments));
|
|
if (columns.back().null)
|
|
{
|
|
b.CreateStore(b.CreateExtractValue(result, {0}), columns.back().data);
|
|
b.CreateStore(b.CreateSelect(b.CreateExtractValue(result, {1}), b.getInt8(1), b.getInt8(0)), columns.back().null);
|
|
}
|
|
else
|
|
{
|
|
b.CreateStore(result, columns.back().data);
|
|
}
|
|
|
|
/// End of loop
|
|
|
|
auto * cur_block = b.GetInsertBlock();
|
|
for (auto & col : columns)
|
|
{
|
|
col.data->addIncoming(b.CreateConstInBoundsGEP1_64(nullptr, col.data, 1), cur_block);
|
|
if (col.null)
|
|
col.null->addIncoming(b.CreateConstInBoundsGEP1_64(nullptr, col.null, 1), cur_block);
|
|
}
|
|
|
|
auto * value = b.CreateAdd(counter_phi, llvm::ConstantInt::get(size_type, 1));
|
|
counter_phi->addIncoming(value, cur_block);
|
|
|
|
b.CreateCondBr(b.CreateICmpEQ(value, rows_count_arg), end, loop);
|
|
|
|
b.SetInsertPoint(end);
|
|
b.CreateRetVoid();
|
|
}
|
|
|
|
CompiledFunction compileFunction(CHJIT & jit, const IFunctionBase & function)
|
|
{
|
|
Stopwatch watch;
|
|
|
|
auto compiled_module = jit.compileModule([&](llvm::Module & module)
|
|
{
|
|
compileFunction(module, function);
|
|
});
|
|
|
|
ProfileEvents::increment(ProfileEvents::CompileExpressionsMicroseconds, watch.elapsedMicroseconds());
|
|
ProfileEvents::increment(ProfileEvents::CompileExpressionsBytes, compiled_module.size);
|
|
ProfileEvents::increment(ProfileEvents::CompileFunction);
|
|
|
|
auto compiled_function_ptr = reinterpret_cast<JITCompiledFunction>(compiled_module.function_name_to_symbol[function.getName()]);
|
|
assert(compiled_function_ptr);
|
|
|
|
CompiledFunction result_compiled_function
|
|
{
|
|
.compiled_function = compiled_function_ptr,
|
|
.compiled_module = compiled_module
|
|
};
|
|
|
|
return result_compiled_function;
|
|
}
|
|
|
|
static void compileCreateAggregateStatesFunctions(llvm::Module & module, const std::vector<AggregateFunctionWithOffset> & functions, const std::string & name)
|
|
{
|
|
auto & context = module.getContext();
|
|
llvm::IRBuilder<> b(context);
|
|
|
|
auto * aggregate_data_places_type = b.getInt8Ty()->getPointerTo();
|
|
auto * create_aggregate_states_function_type = llvm::FunctionType::get(b.getVoidTy(), { aggregate_data_places_type }, false);
|
|
auto * create_aggregate_states_function = llvm::Function::Create(create_aggregate_states_function_type, llvm::Function::ExternalLinkage, name, module);
|
|
|
|
auto * arguments = create_aggregate_states_function->args().begin();
|
|
llvm::Value * aggregate_data_place_arg = arguments++;
|
|
|
|
auto * entry = llvm::BasicBlock::Create(b.getContext(), "entry", create_aggregate_states_function);
|
|
b.SetInsertPoint(entry);
|
|
|
|
std::vector<ColumnDataPlaceholder> columns(functions.size());
|
|
for (const auto & function_to_compile : functions)
|
|
{
|
|
size_t aggregate_function_offset = function_to_compile.aggregate_data_offset;
|
|
const auto * aggregate_function = function_to_compile.function;
|
|
auto * aggregation_place_with_offset = b.CreateConstInBoundsGEP1_64(nullptr, aggregate_data_place_arg, aggregate_function_offset);
|
|
aggregate_function->compileCreate(b, aggregation_place_with_offset);
|
|
}
|
|
|
|
b.CreateRetVoid();
|
|
}
|
|
|
|
static void compileAddIntoAggregateStatesFunctions(llvm::Module & module, const std::vector<AggregateFunctionWithOffset> & functions, const std::string & name)
|
|
{
|
|
auto & context = module.getContext();
|
|
llvm::IRBuilder<> b(context);
|
|
|
|
auto * size_type = b.getIntNTy(sizeof(size_t) * 8);
|
|
auto * places_type = b.getInt8Ty()->getPointerTo()->getPointerTo();
|
|
auto * column_data_type = llvm::StructType::get(b.getInt8PtrTy(), b.getInt8PtrTy());
|
|
|
|
auto * aggregate_loop_func_declaration = llvm::FunctionType::get(b.getVoidTy(), { size_type, size_type, column_data_type->getPointerTo(), places_type }, false);
|
|
auto * aggregate_loop_func_definition = llvm::Function::Create(aggregate_loop_func_declaration, llvm::Function::ExternalLinkage, name, module);
|
|
|
|
auto * arguments = aggregate_loop_func_definition->args().begin();
|
|
llvm::Value * row_start_arg = arguments++;
|
|
llvm::Value * row_end_arg = arguments++;
|
|
llvm::Value * columns_arg = arguments++;
|
|
llvm::Value * places_arg = arguments++;
|
|
|
|
/// Initialize ColumnDataPlaceholder llvm representation of ColumnData
|
|
|
|
auto * entry = llvm::BasicBlock::Create(b.getContext(), "entry", aggregate_loop_func_definition);
|
|
b.SetInsertPoint(entry);
|
|
|
|
llvm::IRBuilder<> entry_builder(entry);
|
|
auto * places_start_arg = entry_builder.CreateInBoundsGEP(nullptr, places_arg, row_start_arg);
|
|
|
|
std::vector<ColumnDataPlaceholder> columns;
|
|
size_t previous_columns_size = 0;
|
|
|
|
for (const auto & function : functions)
|
|
{
|
|
auto argument_types = function.function->getArgumentTypes();
|
|
|
|
ColumnDataPlaceholder data_placeholder;
|
|
|
|
size_t function_arguments_size = argument_types.size();
|
|
|
|
for (size_t column_argument_index = 0; column_argument_index < function_arguments_size; ++column_argument_index)
|
|
{
|
|
const auto & argument_type = argument_types[column_argument_index];
|
|
auto * data = b.CreateLoad(column_data_type, b.CreateConstInBoundsGEP1_64(column_data_type, columns_arg, previous_columns_size + column_argument_index));
|
|
data_placeholder.data_init = b.CreatePointerCast(b.CreateExtractValue(data, {0}), toNativeType(b, removeNullable(argument_type))->getPointerTo());
|
|
data_placeholder.data_init = entry_builder.CreateInBoundsGEP(nullptr, data_placeholder.data_init, row_start_arg);
|
|
if (argument_type->isNullable())
|
|
{
|
|
data_placeholder.null_init = b.CreateExtractValue(data, {1});
|
|
data_placeholder.null_init = entry_builder.CreateInBoundsGEP(nullptr, data_placeholder.null_init, row_start_arg);
|
|
}
|
|
else
|
|
{
|
|
data_placeholder.null_init = nullptr;
|
|
}
|
|
columns.emplace_back(data_placeholder);
|
|
}
|
|
|
|
previous_columns_size += function_arguments_size;
|
|
}
|
|
|
|
/// Initialize loop
|
|
|
|
auto * end = llvm::BasicBlock::Create(b.getContext(), "end", aggregate_loop_func_definition);
|
|
auto * loop = llvm::BasicBlock::Create(b.getContext(), "loop", aggregate_loop_func_definition);
|
|
|
|
b.CreateCondBr(b.CreateICmpEQ(row_start_arg, row_end_arg), end, loop);
|
|
|
|
b.SetInsertPoint(loop);
|
|
|
|
auto * counter_phi = b.CreatePHI(row_start_arg->getType(), 2);
|
|
counter_phi->addIncoming(row_start_arg, entry);
|
|
|
|
auto * places_phi = b.CreatePHI(places_start_arg->getType(), 2);
|
|
places_phi->addIncoming(places_start_arg, entry);
|
|
|
|
for (auto & col : columns)
|
|
{
|
|
col.data = b.CreatePHI(col.data_init->getType(), 2);
|
|
col.data->addIncoming(col.data_init, entry);
|
|
|
|
if (col.null_init)
|
|
{
|
|
col.null = b.CreatePHI(col.null_init->getType(), 2);
|
|
col.null->addIncoming(col.null_init, entry);
|
|
}
|
|
}
|
|
|
|
auto * aggregation_place = b.CreateLoad(b.getInt8Ty()->getPointerTo(), places_phi);
|
|
|
|
previous_columns_size = 0;
|
|
for (const auto & function : functions)
|
|
{
|
|
size_t aggregate_function_offset = function.aggregate_data_offset;
|
|
const auto * aggregate_function_ptr = function.function;
|
|
|
|
auto arguments_types = function.function->getArgumentTypes();
|
|
std::vector<llvm::Value *> arguments_values;
|
|
|
|
size_t function_arguments_size = arguments_types.size();
|
|
arguments_values.resize(function_arguments_size);
|
|
|
|
for (size_t column_argument_index = 0; column_argument_index < function_arguments_size; ++column_argument_index)
|
|
{
|
|
auto * column_argument_data = columns[previous_columns_size + column_argument_index].data;
|
|
auto * column_argument_null_data = columns[previous_columns_size + column_argument_index].null;
|
|
|
|
auto & argument_type = arguments_types[column_argument_index];
|
|
|
|
auto * value = b.CreateLoad(toNativeType(b, removeNullable(argument_type)), column_argument_data);
|
|
if (!argument_type->isNullable())
|
|
{
|
|
arguments_values[column_argument_index] = value;
|
|
continue;
|
|
}
|
|
|
|
auto * is_null = b.CreateICmpNE(b.CreateLoad(b.getInt8Ty(), column_argument_null_data), b.getInt8(0));
|
|
auto * nullable_unitilized = llvm::Constant::getNullValue(toNativeType(b, argument_type));
|
|
auto * nullable_value = b.CreateInsertValue(b.CreateInsertValue(nullable_unitilized, value, {0}), is_null, {1});
|
|
arguments_values[column_argument_index] = nullable_value;
|
|
}
|
|
|
|
auto * aggregation_place_with_offset = b.CreateConstInBoundsGEP1_64(nullptr, aggregation_place, aggregate_function_offset);
|
|
aggregate_function_ptr->compileAdd(b, aggregation_place_with_offset, arguments_types, arguments_values);
|
|
|
|
previous_columns_size += function_arguments_size;
|
|
}
|
|
|
|
/// End of loop
|
|
|
|
auto * cur_block = b.GetInsertBlock();
|
|
for (auto & col : columns)
|
|
{
|
|
col.data->addIncoming(b.CreateConstInBoundsGEP1_64(nullptr, col.data, 1), cur_block);
|
|
|
|
if (col.null)
|
|
col.null->addIncoming(b.CreateConstInBoundsGEP1_64(nullptr, col.null, 1), cur_block);
|
|
}
|
|
|
|
places_phi->addIncoming(b.CreateConstInBoundsGEP1_64(nullptr, places_phi, 1), cur_block);
|
|
|
|
auto * value = b.CreateAdd(counter_phi, llvm::ConstantInt::get(size_type, 1));
|
|
counter_phi->addIncoming(value, cur_block);
|
|
|
|
b.CreateCondBr(b.CreateICmpEQ(value, row_end_arg), end, loop);
|
|
|
|
b.SetInsertPoint(end);
|
|
b.CreateRetVoid();
|
|
}
|
|
|
|
static void compileAddIntoAggregateStatesFunctionsSinglePlace(llvm::Module & module, const std::vector<AggregateFunctionWithOffset> & functions, const std::string & name)
|
|
{
|
|
auto & context = module.getContext();
|
|
llvm::IRBuilder<> b(context);
|
|
|
|
auto * size_type = b.getIntNTy(sizeof(size_t) * 8);
|
|
auto * places_type = b.getInt8Ty()->getPointerTo();
|
|
auto * column_data_type = llvm::StructType::get(b.getInt8PtrTy(), b.getInt8PtrTy());
|
|
|
|
auto * aggregate_loop_func_declaration = llvm::FunctionType::get(b.getVoidTy(), { size_type, size_type, column_data_type->getPointerTo(), places_type }, false);
|
|
auto * aggregate_loop_func_definition = llvm::Function::Create(aggregate_loop_func_declaration, llvm::Function::ExternalLinkage, name, module);
|
|
|
|
auto * arguments = aggregate_loop_func_definition->args().begin();
|
|
llvm::Value * row_start_arg = arguments++;
|
|
llvm::Value * row_end_arg = arguments++;
|
|
llvm::Value * columns_arg = arguments++;
|
|
llvm::Value * place_arg = arguments++;
|
|
|
|
/// Initialize ColumnDataPlaceholder llvm representation of ColumnData
|
|
|
|
auto * entry = llvm::BasicBlock::Create(b.getContext(), "entry", aggregate_loop_func_definition);
|
|
b.SetInsertPoint(entry);
|
|
|
|
llvm::IRBuilder<> entry_builder(entry);
|
|
|
|
std::vector<ColumnDataPlaceholder> columns;
|
|
size_t previous_columns_size = 0;
|
|
|
|
for (const auto & function : functions)
|
|
{
|
|
auto argument_types = function.function->getArgumentTypes();
|
|
|
|
ColumnDataPlaceholder data_placeholder;
|
|
|
|
size_t function_arguments_size = argument_types.size();
|
|
|
|
for (size_t column_argument_index = 0; column_argument_index < function_arguments_size; ++column_argument_index)
|
|
{
|
|
const auto & argument_type = argument_types[column_argument_index];
|
|
auto * data = b.CreateLoad(column_data_type, b.CreateConstInBoundsGEP1_64(column_data_type, columns_arg, previous_columns_size + column_argument_index));
|
|
data_placeholder.data_init = b.CreatePointerCast(b.CreateExtractValue(data, {0}), toNativeType(b, removeNullable(argument_type))->getPointerTo());
|
|
data_placeholder.data_init = entry_builder.CreateInBoundsGEP(nullptr, data_placeholder.data_init, row_start_arg);
|
|
if (argument_type->isNullable())
|
|
{
|
|
data_placeholder.null_init = b.CreateExtractValue(data, {1});
|
|
data_placeholder.null_init = entry_builder.CreateInBoundsGEP(nullptr, data_placeholder.null_init, row_start_arg);
|
|
}
|
|
else
|
|
{
|
|
data_placeholder.null_init = nullptr;
|
|
}
|
|
columns.emplace_back(data_placeholder);
|
|
}
|
|
|
|
previous_columns_size += function_arguments_size;
|
|
}
|
|
|
|
/// Initialize loop
|
|
|
|
auto * end = llvm::BasicBlock::Create(b.getContext(), "end", aggregate_loop_func_definition);
|
|
auto * loop = llvm::BasicBlock::Create(b.getContext(), "loop", aggregate_loop_func_definition);
|
|
|
|
b.CreateCondBr(b.CreateICmpEQ(row_start_arg, row_end_arg), end, loop);
|
|
|
|
b.SetInsertPoint(loop);
|
|
|
|
auto * counter_phi = b.CreatePHI(row_start_arg->getType(), 2);
|
|
counter_phi->addIncoming(row_start_arg, entry);
|
|
|
|
for (auto & col : columns)
|
|
{
|
|
col.data = b.CreatePHI(col.data_init->getType(), 2);
|
|
col.data->addIncoming(col.data_init, entry);
|
|
|
|
if (col.null_init)
|
|
{
|
|
col.null = b.CreatePHI(col.null_init->getType(), 2);
|
|
col.null->addIncoming(col.null_init, entry);
|
|
}
|
|
}
|
|
|
|
previous_columns_size = 0;
|
|
for (const auto & function : functions)
|
|
{
|
|
size_t aggregate_function_offset = function.aggregate_data_offset;
|
|
const auto * aggregate_function_ptr = function.function;
|
|
|
|
auto arguments_types = function.function->getArgumentTypes();
|
|
std::vector<llvm::Value *> arguments_values;
|
|
|
|
size_t function_arguments_size = arguments_types.size();
|
|
arguments_values.resize(function_arguments_size);
|
|
|
|
for (size_t column_argument_index = 0; column_argument_index < function_arguments_size; ++column_argument_index)
|
|
{
|
|
auto * column_argument_data = columns[previous_columns_size + column_argument_index].data;
|
|
auto * column_argument_null_data = columns[previous_columns_size + column_argument_index].null;
|
|
|
|
auto & argument_type = arguments_types[column_argument_index];
|
|
|
|
auto * value = b.CreateLoad(toNativeType(b, removeNullable(argument_type)), column_argument_data);
|
|
if (!argument_type->isNullable())
|
|
{
|
|
arguments_values[column_argument_index] = value;
|
|
continue;
|
|
}
|
|
|
|
auto * is_null = b.CreateICmpNE(b.CreateLoad(b.getInt8Ty(), column_argument_null_data), b.getInt8(0));
|
|
auto * nullable_unitilized = llvm::Constant::getNullValue(toNativeType(b, argument_type));
|
|
auto * nullable_value = b.CreateInsertValue(b.CreateInsertValue(nullable_unitilized, value, {0}), is_null, {1});
|
|
arguments_values[column_argument_index] = nullable_value;
|
|
}
|
|
|
|
auto * aggregation_place_with_offset = b.CreateConstInBoundsGEP1_64(nullptr, place_arg, aggregate_function_offset);
|
|
aggregate_function_ptr->compileAdd(b, aggregation_place_with_offset, arguments_types, arguments_values);
|
|
|
|
previous_columns_size += function_arguments_size;
|
|
}
|
|
|
|
/// End of loop
|
|
|
|
auto * cur_block = b.GetInsertBlock();
|
|
for (auto & col : columns)
|
|
{
|
|
col.data->addIncoming(b.CreateConstInBoundsGEP1_64(nullptr, col.data, 1), cur_block);
|
|
|
|
if (col.null)
|
|
col.null->addIncoming(b.CreateConstInBoundsGEP1_64(nullptr, col.null, 1), cur_block);
|
|
}
|
|
|
|
auto * value = b.CreateAdd(counter_phi, llvm::ConstantInt::get(size_type, 1));
|
|
counter_phi->addIncoming(value, cur_block);
|
|
|
|
b.CreateCondBr(b.CreateICmpEQ(value, row_end_arg), end, loop);
|
|
|
|
b.SetInsertPoint(end);
|
|
b.CreateRetVoid();
|
|
}
|
|
|
|
static void compileMergeAggregatesStates(llvm::Module & module, const std::vector<AggregateFunctionWithOffset> & functions, const std::string & name)
|
|
{
|
|
auto & context = module.getContext();
|
|
llvm::IRBuilder<> b(context);
|
|
|
|
auto * aggregate_data_places_type = b.getInt8Ty()->getPointerTo();
|
|
auto * aggregate_loop_func_declaration = llvm::FunctionType::get(b.getVoidTy(), { aggregate_data_places_type, aggregate_data_places_type }, false);
|
|
auto * aggregate_loop_func = llvm::Function::Create(aggregate_loop_func_declaration, llvm::Function::ExternalLinkage, name, module);
|
|
|
|
auto * arguments = aggregate_loop_func->args().begin();
|
|
llvm::Value * aggregate_data_place_dst_arg = arguments++;
|
|
llvm::Value * aggregate_data_place_src_arg = arguments++;
|
|
|
|
auto * entry = llvm::BasicBlock::Create(b.getContext(), "entry", aggregate_loop_func);
|
|
b.SetInsertPoint(entry);
|
|
|
|
for (const auto & function_to_compile : functions)
|
|
{
|
|
size_t aggregate_function_offset = function_to_compile.aggregate_data_offset;
|
|
const auto * aggregate_function_ptr = function_to_compile.function;
|
|
|
|
auto * aggregate_data_place_merge_dst_with_offset = b.CreateConstInBoundsGEP1_64(nullptr, aggregate_data_place_dst_arg, aggregate_function_offset);
|
|
auto * aggregate_data_place_merge_src_with_offset = b.CreateConstInBoundsGEP1_64(nullptr, aggregate_data_place_src_arg, aggregate_function_offset);
|
|
|
|
aggregate_function_ptr->compileMerge(b, aggregate_data_place_merge_dst_with_offset, aggregate_data_place_merge_src_with_offset);
|
|
}
|
|
|
|
b.CreateRetVoid();
|
|
}
|
|
|
|
static void compileInsertAggregatesIntoResultColumns(llvm::Module & module, const std::vector<AggregateFunctionWithOffset> & functions, const std::string & name)
|
|
{
|
|
auto & context = module.getContext();
|
|
llvm::IRBuilder<> b(context);
|
|
|
|
auto * size_type = b.getIntNTy(sizeof(size_t) * 8);
|
|
|
|
auto * column_data_type = llvm::StructType::get(b.getInt8PtrTy(), b.getInt8PtrTy());
|
|
auto * aggregate_data_places_type = b.getInt8Ty()->getPointerTo()->getPointerTo();
|
|
auto * aggregate_loop_func_declaration = llvm::FunctionType::get(b.getVoidTy(), { size_type, size_type, column_data_type->getPointerTo(), aggregate_data_places_type }, false);
|
|
auto * aggregate_loop_func = llvm::Function::Create(aggregate_loop_func_declaration, llvm::Function::ExternalLinkage, name, module);
|
|
|
|
auto * arguments = aggregate_loop_func->args().begin();
|
|
llvm::Value * row_start_arg = &*arguments++;
|
|
llvm::Value * row_end_arg = &*arguments++;
|
|
llvm::Value * columns_arg = &*arguments++;
|
|
llvm::Value * aggregate_data_places_arg = &*arguments++;
|
|
|
|
auto * entry = llvm::BasicBlock::Create(b.getContext(), "entry", aggregate_loop_func);
|
|
b.SetInsertPoint(entry);
|
|
|
|
llvm::IRBuilder<> entry_builder(entry);
|
|
|
|
std::vector<ColumnDataPlaceholder> columns(functions.size());
|
|
for (size_t i = 0; i < functions.size(); ++i)
|
|
{
|
|
auto return_type = functions[i].function->getReturnType();
|
|
auto * data = b.CreateLoad(column_data_type, b.CreateConstInBoundsGEP1_64(column_data_type, columns_arg, i));
|
|
columns[i].data_init = b.CreatePointerCast(b.CreateExtractValue(data, {0}), toNativeType(b, removeNullable(return_type))->getPointerTo());
|
|
columns[i].data_init = entry_builder.CreateInBoundsGEP(nullptr, columns[i].data_init, row_start_arg);
|
|
if (return_type->isNullable())
|
|
{
|
|
columns[i].null_init = b.CreateExtractValue(data, {1});
|
|
columns[i].null_init = entry_builder.CreateInBoundsGEP(nullptr, columns[i].null_init, row_start_arg);
|
|
}
|
|
else
|
|
{
|
|
columns[i].null_init = nullptr;
|
|
}
|
|
}
|
|
|
|
auto * end = llvm::BasicBlock::Create(b.getContext(), "end", aggregate_loop_func);
|
|
auto * loop = llvm::BasicBlock::Create(b.getContext(), "loop", aggregate_loop_func);
|
|
|
|
b.CreateCondBr(b.CreateICmpEQ(row_start_arg, row_end_arg), end, loop);
|
|
|
|
b.SetInsertPoint(loop);
|
|
|
|
auto * counter_phi = b.CreatePHI(row_start_arg->getType(), 2);
|
|
counter_phi->addIncoming(row_start_arg, entry);
|
|
|
|
auto * aggregate_data_place_phi = b.CreatePHI(aggregate_data_places_type, 2);
|
|
aggregate_data_place_phi->addIncoming(aggregate_data_places_arg, entry);
|
|
|
|
for (auto & col : columns)
|
|
{
|
|
col.data = b.CreatePHI(col.data_init->getType(), 2);
|
|
col.data->addIncoming(col.data_init, entry);
|
|
|
|
if (col.null_init)
|
|
{
|
|
col.null = b.CreatePHI(col.null_init->getType(), 2);
|
|
col.null->addIncoming(col.null_init, entry);
|
|
}
|
|
}
|
|
|
|
for (size_t i = 0; i < functions.size(); ++i)
|
|
{
|
|
size_t aggregate_function_offset = functions[i].aggregate_data_offset;
|
|
const auto * aggregate_function_ptr = functions[i].function;
|
|
|
|
auto * aggregate_data_place = b.CreateLoad(b.getInt8Ty()->getPointerTo(), aggregate_data_place_phi);
|
|
auto * aggregation_place_with_offset = b.CreateConstInBoundsGEP1_64(nullptr, aggregate_data_place, aggregate_function_offset);
|
|
|
|
auto * final_value = aggregate_function_ptr->compileGetResult(b, aggregation_place_with_offset);
|
|
|
|
if (columns[i].null_init)
|
|
{
|
|
b.CreateStore(b.CreateExtractValue(final_value, {0}), columns[i].data);
|
|
b.CreateStore(b.CreateSelect(b.CreateExtractValue(final_value, {1}), b.getInt8(1), b.getInt8(0)), columns[i].null);
|
|
}
|
|
else
|
|
{
|
|
b.CreateStore(final_value, columns[i].data);
|
|
}
|
|
}
|
|
|
|
/// End of loop
|
|
|
|
auto * cur_block = b.GetInsertBlock();
|
|
for (auto & col : columns)
|
|
{
|
|
col.data->addIncoming(b.CreateConstInBoundsGEP1_64(nullptr, col.data, 1), cur_block);
|
|
|
|
if (col.null)
|
|
col.null->addIncoming(b.CreateConstInBoundsGEP1_64(nullptr, col.null, 1), cur_block);
|
|
}
|
|
|
|
auto * value = b.CreateAdd(counter_phi, llvm::ConstantInt::get(size_type, 1), "", true, true);
|
|
counter_phi->addIncoming(value, cur_block);
|
|
|
|
aggregate_data_place_phi->addIncoming(b.CreateConstInBoundsGEP1_64(nullptr, aggregate_data_place_phi, 1), cur_block);
|
|
|
|
b.CreateCondBr(b.CreateICmpEQ(value, row_end_arg), end, loop);
|
|
|
|
b.SetInsertPoint(end);
|
|
b.CreateRetVoid();
|
|
}
|
|
|
|
CompiledAggregateFunctions compileAggregateFunctions(CHJIT & jit, const std::vector<AggregateFunctionWithOffset> & functions, std::string functions_dump_name)
|
|
{
|
|
Stopwatch watch;
|
|
|
|
std::string create_aggregate_states_functions_name = functions_dump_name + "_create";
|
|
std::string add_aggregate_states_functions_name = functions_dump_name + "_add";
|
|
std::string add_aggregate_states_functions_name_single_place = functions_dump_name + "_add_single_place";
|
|
std::string merge_aggregate_states_functions_name = functions_dump_name + "_merge";
|
|
std::string insert_aggregate_states_functions_name = functions_dump_name + "_insert";
|
|
|
|
auto compiled_module = jit.compileModule([&](llvm::Module & module)
|
|
{
|
|
compileCreateAggregateStatesFunctions(module, functions, create_aggregate_states_functions_name);
|
|
compileAddIntoAggregateStatesFunctions(module, functions, add_aggregate_states_functions_name);
|
|
/// FIXME: this leads to use-of-uninitialized-value in llvm
|
|
/// But for now, it is safe, since it is not used by Aggregator anyway
|
|
(void)compileAddIntoAggregateStatesFunctionsSinglePlace;
|
|
/// compileAddIntoAggregateStatesFunctionsSinglePlace(module, functions, add_aggregate_states_functions_name_single_place);
|
|
compileMergeAggregatesStates(module, functions, merge_aggregate_states_functions_name);
|
|
compileInsertAggregatesIntoResultColumns(module, functions, insert_aggregate_states_functions_name);
|
|
});
|
|
|
|
auto create_aggregate_states_function = reinterpret_cast<JITCreateAggregateStatesFunction>(compiled_module.function_name_to_symbol[create_aggregate_states_functions_name]);
|
|
auto add_into_aggregate_states_function = reinterpret_cast<JITAddIntoAggregateStatesFunction>(compiled_module.function_name_to_symbol[add_aggregate_states_functions_name]);
|
|
auto add_into_aggregate_states_function_single_place = reinterpret_cast<JITAddIntoAggregateStatesFunctionSinglePlace>(compiled_module.function_name_to_symbol[add_aggregate_states_functions_name_single_place]);
|
|
auto merge_aggregate_states_function = reinterpret_cast<JITMergeAggregateStatesFunction>(compiled_module.function_name_to_symbol[merge_aggregate_states_functions_name]);
|
|
auto insert_aggregate_states_function = reinterpret_cast<JITInsertAggregateStatesIntoColumnsFunction>(compiled_module.function_name_to_symbol[insert_aggregate_states_functions_name]);
|
|
|
|
assert(create_aggregate_states_function);
|
|
assert(add_into_aggregate_states_function);
|
|
/// assert(add_into_aggregate_states_function_single_place); /// FIXME
|
|
assert(merge_aggregate_states_function);
|
|
assert(insert_aggregate_states_function);
|
|
|
|
ProfileEvents::increment(ProfileEvents::CompileExpressionsMicroseconds, watch.elapsedMicroseconds());
|
|
ProfileEvents::increment(ProfileEvents::CompileExpressionsBytes, compiled_module.size);
|
|
ProfileEvents::increment(ProfileEvents::CompileFunction);
|
|
|
|
CompiledAggregateFunctions compiled_aggregate_functions
|
|
{
|
|
.create_aggregate_states_function = create_aggregate_states_function,
|
|
.add_into_aggregate_states_function = add_into_aggregate_states_function,
|
|
.add_into_aggregate_states_function_single_place = add_into_aggregate_states_function_single_place,
|
|
.merge_aggregate_states_function = merge_aggregate_states_function,
|
|
.insert_aggregates_into_columns_function = insert_aggregate_states_function,
|
|
|
|
.functions_count = functions.size(),
|
|
.compiled_module = std::move(compiled_module)
|
|
};
|
|
|
|
return compiled_aggregate_functions;
|
|
}
|
|
|
|
CompiledSortDescriptionFunction compileSortDescription(
|
|
CHJIT & jit,
|
|
SortDescription & description,
|
|
const DataTypes & sort_description_types,
|
|
const std::string & sort_description_dump)
|
|
{
|
|
Stopwatch watch;
|
|
|
|
auto compiled_module = jit.compileModule([&](llvm::Module & module)
|
|
{
|
|
auto & context = module.getContext();
|
|
llvm::IRBuilder<> b(context);
|
|
|
|
auto * size_type = b.getIntNTy(sizeof(size_t) * 8);
|
|
|
|
auto * column_data_type = llvm::StructType::get(b.getInt8PtrTy(), b.getInt8PtrTy());
|
|
|
|
std::vector<llvm::Type *> types = { size_type, size_type, column_data_type->getPointerTo(), column_data_type->getPointerTo() };
|
|
auto * comparator_func_declaration = llvm::FunctionType::get(b.getInt8Ty(), types, false);
|
|
auto * comparator_func = llvm::Function::Create(comparator_func_declaration, llvm::Function::ExternalLinkage, sort_description_dump, module);
|
|
|
|
auto * arguments = comparator_func->args().begin();
|
|
llvm::Value * lhs_index_arg = &*arguments++;
|
|
llvm::Value * rhs_index_arg = &*arguments++;
|
|
llvm::Value * columns_lhs_arg = &*arguments++;
|
|
llvm::Value * columns_rhs_arg = &*arguments++;
|
|
|
|
size_t columns_size = description.size();
|
|
|
|
std::vector<std::pair<llvm::BasicBlock *, llvm::Value *>> comparator_steps_and_results;
|
|
for (size_t i = 0; i < columns_size; ++i)
|
|
{
|
|
auto * step = llvm::BasicBlock::Create(b.getContext(), "step_" + std::to_string(i), comparator_func);
|
|
llvm::Value * result_value = nullptr;
|
|
comparator_steps_and_results.emplace_back(step, result_value);
|
|
}
|
|
|
|
auto * lhs_equals_rhs_result = llvm::ConstantInt::getSigned(b.getInt8Ty(), 0);
|
|
|
|
auto * comparator_join = llvm::BasicBlock::Create(b.getContext(), "comparator_join", comparator_func);
|
|
|
|
for (size_t i = 0; i < columns_size; ++i)
|
|
{
|
|
b.SetInsertPoint(comparator_steps_and_results[i].first);
|
|
|
|
const auto & sort_description = description[i];
|
|
const auto & column_type = sort_description_types[i];
|
|
|
|
auto dummy_column = column_type->createColumn();
|
|
|
|
auto * column_native_type_nullable = toNativeType(b, column_type);
|
|
auto * column_native_type = toNativeType(b, removeNullable(column_type));
|
|
if (!column_native_type)
|
|
throw Exception(ErrorCodes::LOGICAL_ERROR, "No native type for column type {}", column_type->getName());
|
|
|
|
auto * column_native_type_pointer = column_native_type->getPointerTo();
|
|
bool column_type_is_nullable = column_type->isNullable();
|
|
|
|
auto * nullable_unitilized = llvm::Constant::getNullValue(column_native_type_nullable);
|
|
|
|
auto * lhs_column = b.CreateLoad(column_data_type, b.CreateConstInBoundsGEP1_64(column_data_type, columns_lhs_arg, i));
|
|
auto * lhs_column_data = b.CreatePointerCast(b.CreateExtractValue(lhs_column, {0}), column_native_type_pointer);
|
|
auto * lhs_column_null_data = column_type_is_nullable ? b.CreateExtractValue(lhs_column, {1}) : nullptr;
|
|
|
|
llvm::Value * lhs_value = b.CreateLoad(b.CreateInBoundsGEP(nullptr, lhs_column_data, lhs_index_arg));
|
|
|
|
if (lhs_column_null_data)
|
|
{
|
|
auto * is_null_value_pointer = b.CreateInBoundsGEP(nullptr, lhs_column_null_data, lhs_index_arg);
|
|
auto * is_null = b.CreateICmpNE(b.CreateLoad(b.getInt8Ty(), is_null_value_pointer), b.getInt8(0));
|
|
auto * lhs_nullable_value = b.CreateInsertValue(b.CreateInsertValue(nullable_unitilized, lhs_value, {0}), is_null, {1});
|
|
lhs_value = lhs_nullable_value;
|
|
}
|
|
|
|
auto * rhs_column = b.CreateLoad(column_data_type, b.CreateConstInBoundsGEP1_64(column_data_type, columns_rhs_arg, i));
|
|
auto * rhs_column_data = b.CreatePointerCast(b.CreateExtractValue(rhs_column, {0}), column_native_type_pointer);
|
|
auto * rhs_column_null_data = column_type_is_nullable ? b.CreateExtractValue(rhs_column, {1}) : nullptr;
|
|
|
|
llvm::Value * rhs_value = b.CreateLoad(b.CreateInBoundsGEP(nullptr, rhs_column_data, rhs_index_arg));
|
|
if (rhs_column_null_data)
|
|
{
|
|
auto * is_null_value_pointer = b.CreateInBoundsGEP(nullptr, rhs_column_null_data, rhs_index_arg);
|
|
auto * is_null = b.CreateICmpNE(b.CreateLoad(b.getInt8Ty(), is_null_value_pointer), b.getInt8(0));
|
|
auto * rhs_nullable_value = b.CreateInsertValue(b.CreateInsertValue(nullable_unitilized, rhs_value, {0}), is_null, {1});
|
|
rhs_value = rhs_nullable_value;
|
|
}
|
|
|
|
llvm::Value * direction = llvm::ConstantInt::getSigned(b.getInt8Ty(), sort_description.direction);
|
|
llvm::Value * nan_direction_hint = llvm::ConstantInt::getSigned(b.getInt8Ty(), sort_description.nulls_direction);
|
|
llvm::Value * compare_result = dummy_column->compileComparator(b, lhs_value, rhs_value, nan_direction_hint);
|
|
llvm::Value * result = b.CreateMul(direction, compare_result);
|
|
|
|
comparator_steps_and_results[i].first = b.GetInsertBlock();
|
|
comparator_steps_and_results[i].second = result;
|
|
|
|
if (i == columns_size - 1)
|
|
b.CreateBr(comparator_join);
|
|
else
|
|
b.CreateCondBr(b.CreateICmpEQ(result, lhs_equals_rhs_result), comparator_steps_and_results[i + 1].first, comparator_join);
|
|
}
|
|
|
|
b.SetInsertPoint(comparator_join);
|
|
auto * phi = b.CreatePHI(b.getInt8Ty(), comparator_steps_and_results.size());
|
|
|
|
for (const auto & [block, result_value] : comparator_steps_and_results)
|
|
phi->addIncoming(result_value, block);
|
|
|
|
b.CreateRet(phi);
|
|
});
|
|
|
|
ProfileEvents::increment(ProfileEvents::CompileExpressionsMicroseconds, watch.elapsedMicroseconds());
|
|
ProfileEvents::increment(ProfileEvents::CompileExpressionsBytes, compiled_module.size);
|
|
ProfileEvents::increment(ProfileEvents::CompileFunction);
|
|
|
|
auto comparator_function = reinterpret_cast<JITSortDescriptionFunc>(compiled_module.function_name_to_symbol[sort_description_dump]);
|
|
assert(comparator_function);
|
|
|
|
CompiledSortDescriptionFunction compiled_sort_descriptor_function
|
|
{
|
|
.comparator_function = comparator_function,
|
|
|
|
.compiled_module = std::move(compiled_module)
|
|
};
|
|
|
|
return compiled_sort_descriptor_function;
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|