123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- #include "mkql_logical.h"
- #include <yql/essentials/minikql/computation/mkql_computation_node_codegen.h> // Y_IGNORE
- #include <yql/essentials/minikql/mkql_node_cast.h>
- #include <yql/essentials/minikql/mkql_node_builder.h>
- #include "mkql_check_args.h"
- namespace NKikimr {
- namespace NMiniKQL {
- namespace {
- template <bool IsLeftOptional, bool IsRightOptional>
- class TAndWrapper : public TBinaryCodegeneratorNode<TAndWrapper<IsLeftOptional, IsRightOptional>> {
- typedef TBinaryCodegeneratorNode<TAndWrapper<IsLeftOptional, IsRightOptional>> TBaseComputation;
- public:
- TAndWrapper(TComputationMutables& mutables, IComputationNode* left, IComputationNode* right)
- : TBaseComputation(left, right, EValueRepresentation::Embedded)
- {
- Y_UNUSED(mutables);
- }
- NUdf::TUnboxedValuePod DoCalculate(TComputationContext& ctx) const {
- const auto& left = this->Left->GetValue(ctx);
- if (!IsLeftOptional || left) {
- if (!left.template Get<bool>()) {
- return NUdf::TUnboxedValuePod(false);
- }
- }
- const auto& right = this->Right->GetValue(ctx);
- if (!IsRightOptional || right) {
- if (!right.template Get<bool>()) {
- return NUdf::TUnboxedValuePod(false);
- }
- }
- // both either true (just true) or nothing
- if (IsLeftOptional && !left || IsRightOptional && !right) {
- return NUdf::TUnboxedValuePod();
- }
- return NUdf::TUnboxedValuePod(true);
- }
- #ifndef MKQL_DISABLE_CODEGEN
- Value* DoGenerateGetValue(const TCodegenContext& ctx, BasicBlock*& block) const {
- auto& context = ctx.Codegen.GetContext();
- const auto valueType = Type::getInt128Ty(context);
- const auto left = GetNodeValue(this->Left, ctx, block);
- const auto uvFalse = GetFalse(context);
- const auto skip = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, left, uvFalse, "skip", block);
- const auto both = BasicBlock::Create(context, "both", ctx.Func);
- const auto done = BasicBlock::Create(context, "done", ctx.Func);
- const auto result = PHINode::Create(valueType, 2, "result", done);
- result->addIncoming(uvFalse, block);
- BranchInst::Create(done, both, skip, block);
- block = both;
- const auto right = GetNodeValue(this->Right, ctx, block);
- if (IsLeftOptional) {
- const auto andr = BinaryOperator::CreateAnd(left, right, "and", block);
- const auto over = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, right, uvFalse, "over", block);
- const auto full = SelectInst::Create(over, uvFalse, andr, "full", block);
- result->addIncoming(full, block);
- } else {
- result->addIncoming(right, block);
- }
- BranchInst::Create(done, block);
- block = done;
- return result;
- }
- #endif
- };
- template <bool IsLeftOptional, bool IsRightOptional>
- class TOrWrapper : public TBinaryCodegeneratorNode<TOrWrapper<IsLeftOptional, IsRightOptional>> {
- typedef TBinaryCodegeneratorNode<TOrWrapper<IsLeftOptional, IsRightOptional>> TBaseComputation;
- public:
- TOrWrapper(TComputationMutables& mutables, IComputationNode* left, IComputationNode* right)
- : TBaseComputation(left, right, EValueRepresentation::Embedded)
- {
- Y_UNUSED(mutables);
- }
- NUdf::TUnboxedValuePod DoCalculate(TComputationContext& ctx) const {
- const auto& left = this->Left->GetValue(ctx);
- if (!IsLeftOptional || left) {
- if (left.template Get<bool>()) {
- return NUdf::TUnboxedValuePod(true);
- }
- }
- const auto& right = this->Right->GetValue(ctx);
- if (!IsRightOptional || right) {
- if (right.template Get<bool>()) {
- return NUdf::TUnboxedValuePod(true);
- }
- }
- // both either false (just false) or nothing
- if (IsLeftOptional && !left || IsRightOptional && !right) {
- return NUdf::TUnboxedValuePod();
- }
- return NUdf::TUnboxedValuePod(false);
- }
- #ifndef MKQL_DISABLE_CODEGEN
- Value* DoGenerateGetValue(const TCodegenContext& ctx, BasicBlock*& block) const {
- auto& context = ctx.Codegen.GetContext();
- const auto valueType = Type::getInt128Ty(context);
- const auto left = GetNodeValue(this->Left, ctx, block);
- const auto uvTrue = GetTrue(context);
- const auto skip = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, left, uvTrue, "skip", block);
- const auto both = BasicBlock::Create(context, "both", ctx.Func);
- const auto done = BasicBlock::Create(context, "done", ctx.Func);
- const auto result = PHINode::Create(valueType, 2, "result", done);
- result->addIncoming(uvTrue, block);
- BranchInst::Create(done, both, skip, block);
- block = both;
- const auto right = GetNodeValue(this->Right, ctx, block);
- if (IsLeftOptional) {
- const auto andr = BinaryOperator::CreateAnd(left, right, "and", block);
- const auto over = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, right, uvTrue, "over", block);
- const auto full = SelectInst::Create(over, uvTrue, andr, "full", block);
- result->addIncoming(full, block);
- } else {
- result->addIncoming(right, block);
- }
- BranchInst::Create(done, block);
- block = done;
- return result;
- }
- #endif
- };
- template <bool IsLeftOptional, bool IsRightOptional>
- class TXorWrapper : public TBinaryCodegeneratorNode<TXorWrapper<IsLeftOptional, IsRightOptional>> {
- typedef TBinaryCodegeneratorNode<TXorWrapper<IsLeftOptional, IsRightOptional>> TBaseComputation;
- public:
- TXorWrapper(TComputationMutables& mutables, IComputationNode* left, IComputationNode* right)
- : TBaseComputation(left, right, EValueRepresentation::Embedded)
- {
- Y_UNUSED(mutables);
- }
- NUdf::TUnboxedValuePod DoCalculate(TComputationContext& ctx) const {
- const auto& left = this->Left->GetValue(ctx);
- if (IsLeftOptional && !left) {
- return NUdf::TUnboxedValuePod();
- }
- const auto& right = this->Right->GetValue(ctx);
- if (IsRightOptional && !right) {
- return NUdf::TUnboxedValuePod();
- }
- const bool res = left.template Get<bool>() != right.template Get<bool>();
- return NUdf::TUnboxedValuePod(res);
- }
- #ifndef MKQL_DISABLE_CODEGEN
- Value* DoGenerateGetValue(const TCodegenContext& ctx, BasicBlock*& block) const {
- auto& context = ctx.Codegen.GetContext();
- const auto valueType = Type::getInt128Ty(context);
- if (IsLeftOptional || IsRightOptional) {
- const auto zero = ConstantInt::get(valueType, 0);
- const auto both = BasicBlock::Create(context, "both", ctx.Func);
- const auto done = BasicBlock::Create(context, "done", ctx.Func);
- const auto result = PHINode::Create(valueType, 2, "result", done);
- if (IsLeftOptional) {
- const auto left = GetNodeValue(this->Left, ctx, block);
- const auto skip = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, left, zero, "skip", block);
- result->addIncoming(zero, block);
- BranchInst::Create(done, both, skip, block);
- block = both;
- const auto right = GetNodeValue(this->Right, ctx, block);
- if (IsRightOptional) {
- const auto xorr = BinaryOperator::CreateXor(left, right, "xor", block);
- const auto full = BinaryOperator::CreateOr(xorr, GetFalse(context), "full", block);
- const auto null = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, right, zero, "null", block);
- const auto last = SelectInst::Create(null, zero, full, "last", block);
- result->addIncoming(last, block);
- } else {
- const auto xorr = BinaryOperator::CreateXor(left, right, "xor", block);
- const auto full = BinaryOperator::CreateOr(xorr, GetFalse(context), "full", block);
- result->addIncoming(full, block);
- }
- } else if (IsRightOptional) {
- const auto right = GetNodeValue(this->Right, ctx, block);
- const auto skip = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, right, zero, "skip", block);
- result->addIncoming(zero, block);
- BranchInst::Create(done, both, skip, block);
- block = both;
- const auto left = GetNodeValue(this->Left, ctx, block);
- const auto xorr = BinaryOperator::CreateXor(left, right, "xor", block);
- const auto full = BinaryOperator::CreateOr(xorr, GetFalse(context), "full", block);
- result->addIncoming(full, block);
- }
- BranchInst::Create(done, block);
- block = done;
- return result;
- } else {
- const auto left = GetNodeValue(this->Left, ctx, block);
- const auto right = GetNodeValue(this->Right, ctx, block);
- const auto xorr = BinaryOperator::CreateXor(left, right, "xor", block);
- const auto full = BinaryOperator::CreateOr(xorr, GetFalse(context), "full", block);
- return full;
- }
- }
- #endif
- };
- template <bool IsOptional>
- class TNotWrapper : public TDecoratorCodegeneratorNode<TNotWrapper<IsOptional>> {
- typedef TDecoratorCodegeneratorNode<TNotWrapper<IsOptional>> TBaseComputation;
- public:
- TNotWrapper(IComputationNode* arg)
- : TBaseComputation(arg)
- {}
- NUdf::TUnboxedValuePod DoCalculate(TComputationContext&, const NUdf::TUnboxedValuePod& arg) const {
- if (IsOptional && !arg) {
- return NUdf::TUnboxedValuePod();
- }
- const bool res = !arg.template Get<bool>();
- return NUdf::TUnboxedValuePod(res);
- }
- #ifndef MKQL_DISABLE_CODEGEN
- Value* DoGenerateGetValue(const TCodegenContext& ctx, Value* arg, BasicBlock*& block) const {
- auto& context = ctx.Codegen.GetContext();
- const auto xorr = BinaryOperator::CreateXor(arg, ConstantInt::get(arg->getType(), 1), "xor", block);
- const auto result = IsOptional ? SelectInst::Create(IsExists(arg, block, context), xorr, arg, "sel", block) : static_cast<Value*>(xorr);
- return result;
- }
- #endif
- };
- template <template <bool, bool> class TWrapper>
- IComputationNode* WrapLogicalFunction(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
- const auto nodeLocator = ctx.NodeLocator;
- MKQL_ENSURE(callable.GetInputsCount() == 2, "Expected 2 args");
- const auto leftType = callable.GetInput(0).GetStaticType();
- const auto rightType = callable.GetInput(1).GetStaticType();
- CheckBinaryFunctionArgs(leftType, rightType, true, true);
- const bool isLeftOptional = leftType->IsOptional();
- const bool isRightOptional = rightType->IsOptional();
- const auto left = LocateNode(nodeLocator, callable, 0);
- const auto right = LocateNode(nodeLocator, callable, 1);
- if (isLeftOptional) {
- if (isRightOptional) {
- return new TWrapper<true, true>(ctx.Mutables, left, right);
- } else {
- return new TWrapper<true, false>(ctx.Mutables, left, right);
- }
- }
- else {
- if (isRightOptional) {
- return new TWrapper<false, true>(ctx.Mutables, left, right);
- } else {
- return new TWrapper<false, false>(ctx.Mutables, left, right);
- }
- }
- }
- }
- IComputationNode* WrapAnd(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
- return WrapLogicalFunction<TAndWrapper>(callable, ctx);
- }
- IComputationNode* WrapOr(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
- return WrapLogicalFunction<TOrWrapper>(callable, ctx);
- }
- IComputationNode* WrapXor(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
- return WrapLogicalFunction<TXorWrapper>(callable, ctx);
- }
- IComputationNode* WrapNot(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
- MKQL_ENSURE(callable.GetInputsCount() == 1, "Expected 1 arg");
- bool isOptional;
- const auto& dataType = UnpackOptionalData(callable.GetInput(0), isOptional);
- const auto schemeType = dataType->GetSchemeType();
- MKQL_ENSURE(schemeType == NUdf::TDataType<bool>::Id, "Expected bool");
- const auto node = LocateNode(ctx.NodeLocator, callable, 0);
- if (isOptional) {
- return new TNotWrapper<true>(node);
- }
- else {
- return new TNotWrapper<false>(node);
- }
- }
- }
- }
|