mkql_size.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. #include "mkql_size.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_node_builder.h>
  7. namespace NKikimr {
  8. namespace NMiniKQL {
  9. namespace {
  10. extern "C" void DeleteString(void* strData);
  11. template<size_t Size>
  12. class TSizePrimitiveTypeWrapper : public TDecoratorCodegeneratorNode<TSizePrimitiveTypeWrapper<Size>> {
  13. typedef TDecoratorCodegeneratorNode<TSizePrimitiveTypeWrapper<Size>> TBaseComputation;
  14. public:
  15. TSizePrimitiveTypeWrapper(IComputationNode* data)
  16. : TBaseComputation(data)
  17. {}
  18. NUdf::TUnboxedValuePod DoCalculate(TComputationContext&, const NUdf::TUnboxedValuePod& value) const {
  19. return value ? NUdf::TUnboxedValuePod(ui32(Size)) : NUdf::TUnboxedValuePod();
  20. }
  21. #ifndef MKQL_DISABLE_CODEGEN
  22. Value* DoGenerateGetValue(const TCodegenContext& ctx, Value* value, BasicBlock*& block) const {
  23. auto& context = ctx.Codegen.GetContext();
  24. const uint64_t init[] = {Size, 0x100000000000000ULL};
  25. const auto size = ConstantInt::get(value->getType(), APInt(128, 2, init));
  26. return SelectInst::Create(IsEmpty(value, block, context), value, size, "size", block);
  27. }
  28. #endif
  29. };
  30. template<bool IsOptional>
  31. class TSizeWrapper : public TMutableCodegeneratorNode<TSizeWrapper<IsOptional>> {
  32. typedef TMutableCodegeneratorNode<TSizeWrapper<IsOptional>> TBaseComputation;
  33. public:
  34. TSizeWrapper(TComputationMutables& mutables, IComputationNode* data)
  35. : TBaseComputation(mutables, EValueRepresentation::Embedded)
  36. , Data(data)
  37. {}
  38. NUdf::TUnboxedValuePod DoCalculate(TComputationContext& ctx) const {
  39. const auto& data = Data->GetValue(ctx);
  40. if (IsOptional && !data) {
  41. return NUdf::TUnboxedValuePod();
  42. }
  43. const ui32 size = data.AsStringRef().Size();
  44. return NUdf::TUnboxedValuePod(size);
  45. }
  46. #ifndef MKQL_DISABLE_CODEGEN
  47. Value* DoGenerateGetValue(const TCodegenContext& ctx, BasicBlock*& block) const {
  48. auto& context = ctx.Codegen.GetContext();
  49. const auto data = GetNodeValue(this->Data, ctx, block);
  50. const auto type = Type::getInt8Ty(context);
  51. const auto embType = FixedVectorType::get(type, 16);
  52. const auto cast = CastInst::Create(Instruction::BitCast, data, embType, "cast", block);
  53. const auto mark = ExtractElementInst::Create(cast, {ConstantInt::get(type, 15)}, "mark", block);
  54. const auto bsize = ExtractElementInst::Create(cast, {ConstantInt::get(type, 14)}, "bsize", block);
  55. const auto emb = BasicBlock::Create(context, "emb", ctx.Func);
  56. const auto str = BasicBlock::Create(context, "str", ctx.Func);
  57. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  58. const auto result = PHINode::Create(data->getType(), 4, "result", done);
  59. result->addIncoming(ConstantInt::get(data->getType(), 0), block);
  60. const auto choise = SwitchInst::Create(mark, done, 2, block);
  61. choise->addCase(ConstantInt::get(type, 1), emb);
  62. choise->addCase(ConstantInt::get(type, 2), str);
  63. {
  64. block = emb;
  65. const auto full = SetterFor<ui32>(bsize, context, block);
  66. result->addIncoming(full, block);
  67. BranchInst::Create(done, block);
  68. }
  69. {
  70. block = str;
  71. const auto type32 = Type::getInt32Ty(context);
  72. const auto strType = FixedVectorType::get(type32, 4);
  73. const auto four = CastInst::Create(Instruction::BitCast, data, strType, "four", block);
  74. const auto ssize = ExtractElementInst::Create(four, {ConstantInt::get(type, 2)}, "ssize", block);
  75. const auto full = SetterFor<ui32>(ssize, context, block);
  76. const auto half = CastInst::Create(Instruction::Trunc, data, Type::getInt64Ty(context), "half", block);
  77. const auto strptr = CastInst::Create(Instruction::IntToPtr, half, PointerType::getUnqual(strType), "str_ptr", block);
  78. const auto refptr = GetElementPtrInst::CreateInBounds(strType, strptr, {ConstantInt::get(type32, 0), ConstantInt::get(type32, 1)}, "refptr", block);
  79. const auto refs = new LoadInst(type32, refptr, "refs", block);
  80. const auto test = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_UGT, refs, ConstantInt::get(refs->getType(), 0), "test", block);
  81. const auto free = BasicBlock::Create(context, "free", ctx.Func);
  82. result->addIncoming(full, block);
  83. BranchInst::Create(done, free, test, block);
  84. block = free;
  85. const auto fnType = FunctionType::get(Type::getVoidTy(context), {strptr->getType()}, false);
  86. const auto name = "DeleteString";
  87. ctx.Codegen.AddGlobalMapping(name, reinterpret_cast<const void*>(&DeleteString));
  88. const auto func = ctx.Codegen.GetModule().getOrInsertFunction(name, fnType);
  89. CallInst::Create(func, {strptr}, "", block);
  90. result->addIncoming(full, block);
  91. BranchInst::Create(done, block);
  92. }
  93. block = done;
  94. return result;
  95. }
  96. #endif
  97. private:
  98. void RegisterDependencies() const final {
  99. this->DependsOn(Data);
  100. }
  101. IComputationNode* const Data;
  102. };
  103. }
  104. IComputationNode* WrapSize(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
  105. MKQL_ENSURE(callable.GetInputsCount() == 1, "Expected 1 arg");
  106. bool isOptional;
  107. const auto dataType = UnpackOptionalData(callable.GetInput(0), isOptional);
  108. const auto data = LocateNode(ctx.NodeLocator, callable, 0);
  109. switch(dataType->GetSchemeType()) {
  110. #define MAKE_PRIMITIVE_TYPE_SIZE(type, layout) \
  111. case NUdf::TDataType<type>::Id: \
  112. if (isOptional) \
  113. return new TSizePrimitiveTypeWrapper<sizeof(layout)>(data); \
  114. else \
  115. return ctx.NodeFactory.CreateImmutableNode(NUdf::TUnboxedValuePod(ui32(sizeof(layout))));
  116. KNOWN_FIXED_VALUE_TYPES(MAKE_PRIMITIVE_TYPE_SIZE)
  117. #undef MAKE_PRIMITIVE_TYPE_SIZE
  118. }
  119. if (isOptional)
  120. return new TSizeWrapper<true>(ctx.Mutables, data);
  121. else
  122. return new TSizeWrapper<false>(ctx.Mutables, data);
  123. }
  124. }
  125. }