mkql_builtins_byteat.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. #include "mkql_builtins_impl.h" // Y_IGNORE
  2. namespace NKikimr {
  3. namespace NMiniKQL {
  4. namespace {
  5. template <typename TInput, typename TOutput, bool IsOptional>
  6. struct TByteAtArgs {
  7. static const TFunctionParamMetadata Value[4];
  8. };
  9. template <typename TInput, typename TOutput, bool IsOptional>
  10. const TFunctionParamMetadata TByteAtArgs<TInput, TOutput, IsOptional>::Value[4] = {
  11. { TOutput::Id, TFunctionParamMetadata::FlagIsNullable },
  12. { TInput::Id, IsOptional ? TFunctionParamMetadata::FlagIsNullable : 0 },
  13. { NUdf::TDataType<ui32>::Id, 0 },
  14. { 0, 0 }
  15. };
  16. template <typename TInput, typename TOutput>
  17. struct TByteAt {
  18. static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& left, const NUdf::TUnboxedValuePod& right)
  19. {
  20. const auto& buffer = left.AsStringRef();
  21. const auto index = right.Get<ui32>();
  22. if (index >= buffer.Size()) {
  23. return NUdf::TUnboxedValuePod();
  24. }
  25. return NUdf::TUnboxedValuePod(ui8(buffer.Data()[index]));
  26. }
  27. #ifndef MKQL_DISABLE_CODEGEN
  28. static Value* Generate(Value* left, Value* right, const TCodegenContext& ctx, BasicBlock*& block)
  29. {
  30. auto& context = ctx.Codegen.GetContext();
  31. const auto type = Type::getInt8Ty(context);
  32. const auto embType = FixedVectorType::get(type, 16);
  33. const auto cast = CastInst::Create(Instruction::BitCast, left, embType, "cast", block);
  34. const auto mark = ExtractElementInst::Create(cast, ConstantInt::get(type, 15), "mark", block);
  35. const auto index = GetterFor<ui32>(right, context, block);
  36. const auto bsize = ExtractElementInst::Create(cast, ConstantInt::get(type, 14), "bsize", block);
  37. const auto esize = CastInst::Create(Instruction::ZExt, bsize, index->getType(), "esize", block);
  38. const auto sizeType = Type::getInt32Ty(context);
  39. const auto strType = FixedVectorType::get(sizeType, 4);
  40. const auto four = CastInst::Create(Instruction::BitCast, left, strType, "four", block);
  41. const auto ssize = ExtractElementInst::Create(four, ConstantInt::get(type, 2), "ssize", block);
  42. const auto cemb = CastInst::Create(Instruction::Trunc, mark, Type::getInt1Ty(context), "cemb", block);
  43. const auto size = SelectInst::Create(cemb, esize, ssize, "size", block);
  44. const auto ok = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_ULT, index, size, "ok", block);
  45. const auto sel = BasicBlock::Create(context, "sel", ctx.Func);
  46. const auto emb = BasicBlock::Create(context, "emb", ctx.Func);
  47. const auto str = BasicBlock::Create(context, "str", ctx.Func);
  48. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  49. const auto zero = ConstantInt::get(left->getType(), 0);
  50. const auto result = PHINode::Create(left->getType(), 4, "result", done);
  51. result->addIncoming(zero, block);
  52. BranchInst::Create(sel, done, ok, block);
  53. block = sel;
  54. result->addIncoming(zero, block);
  55. const auto choise = SwitchInst::Create(mark, done, 2, block);
  56. choise->addCase(ConstantInt::get(type, 1), emb);
  57. choise->addCase(ConstantInt::get(type, 2), str);
  58. {
  59. block = emb;
  60. const auto byte = ExtractElementInst::Create(cast, index, "byte", block);
  61. const auto full = SetterFor<ui8>(byte, context, block);
  62. result->addIncoming(full, block);
  63. BranchInst::Create(done, block);
  64. }
  65. {
  66. block = str;
  67. const auto foffs = ExtractElementInst::Create(four, ConstantInt::get(type, 3), "foffs", block);
  68. const auto offs = BinaryOperator::CreateAnd(foffs, ConstantInt::get(foffs->getType(), 0xFFFFFF), "offs", block);
  69. const auto skip = BinaryOperator::CreateAdd(offs, ConstantInt::get(offs->getType(), 16), "skip", block);
  70. const auto pos = BinaryOperator::CreateAdd(index, skip, "pos", block);
  71. const auto half = CastInst::Create(Instruction::Trunc, left, Type::getInt64Ty(context), "half", block);
  72. const auto ptr = CastInst::Create(Instruction::IntToPtr, half, PointerType::getUnqual(type) , "ptr", block);
  73. const auto bytePtr = GetElementPtrInst::CreateInBounds(type, ptr, {pos}, "bptr", block);
  74. const auto got = new LoadInst(type, bytePtr, "got", block);
  75. const auto make = SetterFor<ui8>(got, context, block);
  76. result->addIncoming(make, block);
  77. BranchInst::Create(done, block);
  78. }
  79. block = done;
  80. return result;
  81. }
  82. #endif
  83. };
  84. }
  85. void RegisterByteAt(IBuiltinFunctionRegistry& registry) {
  86. const auto name = "ByteAt";
  87. RegisterFunctionImpl<TByteAt<NUdf::TDataType<char*>, NUdf::TDataType<ui8>>,
  88. TByteAtArgs<NUdf::TDataType<char*>, NUdf::TDataType<ui8>, false>, TBinaryWrap<false, false>>(registry, name);
  89. RegisterFunctionImpl<TByteAt<NUdf::TDataType<char*>, NUdf::TDataType<ui8>>,
  90. TByteAtArgs<NUdf::TDataType<char*>, NUdf::TDataType<ui8>, true>, TBinaryWrap<true, false>>(registry, name);
  91. RegisterFunctionImpl<TByteAt<NUdf::TDataType<NUdf::TUtf8>, NUdf::TDataType<ui8>>,
  92. TByteAtArgs<NUdf::TDataType<NUdf::TUtf8>, NUdf::TDataType<ui8>, false>, TBinaryWrap<false, false>>(registry, name);
  93. RegisterFunctionImpl<TByteAt<NUdf::TDataType<NUdf::TUtf8>, NUdf::TDataType<ui8>>,
  94. TByteAtArgs<NUdf::TDataType<NUdf::TUtf8>, NUdf::TDataType<ui8>, true>, TBinaryWrap<true, false>>(registry, name);
  95. }
  96. } // namespace NMiniKQL
  97. } // namespace NKikimr