mkql_fold1.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. #include "mkql_fold1.h"
  2. #include <yql/essentials/minikql/computation/mkql_computation_node_codegen.h> // Y_IGNORE
  3. namespace NKikimr {
  4. namespace NMiniKQL {
  5. namespace {
  6. class TFold1Wrapper : public TMutableCodegeneratorRootNode<TFold1Wrapper> {
  7. typedef TMutableCodegeneratorRootNode<TFold1Wrapper> TBaseComputation;
  8. public:
  9. TFold1Wrapper(TComputationMutables& mutables, EValueRepresentation kind, IComputationNode* list, IComputationExternalNode* item, IComputationExternalNode* state,
  10. IComputationNode* newState, IComputationNode* initialState)
  11. : TBaseComputation(mutables, kind)
  12. , List(list)
  13. , Item(item)
  14. , State(state)
  15. , NewState(newState)
  16. , InitialState(initialState)
  17. {
  18. }
  19. NUdf::TUnboxedValuePod DoCalculate(TComputationContext& compCtx) const {
  20. ui64 length = 0ULL;
  21. TThresher<false>::DoForEachItem(List->GetValue(compCtx),
  22. [this, &length, &compCtx] (NUdf::TUnboxedValue&& item) {
  23. Item->SetValue(compCtx, std::move(item));
  24. State->SetValue(compCtx, (length++ ? NewState : InitialState)->GetValue(compCtx));
  25. }
  26. );
  27. return length ? State->GetValue(compCtx).Release().MakeOptional() : NUdf::TUnboxedValuePod();
  28. }
  29. #ifndef MKQL_DISABLE_CODEGEN
  30. Value* DoGenerateGetValue(const TCodegenContext& ctx, BasicBlock*& block) const {
  31. auto &context = ctx.Codegen.GetContext();
  32. const auto codegenState = dynamic_cast<ICodegeneratorExternalNode*>(State);
  33. const auto codegenItem = dynamic_cast<ICodegeneratorExternalNode*>(Item);
  34. MKQL_ENSURE(codegenState, "State must be codegenerator node.");
  35. MKQL_ENSURE(codegenItem, "Item must be codegenerator node.");
  36. const auto valueType = Type::getInt128Ty(context);
  37. const auto ptrType = PointerType::getUnqual(valueType);
  38. const auto list = GetNodeValue(List, ctx, block);
  39. const auto elements = CallBoxedValueVirtualMethod<NUdf::TBoxedValueAccessor::EMethod::GetElements>(ptrType, list, ctx.Codegen, block);
  40. const auto null = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, elements, ConstantPointerNull::get(ptrType), "null", block);
  41. const auto fast = BasicBlock::Create(context, "fast", ctx.Func);
  42. const auto slow = BasicBlock::Create(context, "slow", ctx.Func);
  43. const auto exit = BasicBlock::Create(context, "exit", ctx.Func);
  44. const auto result = PHINode::Create(valueType, 3, "result", exit);
  45. BranchInst::Create(slow, fast, null, block);
  46. {
  47. block = fast;
  48. const auto sizeType = Type::getInt64Ty(context);
  49. const auto nil = ConstantInt::get(sizeType, 0);
  50. const auto one = ConstantInt::get(sizeType, 1);
  51. const auto size = CallBoxedValueVirtualMethod<NUdf::TBoxedValueAccessor::EMethod::GetListLength>(sizeType, list, ctx.Codegen, block);
  52. const auto next = BasicBlock::Create(context, "next", ctx.Func);
  53. const auto loop = BasicBlock::Create(context, "loop", ctx.Func);
  54. const auto good = BasicBlock::Create(context, "good", ctx.Func);
  55. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  56. const auto index = PHINode::Create(sizeType, 2, "index", loop);
  57. const auto more1 = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_ULT, nil, size, "more1", block);
  58. result->addIncoming(ConstantInt::get(valueType, 0), block);
  59. BranchInst::Create(next, exit, more1, block);
  60. block = next;
  61. const auto item1Ptr = GetElementPtrInst::CreateInBounds(valueType, elements, {nil}, "item1_ptr", block);
  62. const auto item1 = new LoadInst(valueType, item1Ptr, "item1", block);
  63. codegenItem->CreateSetValue(ctx, block, item1);
  64. const auto init = GetNodeValue(InitialState, ctx, block);
  65. codegenState->CreateSetValue(ctx, block, init);
  66. index->addIncoming(one, block);
  67. BranchInst::Create(loop, block);
  68. block = loop;
  69. const auto more = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_ULT, index, size, "more", block);
  70. BranchInst::Create(good, done, more, block);
  71. block = good;
  72. const auto itemPtr = GetElementPtrInst::CreateInBounds(valueType, elements, {index}, "item_ptr", block);
  73. const auto item = new LoadInst(valueType, itemPtr, "item", block);
  74. codegenItem->CreateSetValue(ctx, block, item);
  75. const auto newState = GetNodeValue(NewState, ctx, block);
  76. codegenState->CreateSetValue(ctx, block, newState);
  77. const auto plus = BinaryOperator::CreateAdd(index, one, "plus", block);
  78. index->addIncoming(plus, block);
  79. BranchInst::Create(loop, block);
  80. block = done;
  81. const auto res = codegenState->CreateGetValue(ctx, block);
  82. const auto opt = MakeOptional(context, res, block);
  83. result->addIncoming(opt, block);
  84. BranchInst::Create(exit, block);
  85. }
  86. {
  87. block = slow;
  88. const auto iterPtr = *Stateless || ctx.AlwaysInline ?
  89. new AllocaInst(valueType, 0U, "iter_ptr", &ctx.Func->getEntryBlock().back()):
  90. new AllocaInst(valueType, 0U, "iter_ptr", block);
  91. CallBoxedValueVirtualMethod<NUdf::TBoxedValueAccessor::EMethod::GetListIterator>(iterPtr, list, ctx.Codegen, block);
  92. const auto iter = new LoadInst(valueType, iterPtr, "iter", block);
  93. const auto stop = BasicBlock::Create(context, "stop", ctx.Func);
  94. const auto next = BasicBlock::Create(context, "next", ctx.Func);
  95. const auto loop = BasicBlock::Create(context, "loop", ctx.Func);
  96. const auto good = BasicBlock::Create(context, "good", ctx.Func);
  97. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  98. const auto step = PHINode::Create(valueType, 2, "step", stop);
  99. const auto item1Ptr = codegenItem->CreateRefValue(ctx, block);
  100. const auto status1 = CallBoxedValueVirtualMethod<NUdf::TBoxedValueAccessor::EMethod::Next>(Type::getInt1Ty(context), iter, ctx.Codegen, block, item1Ptr);
  101. step->addIncoming(ConstantInt::get(valueType, 0), block);
  102. BranchInst::Create(next, stop, status1, block);
  103. block = next;
  104. const auto init = GetNodeValue(InitialState, ctx, block);
  105. codegenState->CreateSetValue(ctx, block, init);
  106. BranchInst::Create(loop, block);
  107. block = loop;
  108. const auto itemPtr = codegenItem->CreateRefValue(ctx, block);
  109. const auto status = CallBoxedValueVirtualMethod<NUdf::TBoxedValueAccessor::EMethod::Next>(Type::getInt1Ty(context), iter, ctx.Codegen, block, itemPtr);
  110. BranchInst::Create(good, done, status, block);
  111. block = good;
  112. const auto newState = GetNodeValue(NewState, ctx, block);
  113. codegenState->CreateSetValue(ctx, block, newState);
  114. BranchInst::Create(loop, block);
  115. block = done;
  116. const auto res = codegenState->CreateGetValue(ctx, block);
  117. const auto opt = MakeOptional(context, res, block);
  118. step->addIncoming(opt, block);
  119. BranchInst::Create(stop, block);
  120. block = stop;
  121. UnRefBoxed(iter, ctx, block);
  122. result->addIncoming(step, block);
  123. BranchInst::Create(exit, block);
  124. }
  125. block = exit;
  126. if (List->IsTemporaryValue())
  127. CleanupBoxed(list, ctx, block);
  128. return result;
  129. }
  130. #endif
  131. private:
  132. void RegisterDependencies() const final {
  133. this->DependsOn(List);
  134. this->DependsOn(InitialState);
  135. this->Own(Item);
  136. this->Own(State);
  137. this->DependsOn(NewState);
  138. }
  139. IComputationNode* const List;
  140. IComputationExternalNode* const Item;
  141. IComputationExternalNode* const State;
  142. IComputationNode* const NewState;
  143. IComputationNode* const InitialState;
  144. };
  145. }
  146. IComputationNode* WrapFold1(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
  147. MKQL_ENSURE(callable.GetInputsCount() == 5, "Expected 5 args");
  148. MKQL_ENSURE(callable.GetInput(0).GetStaticType()->IsList(), "Expected List");
  149. const auto list = LocateNode(ctx.NodeLocator, callable, 0);
  150. const auto initialState = LocateNode(ctx.NodeLocator, callable, 2);
  151. const auto newState = LocateNode(ctx.NodeLocator, callable, 4);
  152. const auto item = LocateExternalNode(ctx.NodeLocator, callable, 1);
  153. const auto state = LocateExternalNode(ctx.NodeLocator, callable, 3);
  154. const auto kind = GetValueRepresentation(callable.GetType()->GetReturnType());
  155. return new TFold1Wrapper(ctx.Mutables, kind, list, item, state, newState, initialState);
  156. }
  157. }
  158. }