#include "mkql_logical.h" #include // Y_IGNORE #include #include #include "mkql_check_args.h" namespace NKikimr { namespace NMiniKQL { namespace { template class TAndWrapper : public TBinaryCodegeneratorNode> { typedef TBinaryCodegeneratorNode> 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()) { return NUdf::TUnboxedValuePod(false); } } const auto& right = this->Right->GetValue(ctx); if (!IsRightOptional || right) { if (!right.template Get()) { 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 class TOrWrapper : public TBinaryCodegeneratorNode> { typedef TBinaryCodegeneratorNode> 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()) { return NUdf::TUnboxedValuePod(true); } } const auto& right = this->Right->GetValue(ctx); if (!IsRightOptional || right) { if (right.template Get()) { 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 class TXorWrapper : public TBinaryCodegeneratorNode> { typedef TBinaryCodegeneratorNode> 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() != right.template Get(); 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 class TNotWrapper : public TDecoratorCodegeneratorNode> { typedef TDecoratorCodegeneratorNode> 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(); 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(xorr); return result; } #endif }; template