Add a JIT interface for row-wise default-nullable functions.
Not actually implemented, though. It does print out some jit-compiled stuff,
but that's about it. For example, this query:
select number from system.numbers where something(cast(number as Float64)) == 4
results in this on server's stderr:
define double @"something(CAST(number, 'Float64'))"(void**, i8*, void*) {
"something(CAST(number, 'Float64'))":
ret double 1.234500e+04
}
(and an exception, because that's what the non-jitted method does.)
As one may notice, this function neither reads the input (first argument;
tuple of arrays) nor writes the output (third argument; array), instead
returning some general nonsense.
In addition, `#if USE_EMBEDDED_COMPILER` doesn't work for some reason,
including LLVM headers requires -Wno-unused-parameter, this probably only
works on LLVM 5.0 due to rampant API instability, and I'm definitely
no expert on CMake. In short, there's still a long way to go.
2018-04-23 22:29:39 +00:00
|
|
|
#pragma once
|
|
|
|
|
2019-06-24 11:17:15 +00:00
|
|
|
#include "config_core.h"
|
2018-04-25 15:19:22 +00:00
|
|
|
#if USE_EMBEDDED_COMPILER
|
|
|
|
|
2019-12-10 10:56:30 +00:00
|
|
|
#include <Functions/IFunctionImpl.h>
|
2018-08-30 16:31:20 +00:00
|
|
|
#include <Interpreters/Context.h>
|
2018-05-06 09:32:36 +00:00
|
|
|
#include <Interpreters/ExpressionActions.h>
|
2018-09-03 10:14:05 +00:00
|
|
|
#include <Common/LRUCache.h>
|
|
|
|
#include <set>
|
2018-05-06 09:32:36 +00:00
|
|
|
|
2018-08-30 16:31:20 +00:00
|
|
|
|
Add a JIT interface for row-wise default-nullable functions.
Not actually implemented, though. It does print out some jit-compiled stuff,
but that's about it. For example, this query:
select number from system.numbers where something(cast(number as Float64)) == 4
results in this on server's stderr:
define double @"something(CAST(number, 'Float64'))"(void**, i8*, void*) {
"something(CAST(number, 'Float64'))":
ret double 1.234500e+04
}
(and an exception, because that's what the non-jitted method does.)
As one may notice, this function neither reads the input (first argument;
tuple of arrays) nor writes the output (third argument; array), instead
returning some general nonsense.
In addition, `#if USE_EMBEDDED_COMPILER` doesn't work for some reason,
including LLVM headers requires -Wno-unused-parameter, this probably only
works on LLVM 5.0 due to rampant API instability, and I'm definitely
no expert on CMake. In short, there's still a long way to go.
2018-04-23 22:29:39 +00:00
|
|
|
namespace DB
|
|
|
|
{
|
2018-09-03 10:14:05 +00:00
|
|
|
|
2018-08-30 16:31:20 +00:00
|
|
|
using CompilableExpression = std::function<llvm::Value * (llvm::IRBuilderBase &, const ValuePlaceholders &)>;
|
|
|
|
|
2019-01-11 21:16:49 +00:00
|
|
|
struct LLVMModuleState;
|
|
|
|
|
2019-12-10 10:56:30 +00:00
|
|
|
class LLVMFunction : public IFunctionBaseImpl
|
2018-08-30 16:31:20 +00:00
|
|
|
{
|
|
|
|
std::string name;
|
|
|
|
Names arg_names;
|
|
|
|
DataTypes arg_types;
|
2019-01-11 21:16:49 +00:00
|
|
|
|
2018-08-30 16:31:20 +00:00
|
|
|
std::vector<FunctionBasePtr> originals;
|
2019-01-11 21:18:57 +00:00
|
|
|
std::unordered_map<StringRef, CompilableExpression> subexpressions;
|
2019-01-11 21:16:49 +00:00
|
|
|
|
|
|
|
std::unique_ptr<LLVMModuleState> module_state;
|
|
|
|
|
2018-08-30 16:31:20 +00:00
|
|
|
public:
|
2019-01-11 21:16:49 +00:00
|
|
|
LLVMFunction(const ExpressionActions::Actions & actions, const Block & sample_block);
|
2018-08-30 16:31:20 +00:00
|
|
|
|
|
|
|
bool isCompilable() const override { return true; }
|
|
|
|
|
2018-10-11 20:31:41 +00:00
|
|
|
llvm::Value * compile(llvm::IRBuilderBase & builder, ValuePlaceholders values) const override;
|
2018-08-30 16:31:20 +00:00
|
|
|
|
|
|
|
String getName() const override { return name; }
|
|
|
|
|
|
|
|
const Names & getArgumentNames() const { return arg_names; }
|
|
|
|
|
|
|
|
const DataTypes & getArgumentTypes() const override { return arg_types; }
|
|
|
|
|
|
|
|
const DataTypePtr & getReturnType() const override { return originals.back()->getReturnType(); }
|
|
|
|
|
2019-12-10 10:56:30 +00:00
|
|
|
ExecutableFunctionImplPtr prepare(const Block &, const ColumnNumbers &, size_t) const override;
|
2018-08-30 16:31:20 +00:00
|
|
|
|
|
|
|
bool isDeterministic() const override;
|
|
|
|
|
|
|
|
bool isDeterministicInScopeOfQuery() const override;
|
|
|
|
|
|
|
|
bool isSuitableForConstantFolding() const override;
|
|
|
|
|
|
|
|
bool isInjective(const Block & sample_block) override;
|
|
|
|
|
|
|
|
bool hasInformationAboutMonotonicity() const override;
|
|
|
|
|
|
|
|
Monotonicity getMonotonicityForRange(const IDataType & type, const Field & left, const Field & right) const override;
|
2018-09-03 10:14:05 +00:00
|
|
|
|
2019-01-11 21:16:49 +00:00
|
|
|
const LLVMModuleState * getLLVMModuleState() const { return module_state.get(); }
|
2018-08-30 16:31:20 +00:00
|
|
|
};
|
|
|
|
|
2018-09-03 10:14:05 +00:00
|
|
|
/** This child of LRUCache breaks one of it's invariants: total weight may be changed after insertion.
|
|
|
|
* We have to do so, because we don't known real memory consumption of generated LLVM code for every function.
|
|
|
|
*/
|
2019-12-10 13:28:22 +00:00
|
|
|
class CompiledExpressionCache : public LRUCache<UInt128, IFunctionBase, UInt128Hash>
|
2018-09-03 10:14:05 +00:00
|
|
|
{
|
|
|
|
public:
|
2019-12-10 13:28:22 +00:00
|
|
|
using Base = LRUCache<UInt128, IFunctionBase, UInt128Hash>;
|
2018-09-03 10:14:05 +00:00
|
|
|
using Base::Base;
|
|
|
|
};
|
Add a JIT interface for row-wise default-nullable functions.
Not actually implemented, though. It does print out some jit-compiled stuff,
but that's about it. For example, this query:
select number from system.numbers where something(cast(number as Float64)) == 4
results in this on server's stderr:
define double @"something(CAST(number, 'Float64'))"(void**, i8*, void*) {
"something(CAST(number, 'Float64'))":
ret double 1.234500e+04
}
(and an exception, because that's what the non-jitted method does.)
As one may notice, this function neither reads the input (first argument;
tuple of arrays) nor writes the output (third argument; array), instead
returning some general nonsense.
In addition, `#if USE_EMBEDDED_COMPILER` doesn't work for some reason,
including LLVM headers requires -Wno-unused-parameter, this probably only
works on LLVM 5.0 due to rampant API instability, and I'm definitely
no expert on CMake. In short, there's still a long way to go.
2018-04-23 22:29:39 +00:00
|
|
|
|
2018-04-29 01:00:26 +00:00
|
|
|
/// For each APPLY_FUNCTION action, try to compile the function to native code; if the only uses of a compilable
|
|
|
|
/// function's result are as arguments to other compilable functions, inline it and leave the now-redundant action as-is.
|
2019-02-11 14:36:54 +00:00
|
|
|
void compileFunctions(ExpressionActions::Actions & actions, const Names & output_columns, const Block & sample_block, std::shared_ptr<CompiledExpressionCache> compilation_cache, size_t min_count_to_compile_expression);
|
Add a JIT interface for row-wise default-nullable functions.
Not actually implemented, though. It does print out some jit-compiled stuff,
but that's about it. For example, this query:
select number from system.numbers where something(cast(number as Float64)) == 4
results in this on server's stderr:
define double @"something(CAST(number, 'Float64'))"(void**, i8*, void*) {
"something(CAST(number, 'Float64'))":
ret double 1.234500e+04
}
(and an exception, because that's what the non-jitted method does.)
As one may notice, this function neither reads the input (first argument;
tuple of arrays) nor writes the output (third argument; array), instead
returning some general nonsense.
In addition, `#if USE_EMBEDDED_COMPILER` doesn't work for some reason,
including LLVM headers requires -Wno-unused-parameter, this probably only
works on LLVM 5.0 due to rampant API instability, and I'm definitely
no expert on CMake. In short, there's still a long way to go.
2018-04-23 22:29:39 +00:00
|
|
|
|
|
|
|
}
|
2018-04-25 15:19:22 +00:00
|
|
|
|
|
|
|
#endif
|