mkql_lazy_list.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. #include "mkql_lazy_list.h"
  2. #include <yql/essentials/minikql/computation/mkql_computation_node_holders.h>
  3. #include <yql/essentials/minikql/computation/mkql_computation_node_codegen.h> // Y_IGNORE
  4. #include <yql/essentials/minikql/mkql_node_cast.h>
  5. namespace NKikimr {
  6. namespace NMiniKQL {
  7. namespace {
  8. template <bool IsOptional>
  9. class TLazyListWrapper : public TMutableCodegeneratorNode<TLazyListWrapper<IsOptional>> {
  10. typedef TMutableCodegeneratorNode<TLazyListWrapper<IsOptional>> TBaseComputation;
  11. public:
  12. TLazyListWrapper(TComputationMutables& mutables, IComputationNode* list)
  13. : TBaseComputation(mutables, EValueRepresentation::Boxed), List(list)
  14. {}
  15. NUdf::TUnboxedValuePod DoCalculate(TComputationContext& ctx) const {
  16. auto list = List->GetValue(ctx);
  17. if (IsOptional && !list) {
  18. return NUdf::TUnboxedValuePod();
  19. }
  20. if (list.GetElements()) {
  21. return ctx.HolderFactory.LazyList(list.Release());
  22. }
  23. return list.Release();
  24. }
  25. #ifndef MKQL_DISABLE_CODEGEN
  26. Value* DoGenerateGetValue(const TCodegenContext& ctx, BasicBlock*& block) const {
  27. auto& context = ctx.Codegen.GetContext();
  28. const auto factory = ctx.GetFactory();
  29. const auto func = ConstantInt::get(Type::getInt64Ty(context), GetMethodPtr(&THolderFactory::LazyList));
  30. const auto list = GetNodeValue(List, ctx, block);
  31. const auto wrap = BasicBlock::Create(context, "wrap", ctx.Func);
  32. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  33. const auto lazy = PHINode::Create(list->getType(), IsOptional ? 3U : 2U, "lazy", done);
  34. lazy->addIncoming(list, block);
  35. if constexpr (IsOptional) {
  36. const auto test = BasicBlock::Create(context, "test", ctx.Func);
  37. BranchInst::Create(done, test, IsEmpty(list, block, context), block);
  38. block = test;
  39. lazy->addIncoming(list, block);
  40. }
  41. const auto ptrType = PointerType::getUnqual(list->getType());
  42. const auto elements = CallBoxedValueVirtualMethod<NUdf::TBoxedValueAccessor::EMethod::GetElements>(ptrType, list, ctx.Codegen, block);
  43. const auto null = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, elements, ConstantPointerNull::get(ptrType), "null", block);
  44. BranchInst::Create(done, wrap, null, block);
  45. block = wrap;
  46. const auto funType = FunctionType::get(list->getType(), {factory->getType(), list->getType()}, false);
  47. const auto funcPtr = CastInst::Create(Instruction::IntToPtr, func, PointerType::getUnqual(funType), "function", block);
  48. const auto res = CallInst::Create(funType, funcPtr, {factory, list}, "res", block);
  49. lazy->addIncoming(res, block);
  50. BranchInst::Create(done, block);
  51. block = done;
  52. return lazy;
  53. }
  54. #endif
  55. private:
  56. void RegisterDependencies() const final {
  57. this->DependsOn(List);
  58. }
  59. IComputationNode* const List;
  60. };
  61. }
  62. IComputationNode* WrapLazyList(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
  63. MKQL_ENSURE(callable.GetInputsCount() == 1U, "Expected single arg, got " << callable.GetInputsCount());
  64. const auto list = LocateNode(ctx.NodeLocator, callable, 0);
  65. if (callable.GetInput(0).GetStaticType()->IsOptional()) {
  66. return new TLazyListWrapper<true>(ctx.Mutables, list);
  67. } else {
  68. return new TLazyListWrapper<false>(ctx.Mutables, list);
  69. }
  70. }
  71. }
  72. }