mkql_dictitems.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  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 = codegen.GetEffectiveTarget() == NYql::NCodegen::ETarget::Windows ? static_cast<Type*>(PointerType::getUnqual(valueType)) : 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 = codegen.GetEffectiveTarget() == NYql::NCodegen::ETarget::Windows ?
  147. new LoadInst(valueType, containerArg, "load_container", false, block) : static_cast<Value*>(containerArg);
  148. const auto good = BasicBlock::Create(context, "good", ctx.Func);
  149. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  150. const auto pairPtr = new AllocaInst(pairType, 0U, "pair_ptr", block);
  151. new StoreInst(ConstantAggregateZero::get(pairType), pairPtr, block);
  152. const auto keyPtr = GetElementPtrInst::CreateInBounds(pairType, pairPtr, {ConstantInt::get(indexType, 0), ConstantInt::get(indexType, 0)}, "key_ptr", block);
  153. const auto payPtr = GetElementPtrInst::CreateInBounds(pairType, pairPtr, {ConstantInt::get(indexType, 0), ConstantInt::get(indexType, 1)}, "pay_ptr", block);
  154. const auto status = CallBoxedValueVirtualMethod<NUdf::TBoxedValueAccessor::EMethod::NextPair>(statusType, container, codegen, block, keyPtr, payPtr);
  155. BranchInst::Create(good, done, status, block);
  156. block = good;
  157. SafeUnRefUnboxed(valuePtr, ctx, block);
  158. const auto itemsType = PointerType::getUnqual(pairType);
  159. const auto itemsPtr = new AllocaInst(itemsType, 0U, "items_ptr", block);
  160. const auto output = ResPair.GenNewArray(2U, itemsPtr, ctx, block);
  161. AddRefBoxed(output, ctx, block);
  162. const auto items = new LoadInst(itemsType, itemsPtr, "items", block);
  163. const auto pair = new LoadInst(pairType, pairPtr, "pair", block);
  164. new StoreInst(pair, items, block);
  165. new StoreInst(output, valuePtr, block);
  166. BranchInst::Create(done, block);
  167. block = done;
  168. ReturnInst::Create(context, status, block);
  169. return ctx.Func;
  170. }
  171. using TNextPtr = typename TCodegenIterator::TNextPtr;
  172. Function* NextFunc = nullptr;
  173. TNextPtr Next = nullptr;
  174. #endif
  175. IComputationNode* const Dict;
  176. const TContainerCacheOnContext ResPair;
  177. };
  178. template <bool KeysOrPayloads>
  179. class TDictHalfsWrapper : public TMutableComputationNode<TDictHalfsWrapper<KeysOrPayloads>> {
  180. typedef TMutableComputationNode<TDictHalfsWrapper<KeysOrPayloads>> TBaseComputation;
  181. public:
  182. using TSelf = TDictHalfsWrapper<KeysOrPayloads>;
  183. class TValue : public TComputationValue<TValue> {
  184. public:
  185. TValue(
  186. TMemoryUsageInfo* memInfo,
  187. const NUdf::TUnboxedValue&& dict,
  188. TComputationContext&, const TSelf*)
  189. : TComputationValue<TValue>(memInfo)
  190. , Dict(std::move(dict))
  191. {}
  192. private:
  193. ui64 GetListLength() const final {
  194. return Dict.GetDictLength();
  195. }
  196. bool HasListItems() const final {
  197. return Dict.HasDictItems();
  198. }
  199. bool HasFastListLength() const final {
  200. return true;
  201. }
  202. NUdf::TUnboxedValue GetListIterator() const final {
  203. return KeysOrPayloads ? Dict.GetKeysIterator() : Dict.GetPayloadsIterator();
  204. }
  205. const NUdf::TUnboxedValue Dict;
  206. };
  207. TDictHalfsWrapper(TComputationMutables& mutables, IComputationNode* dict)
  208. : TBaseComputation(mutables), Dict(dict)
  209. {}
  210. NUdf::TUnboxedValuePod DoCalculate(TComputationContext& ctx) const {
  211. return ctx.HolderFactory.Create<TValue>(Dict->GetValue(ctx), ctx, this);
  212. }
  213. private:
  214. void RegisterDependencies() const final {
  215. this->DependsOn(Dict);
  216. }
  217. IComputationNode* const Dict;
  218. };
  219. }
  220. IComputationNode* WrapDictItems(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
  221. MKQL_ENSURE(callable.GetInputsCount() == 1 || callable.GetInputsCount() == 2, "Expected one or two args");
  222. const auto node = LocateNode(ctx.NodeLocator, callable, 0);
  223. if (1U == callable.GetInputsCount()) {
  224. return new TDictItemsWrapper(ctx.Mutables, node);
  225. }
  226. const auto mode = AS_VALUE(TDataLiteral, callable.GetInput(1))->AsValue().Get<ui32>();
  227. switch (static_cast<EDictItems>(mode)) {
  228. case EDictItems::Both:
  229. return new TDictItemsWrapper(ctx.Mutables, node);
  230. case EDictItems::Keys:
  231. return new TDictHalfsWrapper<true>(ctx.Mutables, node);
  232. case EDictItems::Payloads:
  233. return new TDictHalfsWrapper<false>(ctx.Mutables, node);
  234. default:
  235. Y_ABORT("Unknown mode: %" PRIu32, mode);
  236. }
  237. }
  238. IComputationNode* WrapDictKeys(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
  239. MKQL_ENSURE(callable.GetInputsCount() == 1, "Expected one arg");
  240. const auto node = LocateNode(ctx.NodeLocator, callable, 0);
  241. return new TDictHalfsWrapper<true>(ctx.Mutables, node);
  242. }
  243. IComputationNode* WrapDictPayloads(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
  244. MKQL_ENSURE(callable.GetInputsCount() == 1, "Expected one arg");
  245. const auto node = LocateNode(ctx.NodeLocator, callable, 0);
  246. return new TDictHalfsWrapper<false>(ctx.Mutables, node);
  247. }
  248. }
  249. }