mkql_varitem.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. #include "mkql_varitem.h"
  2. #include <yql/essentials/minikql/computation/mkql_computation_node_codegen.h> // Y_IGNORE
  3. #include <yql/essentials/minikql/mkql_node_cast.h>
  4. #include <yql/essentials/minikql/mkql_node_builder.h>
  5. namespace NKikimr {
  6. namespace NMiniKQL {
  7. namespace {
  8. template <bool IsOptional>
  9. class TVariantItemWrapper: public TMutableCodegeneratorPtrNode<TVariantItemWrapper<IsOptional>> {
  10. typedef TMutableCodegeneratorPtrNode<TVariantItemWrapper<IsOptional>> TBaseComputation;
  11. public:
  12. TVariantItemWrapper(TComputationMutables& mutables, EValueRepresentation kind, IComputationNode* varNode)
  13. : TBaseComputation(mutables, kind)
  14. , VarNode(varNode)
  15. {
  16. }
  17. NUdf::TUnboxedValuePod DoCalculate(TComputationContext& compCtx) const {
  18. auto var = VarNode->GetValue(compCtx);
  19. if (IsOptional && !var) {
  20. return NUdf::TUnboxedValuePod();
  21. }
  22. return var.Release().GetVariantItem().Release();
  23. }
  24. #ifndef MKQL_DISABLE_CODEGEN
  25. void DoGenerateGetValue(const TCodegenContext& ctx, Value* pointer, BasicBlock*& block) const {
  26. auto& context = ctx.Codegen.GetContext();
  27. const auto valueType = Type::getInt128Ty(context);
  28. const auto indexType = Type::getInt32Ty(context);
  29. const auto var = GetNodeValue(VarNode, ctx, block);
  30. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  31. if (IsOptional) {
  32. const auto good = BasicBlock::Create(context, "good", ctx.Func);
  33. const auto none = BasicBlock::Create(context, "none", ctx.Func);
  34. BranchInst::Create(none, good, IsEmpty(var, block, context), block);
  35. block = none;
  36. new StoreInst(var, pointer, block);
  37. BranchInst::Create(done, block);
  38. block = good;
  39. }
  40. const auto lshr = BinaryOperator::CreateLShr(var, ConstantInt::get(valueType, 122), "lshr", block);
  41. const auto trunc = CastInst::Create(Instruction::Trunc, lshr, indexType, "trunc", block);
  42. const auto check = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_NE, trunc, ConstantInt::get(indexType , 0), "check", block);
  43. const auto box = BasicBlock::Create(context, "box", ctx.Func);
  44. const auto emb = BasicBlock::Create(context, "emb", ctx.Func);
  45. BranchInst::Create(emb, box, check, block);
  46. block = emb;
  47. const uint64_t init[] = {0xFFFFFFFFFFFFFFFFULL, 0x3FFFFFFFFFFFFFFULL};
  48. const auto mask = ConstantInt::get(valueType, APInt(128, 2, init));
  49. const auto clean = BinaryOperator::CreateAnd(var, mask, "clean", block);
  50. new StoreInst(clean, pointer, block);
  51. ValueAddRef(this->RepresentationKind, pointer, ctx, block);
  52. BranchInst::Create(done, block);
  53. block = box;
  54. CallBoxedValueVirtualMethod<NUdf::TBoxedValueAccessor::EMethod::GetVariantItem>(pointer, var, ctx.Codegen, block);
  55. BranchInst::Create(done, block);
  56. block = done;
  57. }
  58. #endif
  59. private:
  60. void RegisterDependencies() const final {
  61. this->DependsOn(VarNode);
  62. }
  63. IComputationNode *const VarNode;
  64. };
  65. }
  66. IComputationNode* WrapVariantItem(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
  67. MKQL_ENSURE(callable.GetInputsCount() == 1, "Expected 1 argument");
  68. bool isOptional;
  69. const auto unpacked = UnpackOptional(callable.GetInput(0), isOptional);
  70. const auto varType = AS_TYPE(TVariantType, unpacked);
  71. const auto variant = LocateNode(ctx.NodeLocator, callable, 0);
  72. if (isOptional) {
  73. return new TVariantItemWrapper<true>(ctx.Mutables, GetValueRepresentation(varType->GetAlternativeType(0)), variant);
  74. } else {
  75. return new TVariantItemWrapper<false>(ctx.Mutables, GetValueRepresentation(varType->GetAlternativeType(0)), variant);
  76. }
  77. }
  78. }
  79. }