mkql_coalesce.cpp 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. #include "mkql_coalesce.h"
  2. #include <yql/essentials/minikql/computation/mkql_computation_node_codegen.h> // Y_IGNORE
  3. #include <yql/essentials/minikql/mkql_node_cast.h>
  4. #include <yql/essentials/minikql/mkql_node_builder.h>
  5. namespace NKikimr {
  6. namespace NMiniKQL {
  7. namespace {
  8. template<bool Unpack>
  9. class TCoalesceWrapper : public TBinaryCodegeneratorNode<TCoalesceWrapper<Unpack>> {
  10. typedef TBinaryCodegeneratorNode<TCoalesceWrapper<Unpack>> TBaseComputation;
  11. public:
  12. TCoalesceWrapper(IComputationNode* left, IComputationNode* right, EValueRepresentation kind)
  13. : TBaseComputation(left, right, kind)
  14. {
  15. }
  16. NUdf::TUnboxedValuePod DoCalculate(TComputationContext& compCtx) const {
  17. if (auto left = this->Left->GetValue(compCtx)) {
  18. return left.Release().template GetOptionalValueIf<Unpack>();
  19. }
  20. return this->Right->GetValue(compCtx).Release();
  21. }
  22. #ifndef MKQL_DISABLE_CODEGEN
  23. Value* DoGenerateGetValue(const TCodegenContext& ctx, BasicBlock*& block) const {
  24. auto& context = ctx.Codegen.GetContext();
  25. const auto left = GetNodeValue(this->Left, ctx, block);
  26. const auto null = BasicBlock::Create(context, "null", ctx.Func);
  27. const auto good = BasicBlock::Create(context, "good", ctx.Func);
  28. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  29. const auto result = PHINode::Create(left->getType(), 2, "result", done);
  30. BranchInst::Create(good, null, IsExists(left, block, context), block);
  31. block = null;
  32. const auto right = GetNodeValue(this->Right, ctx, block);
  33. result->addIncoming(right, block);
  34. BranchInst::Create(done, block);
  35. block = good;
  36. const auto unpack = Unpack ? GetOptionalValue(context, left, block) : left;
  37. result->addIncoming(unpack, block);
  38. BranchInst::Create(done, block);
  39. block = done;
  40. return result;
  41. }
  42. #endif
  43. };
  44. }
  45. IComputationNode* WrapCoalesce(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
  46. MKQL_ENSURE(callable.GetInputsCount() == 2, "Expected 2 args");
  47. bool isLeftOptional = false;
  48. const auto& leftType = UnpackOptional(callable.GetInput(0), isLeftOptional);
  49. MKQL_ENSURE(isLeftOptional || leftType->IsPg(), "Expected optional or pg");
  50. bool isRightOptional = false;
  51. if (!leftType->IsSameType(*callable.GetInput(1).GetStaticType())) {
  52. const auto& rightType = UnpackOptional(callable.GetInput(1), isRightOptional);
  53. MKQL_ENSURE(leftType->IsSameType(*rightType), "Mismatch types");
  54. }
  55. const auto kind = GetValueRepresentation(callable.GetType()->GetReturnType());
  56. if (isRightOptional)
  57. return new TCoalesceWrapper<false>(LocateNode(ctx.NodeLocator, callable, 0), LocateNode(ctx.NodeLocator, callable, 1), kind);
  58. else
  59. return new TCoalesceWrapper<true>(LocateNode(ctx.NodeLocator, callable, 0), LocateNode(ctx.NodeLocator, callable, 1), kind);
  60. }
  61. }
  62. }