mkql_dictitems.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. #include "mkql_dictitems.h"
  2. #include <yql/essentials/minikql/computation/mkql_computation_node_codegen.h> // Y_IGNORE
  3. #include <yql/essentials/minikql/computation/mkql_computation_node_holders.h>
  4. #include <yql/essentials/minikql/computation/mkql_computation_node_holders_codegen.h>
  5. #include <yql/essentials/minikql/mkql_node_cast.h>
  6. #include <yql/essentials/minikql/mkql_program_builder.h>
  7. namespace NKikimr {
  8. namespace NMiniKQL {
  9. namespace {
  10. class TDictItemsWrapper : public TCustomValueCodegeneratorNode<TDictItemsWrapper> {
  11. typedef TCustomValueCodegeneratorNode<TDictItemsWrapper> TBaseComputation;
  12. public:
  13. using TSelf = TDictItemsWrapper;
  14. #ifndef MKQL_DISABLE_CODEGEN
  15. class TCodegenValue : public TComputationValue<TCodegenValue> {
  16. public:
  17. using TNextPtr = TCodegenIterator::TNextPtr;
  18. TCodegenValue(TMemoryUsageInfo* memInfo, TNextPtr next, TComputationContext* ctx, NUdf::TUnboxedValue&& dict)
  19. : TComputationValue<TCodegenValue>(memInfo)
  20. , NextFunc(next)
  21. , Ctx(ctx)
  22. , Dict(std::move(dict))
  23. {}
  24. private:
  25. NUdf::TUnboxedValue GetListIterator() const final {
  26. return Ctx->HolderFactory.Create<TCodegenIterator>(NextFunc, Ctx, Dict.GetDictIterator());
  27. }
  28. ui64 GetListLength() const final {
  29. return Dict.GetDictLength();
  30. }
  31. bool HasListItems() const final {
  32. return Dict.HasDictItems();
  33. }
  34. bool HasFastListLength() const final {
  35. return true;
  36. }
  37. const TNextPtr NextFunc;
  38. TComputationContext* const Ctx;
  39. const NUdf::TUnboxedValue Dict;
  40. };
  41. #endif
  42. class TValue : public TComputationValue<TValue> {
  43. public:
  44. class TIterator : public TComputationValue<TIterator> {
  45. public:
  46. TIterator(TMemoryUsageInfo* memInfo, NUdf::TUnboxedValue&& inner,
  47. TComputationContext& compCtx, const TSelf* self)
  48. : TComputationValue<TIterator>(memInfo)
  49. , Inner(std::move(inner))
  50. , CompCtx(compCtx)
  51. , Self(self)
  52. {
  53. }
  54. private:
  55. bool Next(NUdf::TUnboxedValue& value) override {
  56. NUdf::TUnboxedValue key, payload;
  57. if (!Inner.NextPair(key, payload))
  58. return false;
  59. NUdf::TUnboxedValue* items = nullptr;
  60. value = Self->ResPair.NewArray(CompCtx, 2, items);
  61. items[0] = std::move(key);
  62. items[1] = std::move(payload);
  63. return true;
  64. }
  65. bool Skip() override {
  66. return Inner.Skip();
  67. }
  68. const NUdf::TUnboxedValue Inner;
  69. TComputationContext& CompCtx;
  70. const TSelf* const Self;
  71. };
  72. TValue(
  73. TMemoryUsageInfo* memInfo,
  74. const NUdf::TUnboxedValue&& dict,
  75. TComputationContext& compCtx, const TSelf* self)
  76. : TComputationValue<TValue>(memInfo)
  77. , Dict(std::move(dict))
  78. , CompCtx(compCtx)
  79. , Self(self)
  80. {
  81. }
  82. private:
  83. ui64 GetListLength() const final {
  84. return Dict.GetDictLength();
  85. }
  86. bool HasListItems() const final {
  87. return Dict.HasDictItems();
  88. }
  89. bool HasFastListLength() const final {
  90. return true;
  91. }
  92. NUdf::TUnboxedValue GetListIterator() const final {
  93. return CompCtx.HolderFactory.Create<TIterator>(Dict.GetDictIterator(), CompCtx, Self);
  94. }
  95. const NUdf::TUnboxedValue Dict;
  96. TComputationContext& CompCtx;
  97. const TSelf* const Self;
  98. };
  99. TDictItemsWrapper(TComputationMutables& mutables, IComputationNode* dict)
  100. : TBaseComputation(mutables)
  101. , Dict(dict)
  102. , ResPair(mutables)
  103. {}
  104. NUdf::TUnboxedValuePod DoCalculate(TComputationContext& ctx) const {
  105. #ifndef MKQL_DISABLE_CODEGEN
  106. if (ctx.ExecuteLLVM && Next)
  107. return ctx.HolderFactory.Create<TCodegenValue>(Next, &ctx, Dict->GetValue(ctx));
  108. #endif
  109. return ctx.HolderFactory.Create<TValue>(Dict->GetValue(ctx), ctx, this);
  110. }
  111. private:
  112. void RegisterDependencies() const final {
  113. DependsOn(Dict);
  114. }
  115. #ifndef MKQL_DISABLE_CODEGEN
  116. void GenerateFunctions(NYql::NCodegen::ICodegen& codegen) final {
  117. NextFunc = GenerateNext(codegen);
  118. codegen.ExportSymbol(NextFunc);
  119. }
  120. void FinalizeFunctions(NYql::NCodegen::ICodegen& codegen) final {
  121. if (NextFunc)
  122. Next = reinterpret_cast<TNextPtr>(codegen.GetPointerToFunction(NextFunc));
  123. }
  124. Function* GenerateNext(NYql::NCodegen::ICodegen& codegen) const {
  125. auto& module = codegen.GetModule();
  126. auto& context = codegen.GetContext();
  127. const auto& name = TBaseComputation::MakeName("Next");
  128. if (const auto f = module.getFunction(name.c_str()))
  129. return f;
  130. const auto valueType = Type::getInt128Ty(context);
  131. const auto indexType = Type::getInt32Ty(context);
  132. const auto pairType = ArrayType::get(valueType, 2U);
  133. const auto containerType = static_cast<Type*>(valueType);
  134. const auto contextType = GetCompContextType(context);
  135. const auto statusType = Type::getInt1Ty(context);
  136. const auto funcType = FunctionType::get(statusType, {PointerType::getUnqual(contextType), containerType, PointerType::getUnqual(valueType)}, false);
  137. TCodegenContext ctx(codegen);
  138. ctx.Func = cast<Function>(module.getOrInsertFunction(name.c_str(), funcType).getCallee());
  139. DISubprogramAnnotator annotator(ctx, ctx.Func);
  140. auto args = ctx.Func->arg_begin();
  141. ctx.Ctx = &*args;
  142. const auto containerArg = &*++args;
  143. const auto valuePtr = &*++args;
  144. const auto main = BasicBlock::Create(context, "main", ctx.Func);
  145. auto block = main;
  146. const auto container = static_cast<Value*>(containerArg);
  147. const auto good = BasicBlock::Create(context, "good", ctx.Func);
  148. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  149. const auto pairPtr = new AllocaInst(pairType, 0U, "pair_ptr", block);
  150. new StoreInst(ConstantAggregateZero::get(pairType), pairPtr, block);
  151. const auto keyPtr = GetElementPtrInst::CreateInBounds(pairType, pairPtr, {ConstantInt::get(indexType, 0), ConstantInt::get(indexType, 0)}, "key_ptr", block);
  152. const auto payPtr = GetElementPtrInst::CreateInBounds(pairType, pairPtr, {ConstantInt::get(indexType, 0), ConstantInt::get(indexType, 1)}, "pay_ptr", block);
  153. const auto status = CallBoxedValueVirtualMethod<NUdf::TBoxedValueAccessor::EMethod::NextPair>(statusType, container, codegen, block, keyPtr, payPtr);
  154. BranchInst::Create(good, done, status, block);
  155. block = good;
  156. SafeUnRefUnboxedOne(valuePtr, ctx, block);
  157. const auto itemsType = PointerType::getUnqual(pairType);
  158. const auto itemsPtr = new AllocaInst(itemsType, 0U, "items_ptr", block);
  159. const auto output = ResPair.GenNewArray(2U, itemsPtr, ctx, block);
  160. AddRefBoxed(output, ctx, block);
  161. const auto items = new LoadInst(itemsType, itemsPtr, "items", block);
  162. const auto pair = new LoadInst(pairType, pairPtr, "pair", block);
  163. new StoreInst(pair, items, block);
  164. new StoreInst(output, valuePtr, block);
  165. BranchInst::Create(done, block);
  166. block = done;
  167. ReturnInst::Create(context, status, block);
  168. return ctx.Func;
  169. }
  170. using TNextPtr = typename TCodegenIterator::TNextPtr;
  171. Function* NextFunc = nullptr;
  172. TNextPtr Next = nullptr;
  173. #endif
  174. IComputationNode* const Dict;
  175. const TContainerCacheOnContext ResPair;
  176. };
  177. template <bool KeysOrPayloads>
  178. class TDictHalfsWrapper : public TMutableComputationNode<TDictHalfsWrapper<KeysOrPayloads>> {
  179. typedef TMutableComputationNode<TDictHalfsWrapper<KeysOrPayloads>> TBaseComputation;
  180. public:
  181. using TSelf = TDictHalfsWrapper<KeysOrPayloads>;
  182. class TValue : public TComputationValue<TValue> {
  183. public:
  184. TValue(
  185. TMemoryUsageInfo* memInfo,
  186. const NUdf::TUnboxedValue&& dict,
  187. TComputationContext&, const TSelf*)
  188. : TComputationValue<TValue>(memInfo)
  189. , Dict(std::move(dict))
  190. {}
  191. private:
  192. ui64 GetListLength() const final {
  193. return Dict.GetDictLength();
  194. }
  195. bool HasListItems() const final {
  196. return Dict.HasDictItems();
  197. }
  198. bool HasFastListLength() const final {
  199. return true;
  200. }
  201. NUdf::TUnboxedValue GetListIterator() const final {
  202. return KeysOrPayloads ? Dict.GetKeysIterator() : Dict.GetPayloadsIterator();
  203. }
  204. const NUdf::TUnboxedValue Dict;
  205. };
  206. TDictHalfsWrapper(TComputationMutables& mutables, IComputationNode* dict)
  207. : TBaseComputation(mutables), Dict(dict)
  208. {}
  209. NUdf::TUnboxedValuePod DoCalculate(TComputationContext& ctx) const {
  210. return ctx.HolderFactory.Create<TValue>(Dict->GetValue(ctx), ctx, this);
  211. }
  212. private:
  213. void RegisterDependencies() const final {
  214. this->DependsOn(Dict);
  215. }
  216. IComputationNode* const Dict;
  217. };
  218. }
  219. IComputationNode* WrapDictItems(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
  220. MKQL_ENSURE(callable.GetInputsCount() == 1 || callable.GetInputsCount() == 2, "Expected one or two args");
  221. const auto node = LocateNode(ctx.NodeLocator, callable, 0);
  222. if (1U == callable.GetInputsCount()) {
  223. return new TDictItemsWrapper(ctx.Mutables, node);
  224. }
  225. const auto mode = AS_VALUE(TDataLiteral, callable.GetInput(1))->AsValue().Get<ui32>();
  226. switch (static_cast<EDictItems>(mode)) {
  227. case EDictItems::Both:
  228. return new TDictItemsWrapper(ctx.Mutables, node);
  229. case EDictItems::Keys:
  230. return new TDictHalfsWrapper<true>(ctx.Mutables, node);
  231. case EDictItems::Payloads:
  232. return new TDictHalfsWrapper<false>(ctx.Mutables, node);
  233. default:
  234. Y_ABORT("Unknown mode: %" PRIu32, mode);
  235. }
  236. }
  237. IComputationNode* WrapDictKeys(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
  238. MKQL_ENSURE(callable.GetInputsCount() == 1, "Expected one arg");
  239. const auto node = LocateNode(ctx.NodeLocator, callable, 0);
  240. return new TDictHalfsWrapper<true>(ctx.Mutables, node);
  241. }
  242. IComputationNode* WrapDictPayloads(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
  243. MKQL_ENSURE(callable.GetInputsCount() == 1, "Expected one arg");
  244. const auto node = LocateNode(ctx.NodeLocator, callable, 0);
  245. return new TDictHalfsWrapper<false>(ctx.Mutables, node);
  246. }
  247. }
  248. }