mkql_prepend.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. #include "mkql_prepend.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 IsVoid>
  9. class TPrependWrapper : public TMutableCodegeneratorNode<TPrependWrapper<IsVoid>> {
  10. typedef TMutableCodegeneratorNode<TPrependWrapper<IsVoid>> TBaseComputation;
  11. public:
  12. TPrependWrapper(TComputationMutables& mutables, IComputationNode* left, IComputationNode* right)
  13. : TBaseComputation(mutables, right->GetRepresentation())
  14. , Left(left)
  15. , Right(right)
  16. {
  17. }
  18. NUdf::TUnboxedValuePod DoCalculate(TComputationContext& ctx) const {
  19. auto left = Left->GetValue(ctx);
  20. auto right = Right->GetValue(ctx);
  21. if (IsVoid && !left.IsBoxed())
  22. return right.Release();
  23. return ctx.HolderFactory.Prepend(left.Release(), right.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::Prepend));
  30. const auto left = GetNodeValue(Left, ctx, block);
  31. const auto right = GetNodeValue(Right, ctx, block);
  32. if constexpr (IsVoid) {
  33. const auto work = BasicBlock::Create(context, "work", ctx.Func);
  34. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  35. const auto result = PHINode::Create(right->getType(), 2, "result", done);
  36. result->addIncoming(right, block);
  37. const uint64_t init[] = {0x0ULL, 0x300000000000000ULL};
  38. const auto mask = ConstantInt::get(left->getType(), APInt(128, 2, init));
  39. const auto boxed = BinaryOperator::CreateAnd(left, mask, "boxed", block);
  40. const auto check = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, boxed, mask, "check", block);
  41. BranchInst::Create(work, done, check, block);
  42. block = work;
  43. if (NYql::NCodegen::ETarget::Windows != ctx.Codegen.GetEffectiveTarget()) {
  44. const auto funType = FunctionType::get(right->getType(), {factory->getType(), left->getType(), right->getType()}, false);
  45. const auto funcPtr = CastInst::Create(Instruction::IntToPtr, func, PointerType::getUnqual(funType), "function", block);
  46. const auto res = CallInst::Create(funType, funcPtr, {factory, left, right}, "res", block);
  47. result->addIncoming(res, block);
  48. } else {
  49. const auto retPtr = new AllocaInst(right->getType(), 0U, "ret_ptr", block);
  50. const auto itemPtr = new AllocaInst(left->getType(), 0U, "item_ptr", block);
  51. new StoreInst(right, retPtr, block);
  52. new StoreInst(left, itemPtr, block);
  53. const auto funType = FunctionType::get(Type::getVoidTy(context), {factory->getType(), retPtr->getType(), itemPtr->getType(), retPtr->getType()}, false);
  54. const auto funcPtr = CastInst::Create(Instruction::IntToPtr, func, PointerType::getUnqual(funType), "function", block);
  55. CallInst::Create(funType, funcPtr, {factory, retPtr, itemPtr, retPtr}, "", block);
  56. const auto res = new LoadInst(right->getType(), retPtr, "res", block);
  57. result->addIncoming(res, block);
  58. }
  59. BranchInst::Create(done, block);
  60. block = done;
  61. return result;
  62. } else {
  63. if (NYql::NCodegen::ETarget::Windows != ctx.Codegen.GetEffectiveTarget()) {
  64. const auto funType = FunctionType::get(right->getType(), {factory->getType(), left->getType(), right->getType()}, false);
  65. const auto funcPtr = CastInst::Create(Instruction::IntToPtr, func, PointerType::getUnqual(funType), "function", block);
  66. const auto res = CallInst::Create(funType, funcPtr, {factory, left, right}, "res", block);
  67. return res;
  68. } else {
  69. const auto retPtr = new AllocaInst(right->getType(), 0U, "ret_ptr", block);
  70. const auto itemPtr = new AllocaInst(left->getType(), 0U, "item_ptr", block);
  71. new StoreInst(right, retPtr, block);
  72. new StoreInst(left, itemPtr, block);
  73. const auto funType = FunctionType::get(Type::getVoidTy(context), {factory->getType(), retPtr->getType(), itemPtr->getType(), retPtr->getType()}, false);
  74. const auto funcPtr = CastInst::Create(Instruction::IntToPtr, func, PointerType::getUnqual(funType), "function", block);
  75. CallInst::Create(funType, funcPtr, {factory, retPtr, itemPtr, retPtr}, "", block);
  76. const auto res = new LoadInst(right->getType(), retPtr, "res", block);
  77. return res;
  78. }
  79. }
  80. }
  81. #endif
  82. private:
  83. void RegisterDependencies() const final {
  84. this->DependsOn(Left);
  85. this->DependsOn(Right);
  86. }
  87. IComputationNode* const Left;
  88. IComputationNode* const Right;
  89. };
  90. }
  91. IComputationNode* WrapPrepend(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
  92. MKQL_ENSURE(callable.GetInputsCount() == 2, "Expected 2 args");
  93. const auto leftType = callable.GetInput(0).GetStaticType();
  94. const auto rightType = AS_TYPE(TListType, callable.GetInput(1));
  95. MKQL_ENSURE(rightType->GetItemType()->IsSameType(*leftType), "Mismatch item type");
  96. const auto left = LocateNode(ctx.NodeLocator, callable, 0);
  97. const auto right = LocateNode(ctx.NodeLocator, callable, 1);
  98. if (leftType->IsVoid())
  99. return new TPrependWrapper<true>(ctx.Mutables, left, right);
  100. else
  101. return new TPrependWrapper<false>(ctx.Mutables, left, right);
  102. }
  103. }
  104. }