Updated interfaces

This commit is contained in:
Maksim Kita 2021-05-04 01:34:40 +03:00
parent d2eecfe593
commit 24798ef07c
11 changed files with 74 additions and 80 deletions

View File

@ -1323,7 +1323,7 @@ public:
});
}
llvm::Value * compileImpl(llvm::IRBuilderBase & builder, const DataTypes & types, ValuePlaceholders values) const override
llvm::Value * compileImpl(llvm::IRBuilderBase & builder, const DataTypes & types, Values values) const override
{
assert(2 == types.size() && 2 == values.size());
@ -1340,8 +1340,8 @@ public:
{
auto & b = static_cast<llvm::IRBuilder<> &>(builder);
auto type = std::make_shared<ResultDataType>();
auto * lval = nativeCast(b, types[0], values[0](), type);
auto * rval = nativeCast(b, types[1], values[1](), type);
auto * lval = nativeCast(b, types[0], values[0], type);
auto * rval = nativeCast(b, types[1], values[1], type);
result = OpSpec::compile(b, lval, rval, std::is_signed_v<typename ResultDataType::FieldType>);
return true;
}

View File

@ -40,7 +40,7 @@ public:
return true;
}
llvm::Value * compileImpl(llvm::IRBuilderBase & builder, const DataTypes & types, ValuePlaceholders values) const override
llvm::Value * compileImpl(llvm::IRBuilderBase & builder, const DataTypes & types, Values values) const override
{
auto & b = static_cast<llvm::IRBuilder<> &>(builder);
auto type = getReturnTypeImpl(types);
@ -54,7 +54,7 @@ public:
{
auto * then = llvm::BasicBlock::Create(head->getContext(), "", head->getParent());
auto * next = llvm::BasicBlock::Create(head->getContext(), "", head->getParent());
auto * cond = values[i]();
auto * cond = values[i];
if (!null_is_false && types[i]->isNullable())
{
auto * nonnull = llvm::BasicBlock::Create(head->getContext(), "", head->getParent());
@ -68,12 +68,12 @@ public:
b.CreateCondBr(nativeBoolCast(b, types[i], cond), then, next);
}
b.SetInsertPoint(then);
auto * value = nativeCast(b, types[i + 1], values[i + 1](), type);
auto * value = nativeCast(b, types[i + 1], values[i + 1], type);
returns.emplace_back(b.GetInsertBlock(), value);
b.CreateBr(join);
b.SetInsertPoint(next);
}
auto * value = nativeCast(b, types.back(), values.back()(), type);
auto * value = nativeCast(b, types.back(), values.back(), type);
returns.emplace_back(b.GetInsertBlock(), value);
b.CreateBr(join);
b.SetInsertPoint(join);

View File

@ -243,7 +243,7 @@ public:
});
}
llvm::Value * compileImpl(llvm::IRBuilderBase & builder, const DataTypes & types, ValuePlaceholders values) const override
llvm::Value * compileImpl(llvm::IRBuilderBase & builder, const DataTypes & types, Values values) const override
{
assert(1 == types.size() && 1 == values.size());
@ -260,7 +260,7 @@ public:
if constexpr (!std::is_same_v<T1, InvalidType> && !IsDataTypeDecimal<DataType> && Op<T0>::compilable)
{
auto & b = static_cast<llvm::IRBuilder<> &>(builder);
auto * v = nativeCast(b, types[0], values[0](), std::make_shared<DataTypeNumber<T1>>());
auto * v = nativeCast(b, types[0], values[0], std::make_shared<DataTypeNumber<T1>>());
result = Op<T0>::compile(b, v, is_signed_v<T1>);
return true;
}

View File

@ -1254,13 +1254,13 @@ public:
return isCompilableType(types[0]) && isCompilableType(types[1]);
}
llvm::Value * compileImpl(llvm::IRBuilderBase & builder, const DataTypes & types, ValuePlaceholders values) const override
llvm::Value * compileImpl(llvm::IRBuilderBase & builder, const DataTypes & types, Values values) const override
{
assert(2 == types.size() && 2 == values.size());
auto & b = static_cast<llvm::IRBuilder<> &>(builder);
auto * x = values[0]();
auto * y = values[1]();
auto * x = values[0];
auto * y = values[1];
if (!types[0]->equals(*types[1]))
{
llvm::Type * common;

View File

@ -160,16 +160,16 @@ public:
#if USE_EMBEDDED_COMPILER
bool isCompilableImpl(const DataTypes &) const override { return useDefaultImplementationForNulls(); }
llvm::Value * compileImpl(llvm::IRBuilderBase & builder, const DataTypes & types, ValuePlaceholders values) const override
llvm::Value * compileImpl(llvm::IRBuilderBase & builder, const DataTypes & types, Values values) const override
{
assert(!types.empty() && !values.empty());
auto & b = static_cast<llvm::IRBuilder<> &>(builder);
if constexpr (!Impl::isSaturable())
{
auto * result = nativeBoolCast(b, types[0], values[0]());
auto * result = nativeBoolCast(b, types[0], values[0]);
for (size_t i = 1; i < types.size(); i++)
result = Impl::apply(b, result, nativeBoolCast(b, types[i], values[i]()));
result = Impl::apply(b, result, nativeBoolCast(b, types[i], values[i]));
return b.CreateSelect(result, b.getInt8(1), b.getInt8(0));
}
constexpr bool breakOnTrue = Impl::isSaturatedValue(true);
@ -180,7 +180,7 @@ public:
for (size_t i = 0; i < types.size(); i++)
{
b.SetInsertPoint(next);
auto * value = values[i]();
auto * value = values[i];
auto * truth = nativeBoolCast(b, types[i], value);
if (!types[i]->equals(DataTypeUInt8{}))
value = b.CreateSelect(truth, b.getInt8(1), b.getInt8(0));
@ -223,10 +223,10 @@ public:
#if USE_EMBEDDED_COMPILER
bool isCompilableImpl(const DataTypes &) const override { return true; }
llvm::Value * compileImpl(llvm::IRBuilderBase & builder, const DataTypes & types, ValuePlaceholders values) const override
llvm::Value * compileImpl(llvm::IRBuilderBase & builder, const DataTypes & types, Values values) const override
{
auto & b = static_cast<llvm::IRBuilder<> &>(builder);
return b.CreateSelect(Impl<UInt8>::apply(b, nativeBoolCast(b, types[0], values[0]())), b.getInt8(1), b.getInt8(0));
return b.CreateSelect(Impl<UInt8>::apply(b, nativeBoolCast(b, types[0], values[0])), b.getInt8(1), b.getInt8(0));
}
#endif
};

View File

@ -516,58 +516,47 @@ bool IFunction::isCompilable(const DataTypes & arguments) const
return isCompilableImpl(arguments);
}
llvm::Value * IFunction::compile(llvm::IRBuilderBase & builder, const DataTypes & arguments, ValuePlaceholders values) const
llvm::Value * IFunction::compile(llvm::IRBuilderBase & builder, const DataTypes & arguments, Values values) const
{
auto denulled_arguments = removeNullables(arguments);
if (useDefaultImplementationForNulls() && denulled_arguments)
{
auto & b = static_cast<llvm::IRBuilder<> &>(builder);
std::vector<llvm::Value*> non_lazy_values;
std::vector<llvm::Value*> unwrapped_values;
std::vector<llvm::Value*> is_null_values;
non_lazy_values.reserve(arguments.size());
unwrapped_values.reserve(arguments.size());
is_null_values.reserve(arguments.size());
for (size_t i = 0; i < arguments.size(); ++i)
{
auto * value = values[i]();
auto * value = values[i];
WhichDataType data_type(arguments[i]);
if (data_type.isNullable())
{
non_lazy_values.emplace_back(b.CreateExtractValue(value, {0}));
unwrapped_values.emplace_back(b.CreateExtractValue(value, {0}));
is_null_values.emplace_back(b.CreateExtractValue(value, {1}));
}
else
{
non_lazy_values.emplace_back(value);
unwrapped_values.emplace_back(value);
}
}
ValuePlaceholders place_holders;
place_holders.reserve(non_lazy_values.size());
auto * result = compileImpl(builder, *denulled_arguments, unwrapped_values);
for (size_t i = 0; i < non_lazy_values.size(); ++i)
place_holders.emplace_back([lazy_value = non_lazy_values[i]](){ return lazy_value; });
auto * nullable_structure_type = toNativeType(b, makeNullable(getReturnTypeImpl(*denulled_arguments)));
auto * nullable_structure_value = llvm::Constant::getNullValue(nullable_structure_type);
auto * result = compileImpl(builder, *denulled_arguments, place_holders);
auto * nullable_structure_with_result_value = b.CreateInsertValue(nullable_structure_value, result, {0});
auto * nullable_structure_result_null = b.CreateExtractValue(nullable_structure_with_result_value, {1});
if (!is_null_values.empty())
{
auto * nullable_structure_type = toNativeType(b, makeNullable(getReturnTypeImpl(*denulled_arguments)));
auto * nullable_structure_value = llvm::Constant::getNullValue(nullable_structure_type);
for (auto * is_null_value : is_null_values)
nullable_structure_result_null = b.CreateOr(nullable_structure_result_null, is_null_value);
auto * nullable_structure_with_result_value = b.CreateInsertValue(nullable_structure_value, result, {0});
auto * nullable_structure_result_null = b.CreateExtractValue(nullable_structure_with_result_value, {1});
for (auto * is_null_value : is_null_values)
nullable_structure_result_null = b.CreateOr(nullable_structure_result_null, is_null_value);
return b.CreateInsertValue(nullable_structure_with_result_value, nullable_structure_result_null, {1});
}
return result;
return b.CreateInsertValue(nullable_structure_with_result_value, nullable_structure_result_null, {1});
// DataTypes non_null_arguments;
// non_null_arguments.reserve(arguments.size());

View File

@ -54,7 +54,7 @@ public:
using ExecutableFunctionPtr = std::shared_ptr<IExecutableFunction>;
using ValuePlaceholders = std::vector<std::function<llvm::Value * ()>>;
using Values = std::vector<llvm::Value *>;
/// Function with known arguments and return type (when the specific overload was chosen).
/// It is also the point where all function-specific properties are known.
@ -90,7 +90,7 @@ public:
* templates with default arguments is impossible and including LLVM in such a generic header
* as this one is a major pain.
*/
virtual llvm::Value * compile(llvm::IRBuilderBase & /*builder*/, ValuePlaceholders /*values*/) const
virtual llvm::Value * compile(llvm::IRBuilderBase & /*builder*/, Values /*values*/) const
{
throw Exception(getName() + " is not JIT-compilable", ErrorCodes::NOT_IMPLEMENTED);
}

View File

@ -54,7 +54,7 @@ public:
bool isCompilable() const final { return impl->isCompilable(); }
llvm::Value * compile(llvm::IRBuilderBase & builder, ValuePlaceholders values) const override
llvm::Value * compile(llvm::IRBuilderBase & builder, Values values) const override
{
return impl->compile(builder, std::move(values));
}
@ -183,7 +183,10 @@ public:
bool isCompilable() const override { return function->isCompilable(getArgumentTypes()); }
llvm::Value * compile(llvm::IRBuilderBase & builder, ValuePlaceholders values) const override { return function->compile(builder, getArgumentTypes(), std::move(values)); }
llvm::Value * compile(llvm::IRBuilderBase & builder, Values values) const override
{
return function->compile(builder, getArgumentTypes(), std::move(values));
}
#endif

View File

@ -96,7 +96,7 @@ public:
virtual bool isCompilable() const { return false; }
virtual llvm::Value * compile(llvm::IRBuilderBase & /*builder*/, ValuePlaceholders /*values*/) const
virtual llvm::Value * compile(llvm::IRBuilderBase & /*builder*/, Values /*values*/) const
{
throw Exception(getName() + " is not JIT-compilable", ErrorCodes::NOT_IMPLEMENTED);
}
@ -284,7 +284,7 @@ public:
bool isCompilable(const DataTypes & arguments) const;
llvm::Value * compile(llvm::IRBuilderBase &, const DataTypes & arguments, ValuePlaceholders values) const;
llvm::Value * compile(llvm::IRBuilderBase &, const DataTypes & arguments, Values values) const;
#endif
@ -294,7 +294,7 @@ protected:
virtual bool isCompilableImpl(const DataTypes &) const { return false; }
virtual llvm::Value * compileImpl(llvm::IRBuilderBase &, const DataTypes &, ValuePlaceholders) const
virtual llvm::Value * compileImpl(llvm::IRBuilderBase &, const DataTypes &, Values) const
{
throw Exception(getName() + " is not JIT-compilable", ErrorCodes::NOT_IMPLEMENTED);
}

View File

@ -46,14 +46,12 @@ namespace
{
const char * data = nullptr;
const char * null = nullptr;
size_t stride = 0;
};
struct ColumnDataPlaceholder
{
llvm::Value * data_init; /// first row
llvm::Value * null_init;
llvm::Value * stride;
llvm::PHINode * data; /// current row
llvm::PHINode * null;
};
@ -63,16 +61,18 @@ static ColumnData getColumnData(const IColumn * column)
{
ColumnData result;
const bool is_const = isColumnConst(*column);
/// TODO: There should be no const columns
if (is_const)
column = &reinterpret_cast<const ColumnConst *>(column)->getDataColumn();
throw Exception(ErrorCodes::LOGICAL_ERROR, "Input columns should not be constant");
if (const auto * nullable = typeid_cast<const ColumnNullable *>(column))
{
result.null = nullable->getNullMapColumn().getRawData().data;
column = &nullable->getNestedColumn();
}
result.data = column->getRawData().data;
result.stride = is_const ? 0 : column->sizeOfValueIfFixed();
return result;
}
@ -123,6 +123,7 @@ public:
const auto * column = arguments[i].column.get();
if (!column)
throw Exception("Column " + arguments[i].name + " is missing", ErrorCodes::LOGICAL_ERROR);
columns[i] = getColumnData(column);
}
@ -182,7 +183,6 @@ static void compileFunction(llvm::Module & module, const IFunctionBaseImpl & f)
auto * data = b.CreateLoad(b.CreateConstInBoundsGEP1_32(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;
columns[i].stride = b.CreateExtractValue(data, {2});
}
/// assume nonzero initial value in `counter_arg`
@ -202,20 +202,25 @@ static void compileFunction(llvm::Module & module, const IFunctionBaseImpl & f)
}
}
ValuePlaceholders arguments(arg_types.size());
for (size_t i = 0; i < arguments.size(); ++i) // NOLINT
Values arguments;
arguments.reserve(arg_types.size());
for (size_t i = 0; i < arg_types.size(); ++i) // NOLINT
{
arguments[i] = [&b, &col = columns[i], &type = arg_types[i]]() -> llvm::Value *
auto & column = columns[i];
auto type = arg_types[i];
auto * value = b.CreateLoad(column.data);
if (!column.null)
{
auto * value = b.CreateLoad(col.data);
if (!col.null)
return value;
arguments.emplace_back(value);
continue;
}
auto * is_null = b.CreateICmpNE(b.CreateLoad(col.null), b.getInt8(0));
auto * nullable = llvm::Constant::getNullValue(toNativeType(b, type));
return b.CreateInsertValue(b.CreateInsertValue(nullable, value, {0}), is_null, {1});
};
auto * is_null = b.CreateICmpNE(b.CreateLoad(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);
}
auto * result = f.compile(b, std::move(arguments));
@ -269,35 +274,32 @@ static llvm::Constant * getNativeValue(llvm::Type * type, const IColumn & column
}
/// Same as IFunctionBase::compile, but also for constants and input columns.
using CompilableExpression = std::function<llvm::Value * (llvm::IRBuilderBase &, const ValuePlaceholders &)>;
static CompilableExpression subexpression(ColumnPtr c, DataTypePtr type)
{
return [=](llvm::IRBuilderBase & b, const ValuePlaceholders &)
return [=](llvm::IRBuilderBase & b, const Values &)
{
auto * native_value = getNativeValue(toNativeType(b, type), *c, 0);
llvm::errs() << "Constant subexpression " << *native_value->getType() << "\n";
return native_value;
};
}
static CompilableExpression subexpression(size_t i)
{
return [=](llvm::IRBuilderBase &, const ValuePlaceholders & inputs)
return [=](llvm::IRBuilderBase &, const Values & inputs)
{
auto * column = inputs[i]();
llvm::errs() << "Column subexpression " << *column->getType() << "\n";
auto * column = inputs[i];
return column;
};
}
static CompilableExpression subexpression(const IFunctionBase & f, std::vector<CompilableExpression> args)
{
return [&, args = std::move(args)](llvm::IRBuilderBase & builder, const ValuePlaceholders & inputs)
return [&, args = std::move(args)](llvm::IRBuilderBase & builder, const Values & inputs)
{
ValuePlaceholders input;
Values input;
for (const auto & arg : args)
input.push_back([&]() { return arg(builder, inputs); });
input.push_back(arg(builder, inputs));
auto * result = f.compile(builder, input);
if (result->getType() != toNativeType(builder, f.getResultType()))
@ -369,11 +371,11 @@ LLVMFunction::LLVMFunction(const CompileDAG & dag)
// std::cerr << "Func name " << std::string(func.getName()) << std::endl;
// }
module.print(llvm::errs(), nullptr);
// module.print(llvm::errs(), nullptr);
});
}
llvm::Value * LLVMFunction::compile(llvm::IRBuilderBase & builder, ValuePlaceholders values) const
llvm::Value * LLVMFunction::compile(llvm::IRBuilderBase & builder, Values values) const
{
return expression(builder, values);
}

View File

@ -15,7 +15,7 @@
namespace DB
{
using CompilableExpression = std::function<llvm::Value * (llvm::IRBuilderBase &, const ValuePlaceholders &)>;
using CompilableExpression = std::function<llvm::Value * (llvm::IRBuilderBase &, const Values &)>;
class LLVMFunction : public IFunctionBaseImpl
{
@ -61,7 +61,7 @@ public:
bool isCompilable() const override { return true; }
llvm::Value * compile(llvm::IRBuilderBase & builder, ValuePlaceholders values) const override;
llvm::Value * compile(llvm::IRBuilderBase & builder, Values values) const override;
String getName() const override { return name; }