mkql_visitall.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. #include "mkql_visitall.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 <util/string/cast.h>
  5. namespace NKikimr {
  6. namespace NMiniKQL {
  7. namespace {
  8. class TVisitAllWrapper: public TMutableCodegeneratorNode<TVisitAllWrapper> {
  9. using TBaseComputation = TMutableCodegeneratorNode<TVisitAllWrapper>;
  10. public:
  11. TVisitAllWrapper(TComputationMutables& mutables, EValueRepresentation kind, IComputationNode* varNode, TComputationExternalNodePtrVector&& args, TComputationNodePtrVector&& newNodes)
  12. : TBaseComputation(mutables, kind)
  13. , VarNode(varNode)
  14. , Args(std::move(args))
  15. , NewNodes(std::move(newNodes))
  16. {}
  17. NUdf::TUnboxedValuePod DoCalculate(TComputationContext& ctx) const {
  18. const auto& var = VarNode->GetValue(ctx);
  19. const auto currentIndex = var.GetVariantIndex();
  20. if (currentIndex >= Args.size())
  21. return NUdf::TUnboxedValuePod();
  22. Args[currentIndex]->SetValue(ctx, var.GetVariantItem());
  23. return NewNodes[currentIndex]->GetValue(ctx).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 done = BasicBlock::Create(context, "done", ctx.Func);
  29. const auto variant = GetNodeValue(VarNode, ctx, block);
  30. const auto unpack = GetVariantParts(variant, ctx, block);
  31. const auto result = PHINode::Create(variant->getType(), Args.size() + 1U, "result", done);
  32. result->addIncoming(ConstantInt::get(variant->getType(), 0ULL), block);
  33. const auto choise = SwitchInst::Create(unpack.first, done, Args.size(), block);
  34. for (ui32 i = 0; i < NewNodes.size(); ++i) {
  35. const auto var = BasicBlock::Create(context, (TString("case_") += ToString(i)).c_str(), ctx.Func);
  36. choise->addCase(ConstantInt::get(Type::getInt32Ty(context), i), var);
  37. block = var;
  38. const auto codegenArg = dynamic_cast<ICodegeneratorExternalNode*>(Args[i]);
  39. MKQL_ENSURE(codegenArg, "Arg must be codegenerator node.");
  40. codegenArg->CreateSetValue(ctx, block, unpack.second);
  41. const auto item = GetNodeValue(NewNodes[i], ctx, block);
  42. result->addIncoming(item, block);
  43. BranchInst::Create(done, block);
  44. }
  45. block = done;
  46. return result;
  47. }
  48. #endif
  49. private:
  50. void RegisterDependencies() const final {
  51. DependsOn(VarNode);
  52. std::for_each(Args.cbegin(), Args.cend(), std::bind(&TVisitAllWrapper::Own, this, std::placeholders::_1));
  53. std::for_each(NewNodes.cbegin(), NewNodes.cend(), std::bind(&TVisitAllWrapper::DependsOn, this, std::placeholders::_1));
  54. }
  55. IComputationNode *const VarNode;
  56. const TComputationExternalNodePtrVector Args;
  57. const TComputationNodePtrVector NewNodes;
  58. };
  59. class TFlowVisitAllWrapper: public TStatefulFlowCodegeneratorNode<TFlowVisitAllWrapper> {
  60. using TBaseComputation = TStatefulFlowCodegeneratorNode<TFlowVisitAllWrapper>;
  61. public:
  62. TFlowVisitAllWrapper(TComputationMutables& mutables, EValueRepresentation kind, IComputationNode* varNode, TComputationExternalNodePtrVector&& args, TComputationNodePtrVector&& newNodes)
  63. : TBaseComputation(mutables, nullptr, kind, EValueRepresentation::Embedded)
  64. , VarNode(varNode)
  65. , Args(std::move(args))
  66. , NewNodes(std::move(newNodes))
  67. {}
  68. NUdf::TUnboxedValuePod DoCalculate(NUdf::TUnboxedValue& state, TComputationContext& ctx) const {
  69. if (state.IsInvalid()) {
  70. const auto& var = VarNode->GetValue(ctx);
  71. const auto index = var.GetVariantIndex();
  72. state = NUdf::TUnboxedValuePod(index);
  73. if (index < Args.size()) {
  74. Args[index]->SetValue(ctx, var.GetVariantItem());
  75. }
  76. }
  77. const auto index = state.Get<ui32>();
  78. return index < NewNodes.size() ? NewNodes[index]->GetValue(ctx).Release() : NUdf::TUnboxedValuePod::MakeFinish();
  79. }
  80. #ifndef MKQL_DISABLE_CODEGEN
  81. Value* DoGenerateGetValue(const TCodegenContext& ctx, Value* statePtr, BasicBlock*& block) const {
  82. auto& context = ctx.Codegen.GetContext();
  83. const auto init = BasicBlock::Create(context, "init", ctx.Func);
  84. const auto work = BasicBlock::Create(context, "work", ctx.Func);
  85. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  86. const auto valueType = Type::getInt128Ty(context);
  87. const auto result = PHINode::Create(valueType, NewNodes.size() + 2U, "result", done);
  88. BranchInst::Create(init, work, IsInvalid(statePtr, block, context), block);
  89. {
  90. block = init;
  91. const auto variant = GetNodeValue(VarNode, ctx, block);
  92. const auto unpack = GetVariantParts(variant, ctx, block);
  93. const auto index = SetterFor<ui32>(unpack.first, context, block);
  94. new StoreInst(index, statePtr, block);
  95. result->addIncoming(GetFinish(context), block);
  96. const auto choise = SwitchInst::Create(unpack.first, done, Args.size(), block);
  97. for (ui32 i = 0; i < Args.size(); ++i) {
  98. const auto var = BasicBlock::Create(context, (TString("init_") += ToString(i)).c_str(), ctx.Func);
  99. choise->addCase(ConstantInt::get(Type::getInt32Ty(context), i), var);
  100. block = var;
  101. const auto codegenArg = dynamic_cast<ICodegeneratorExternalNode*>(Args[i]);
  102. MKQL_ENSURE(codegenArg, "Arg must be codegenerator node.");
  103. codegenArg->CreateSetValue(ctx, block, unpack.second);
  104. BranchInst::Create(work, block);
  105. }
  106. }
  107. {
  108. block = work;
  109. const auto state = new LoadInst(valueType, statePtr, "state", block);
  110. const auto index = GetterFor<ui32>(state, context, block);
  111. result->addIncoming(GetFinish(context), block);
  112. const auto choise = SwitchInst::Create(index, done, NewNodes.size(), block);
  113. for (ui32 i = 0; i < NewNodes.size(); ++i) {
  114. const auto var = BasicBlock::Create(context, (TString("case_") += ToString(i)).c_str(), ctx.Func);
  115. choise->addCase(ConstantInt::get(Type::getInt32Ty(context), i), var);
  116. block = var;
  117. const auto item = GetNodeValue(NewNodes[i], ctx, block);
  118. result->addIncoming(item, block);
  119. BranchInst::Create(done, block);
  120. }
  121. }
  122. block = done;
  123. return result;
  124. }
  125. #endif
  126. private:
  127. void RegisterDependencies() const final {
  128. if (const auto flow = FlowDependsOnAll(NewNodes)) {
  129. DependsOn(flow, VarNode);
  130. std::for_each(Args.cbegin(), Args.cend(), std::bind(&TFlowVisitAllWrapper::Own, flow, std::placeholders::_1));
  131. }
  132. std::for_each(Args.cbegin(), Args.cend(), std::bind(&IComputationNode::AddDependence, VarNode, std::placeholders::_1));
  133. }
  134. IComputationNode *const VarNode;
  135. const TComputationExternalNodePtrVector Args;
  136. const TComputationNodePtrVector NewNodes;
  137. };
  138. class TWideVisitAllWrapper: public TStatefulWideFlowCodegeneratorNode<TWideVisitAllWrapper> {
  139. using TBaseComputation = TStatefulWideFlowCodegeneratorNode<TWideVisitAllWrapper>;
  140. public:
  141. TWideVisitAllWrapper(TComputationMutables& mutables, IComputationNode* varNode, TComputationExternalNodePtrVector&& args, TComputationWideFlowNodePtrVector&& newNodes)
  142. : TBaseComputation(mutables, nullptr, EValueRepresentation::Embedded)
  143. , VarNode(varNode)
  144. , Args(std::move(args))
  145. , NewNodes(std::move(newNodes))
  146. {}
  147. EFetchResult DoCalculate(NUdf::TUnboxedValue& state, TComputationContext& ctx, NUdf::TUnboxedValue*const* output) const {
  148. if (state.IsInvalid()) {
  149. const auto& var = VarNode->GetValue(ctx);
  150. const auto index = var.GetVariantIndex();
  151. state = NUdf::TUnboxedValuePod(index);
  152. if (index < Args.size()) {
  153. Args[index]->SetValue(ctx, var.GetVariantItem());
  154. }
  155. }
  156. const auto index = state.Get<ui32>();
  157. return index < NewNodes.size() ? NewNodes[index]->FetchValues(ctx, output) : EFetchResult::Finish;
  158. }
  159. #ifndef MKQL_DISABLE_CODEGEN
  160. TGenerateResult DoGenGetValues(const TCodegenContext& ctx, Value* statePtr, BasicBlock*& block) const {
  161. auto& context = ctx.Codegen.GetContext();
  162. const auto init = BasicBlock::Create(context, "init", ctx.Func);
  163. const auto work = BasicBlock::Create(context, "work", ctx.Func);
  164. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  165. const auto resultType = Type::getInt32Ty(context);
  166. const auto result = PHINode::Create(resultType, NewNodes.size() + 2U, "result", done);
  167. BranchInst::Create(init, work, IsInvalid(statePtr, block, context), block);
  168. {
  169. block = init;
  170. const auto variant = GetNodeValue(VarNode, ctx, block);
  171. const auto unpack = GetVariantParts(variant, ctx, block);
  172. const auto index = SetterFor<ui32>(unpack.first, context, block);
  173. new StoreInst(index, statePtr, block);
  174. result->addIncoming(ConstantInt::get(resultType, static_cast<i32>(EFetchResult::Finish)), block);
  175. const auto choise = SwitchInst::Create(unpack.first, done, Args.size(), block);
  176. for (ui32 i = 0; i < Args.size(); ++i) {
  177. const auto var = BasicBlock::Create(context, (TString("init_") += ToString(i)).c_str(), ctx.Func);
  178. choise->addCase(ConstantInt::get(Type::getInt32Ty(context), i), var);
  179. block = var;
  180. const auto codegenArg = dynamic_cast<ICodegeneratorExternalNode*>(Args[i]);
  181. MKQL_ENSURE(codegenArg, "Arg must be codegenerator node.");
  182. codegenArg->CreateSetValue(ctx, block, unpack.second);
  183. BranchInst::Create(work, block);
  184. }
  185. }
  186. std::vector<TGettersList> allGetters;
  187. allGetters.reserve(NewNodes.size());
  188. {
  189. block = work;
  190. const auto state = new LoadInst(Type::getInt128Ty(context), statePtr, "state", block);
  191. const auto index = GetterFor<ui32>(state, context, block);
  192. result->addIncoming(ConstantInt::get(resultType, static_cast<i32>(EFetchResult::Finish)), block);
  193. const auto choise = SwitchInst::Create(index, done, NewNodes.size(), block);
  194. for (ui32 i = 0; i < NewNodes.size(); ++i) {
  195. const auto var = BasicBlock::Create(context, (TString("case_") += ToString(i)).c_str(), ctx.Func);
  196. choise->addCase(ConstantInt::get(Type::getInt32Ty(context), i), var);
  197. block = var;
  198. auto get = GetNodeValues(NewNodes[i], ctx, block);
  199. allGetters.emplace_back(std::move(get.second));
  200. result->addIncoming(get.first, block);
  201. BranchInst::Create(done, block);
  202. }
  203. }
  204. TGettersList getters;
  205. getters.reserve(allGetters.back().size());
  206. const auto index = static_cast<const IComputationNode*>(this)->GetIndex();
  207. size_t idx = 0U;
  208. std::generate_n(std::back_inserter(getters), allGetters.front().size(), [&]() {
  209. TGettersList slice;
  210. slice.reserve(allGetters.size());
  211. std::transform(allGetters.begin(), allGetters.end(), std::back_inserter(slice), [j = idx++](TGettersList& list) { return std::move(list[j]);});
  212. return [index, slice = std::move(slice)](const TCodegenContext& ctx, BasicBlock*& block) {
  213. auto& context = ctx.Codegen.GetContext();
  214. const auto stub = BasicBlock::Create(context, "stub", ctx.Func);
  215. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  216. new UnreachableInst(context, stub);
  217. const auto valueType = Type::getInt128Ty(context);
  218. const auto res = PHINode::Create(valueType, slice.size(), "res", done);
  219. const auto statePtr = GetElementPtrInst::CreateInBounds(valueType, ctx.GetMutables(), {ConstantInt::get(Type::getInt32Ty(context), index)}, "state_ptr", block);
  220. const auto state = new LoadInst(valueType, statePtr, "state", block);
  221. const auto trunc = GetterFor<ui32>(state, context, block);
  222. const auto choise = SwitchInst::Create(trunc, stub, slice.size(), block);
  223. for (auto i = 0U; i < slice.size(); ++i) {
  224. const auto var = BasicBlock::Create(context, (TString("case_") += ToString(i)).c_str(), ctx.Func);
  225. choise->addCase(ConstantInt::get(Type::getInt32Ty(context), i), var);
  226. block = var;
  227. const auto get = slice[i](ctx, block);
  228. res->addIncoming(get, block);
  229. BranchInst::Create(done, block);
  230. }
  231. block = done;
  232. return res;
  233. };
  234. });
  235. block = done;
  236. return {result, std::move(getters)};
  237. }
  238. #endif
  239. private:
  240. void RegisterDependencies() const final {
  241. if (const auto flow = this->FlowDependsOnAll(NewNodes)) {
  242. DependsOn(flow, VarNode);
  243. std::for_each(Args.cbegin(), Args.cend(), std::bind(&TWideVisitAllWrapper::Own, flow, std::placeholders::_1));
  244. }
  245. std::for_each(Args.cbegin(), Args.cend(), std::bind(&IComputationNode::AddDependence, VarNode, std::placeholders::_1));
  246. }
  247. IComputationNode *const VarNode;
  248. const TComputationExternalNodePtrVector Args;
  249. const TComputationWideFlowNodePtrVector NewNodes;
  250. };
  251. }
  252. IComputationNode* WrapVisitAll(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
  253. MKQL_ENSURE(callable.GetInputsCount() >= 3, "Expected at least 3 arguments");
  254. const auto varType = AS_TYPE(TVariantType, callable.GetInput(0));
  255. MKQL_ENSURE(callable.GetInputsCount() == varType->GetAlternativesCount() * 2 + 1, "Mismatch handlers count");
  256. const auto variant = LocateNode(ctx.NodeLocator, callable, 0U);
  257. TComputationNodePtrVector newNodes;
  258. newNodes.reserve(varType->GetAlternativesCount());
  259. for (auto i = 1U; i <= varType->GetAlternativesCount() << 1U; ++i) {
  260. newNodes.emplace_back(LocateNode(ctx.NodeLocator, callable, ++i));
  261. }
  262. TComputationExternalNodePtrVector args;
  263. args.reserve(varType->GetAlternativesCount());
  264. for (auto i = 0U; i < varType->GetAlternativesCount() << 1U; ++i) {
  265. args.emplace_back(LocateExternalNode(ctx.NodeLocator, callable, ++i));
  266. }
  267. if (const auto type = callable.GetType()->GetReturnType(); type->IsFlow()) {
  268. TComputationWideFlowNodePtrVector wideNodes;
  269. wideNodes.reserve(newNodes.size());
  270. std::transform(newNodes.cbegin(), newNodes.cend(), std::back_inserter(wideNodes), [](IComputationNode* node){ return dynamic_cast<IComputationWideFlowNode*>(node); });
  271. wideNodes.erase(std::remove_if(wideNodes.begin(), wideNodes.end(), std::logical_not<IComputationWideFlowNode*>()), wideNodes.cend());
  272. if (wideNodes.empty())
  273. return new TFlowVisitAllWrapper(ctx.Mutables, GetValueRepresentation(callable.GetType()->GetReturnType()), variant, std::move(args), std::move(newNodes));
  274. else if (wideNodes.size() == newNodes.size())
  275. return new TWideVisitAllWrapper(ctx.Mutables, variant, std::move(args), std::move(wideNodes));
  276. } else
  277. return new TVisitAllWrapper(ctx.Mutables, GetValueRepresentation(callable.GetType()->GetReturnType()), variant, std::move(args), std::move(newNodes));
  278. THROW yexception() << "Wrong signature.";
  279. }
  280. }
  281. }