mkql_builtins_min.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. #include "mkql_builtins_decimal.h" // Y_IGNORE
  2. #include "mkql_builtins_compare.h"
  3. #include <cmath>
  4. namespace NKikimr {
  5. namespace NMiniKQL {
  6. namespace {
  7. template <typename T, std::enable_if_t<std::is_integral<T>::value>* = nullptr>
  8. inline T Min(T l, T r) {
  9. return std::min(l, r);
  10. }
  11. template <typename T, std::enable_if_t<std::is_floating_point<T>::value>* = nullptr>
  12. inline T Min(T l, T r) {
  13. return std::fmin(l, r);
  14. }
  15. template<typename TLeft, typename TRight, typename TOutput>
  16. struct TMin : public TSimpleArithmeticBinary<TLeft, TRight, TOutput, TMin<TLeft, TRight, TOutput>> {
  17. static TOutput Do(TLeft left, TRight right)
  18. {
  19. return Min<TOutput>(left, right);
  20. }
  21. #ifndef MKQL_DISABLE_CODEGEN
  22. static Value* Gen(Value* left, Value* right, const TCodegenContext& ctx, BasicBlock*& block)
  23. {
  24. if constexpr (std::is_floating_point<TOutput>()) {
  25. auto& context = ctx.Codegen.GetContext();
  26. auto& module = ctx.Codegen.GetModule();
  27. const auto fnType = FunctionType::get(GetTypeFor<TOutput>(context), {left->getType(), right->getType()}, false);
  28. const auto& name = GetFuncNameForType<TOutput>("llvm.minnum");
  29. const auto func = module.getOrInsertFunction(name, fnType).getCallee();
  30. const auto res = CallInst::Create(fnType, func, {left, right}, "minnum", block);
  31. return res;
  32. } else {
  33. const auto check = CmpInst::Create(Instruction::ICmp, std::is_signed<TOutput>() ? ICmpInst::ICMP_SGT : ICmpInst::ICMP_UGT, left, right, "greater", block);
  34. const auto res = SelectInst::Create(check, right, left, "min", block);
  35. return res;
  36. }
  37. }
  38. #endif
  39. };
  40. template<typename TType>
  41. struct TFloatAggrMin : public TSimpleArithmeticBinary<TType, TType, TType, TFloatAggrMin<TType>> {
  42. static TType Do(TType left, TType right)
  43. {
  44. return left < right || std::isnan(right) ? left : right;
  45. }
  46. #ifndef MKQL_DISABLE_CODEGEN
  47. static Value* Gen(Value* left, Value* right, const TCodegenContext&, BasicBlock*& block)
  48. {
  49. const auto ult = CmpInst::Create(Instruction::FCmp, FCmpInst::FCMP_ULT, left, right, "less", block);
  50. const auto ord = CmpInst::Create(Instruction::FCmp, FCmpInst::FCMP_ORD, ConstantFP::get(left->getType(), 0.0), left, "ordered", block);
  51. const auto both = BinaryOperator::CreateAnd(ult, ord, "and", block);
  52. return SelectInst::Create(both, left, right, "min", block);
  53. }
  54. #endif
  55. };
  56. template<NUdf::EDataSlot Slot>
  57. struct TDecimalMin {
  58. static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& left, const NUdf::TUnboxedValuePod& right) {
  59. const auto lv = left.GetInt128();
  60. if (!NYql::NDecimal::IsComparable(lv))
  61. return right;
  62. const auto rv = right.GetInt128();
  63. if (!NYql::NDecimal::IsComparable(rv))
  64. return left;
  65. return NUdf::TUnboxedValuePod(lv > rv ? rv : lv);
  66. }
  67. #ifndef MKQL_DISABLE_CODEGEN
  68. static Value* Generate(Value* left, Value* right, const TCodegenContext& ctx, BasicBlock*& block)
  69. {
  70. auto& context = ctx.Codegen.GetContext();
  71. const auto next = BasicBlock::Create(context, "next", ctx.Func);
  72. const auto good = BasicBlock::Create(context, "good", ctx.Func);
  73. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  74. const auto result = PHINode::Create(Type::getInt128Ty(context), 3, "result", done);
  75. const auto l = GetterForInt128(left, block);
  76. const auto lok = NDecimal::GenIsComparable(l, context, block);
  77. result->addIncoming(right, block);
  78. BranchInst::Create(next, done, lok, block);
  79. block = next;
  80. const auto r = GetterForInt128(right, block);
  81. const auto rok = NDecimal::GenIsComparable(r, context, block);
  82. result->addIncoming(left, block);
  83. BranchInst::Create(good, done, rok, block);
  84. block = good;
  85. const auto greater = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SGT, l, r, "greater", block);
  86. const auto res = SelectInst::Create(greater, right, left, "min", block);
  87. result->addIncoming(res, block);
  88. BranchInst::Create(done, block);
  89. block = done;
  90. return result;
  91. }
  92. #endif
  93. };
  94. template<NUdf::EDataSlot Slot>
  95. struct TDecimalAggrMin {
  96. static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& left, const NUdf::TUnboxedValuePod& right) {
  97. const auto lv = left.GetInt128();
  98. const auto rv = right.GetInt128();
  99. return lv < rv ? left : right;
  100. }
  101. #ifndef MKQL_DISABLE_CODEGEN
  102. static Value* Generate(Value* left, Value* right, const TCodegenContext&, BasicBlock*& block)
  103. {
  104. const auto l = GetterForInt128(left, block);
  105. const auto r = GetterForInt128(right, block);
  106. const auto less = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SLT, l, r, "less", block);
  107. return SelectInst::Create(less, left, right, "min", block);
  108. }
  109. #endif
  110. };
  111. template<typename TType>
  112. using TAggrMin = std::conditional_t<std::is_floating_point<TType>::value, TFloatAggrMin<TType>, TMin<TType, TType, TType>>;
  113. template<typename TType>
  114. struct TTzMin : public TSelectArithmeticBinaryCopyTimezone<TType, TTzMin<TType>> {
  115. static bool Do(TType left, TType right)
  116. {
  117. return left <= right;
  118. }
  119. #ifndef MKQL_DISABLE_CODEGEN
  120. static Value* Gen(Value* left, Value* right, const TCodegenContext&, BasicBlock*& block)
  121. {
  122. return CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_ULE, left, right, "less_or_equal", block);
  123. }
  124. #endif
  125. };
  126. template<typename TType>
  127. struct TAggrTzMin : public TSelectArithmeticBinaryWithTimezone<TType, TAggrTzMin<TType>> {
  128. static bool Do(TType left, TType right)
  129. {
  130. return left <= right;
  131. }
  132. static bool DoTz(ui16 left, ui16 right)
  133. {
  134. return left <= right;
  135. }
  136. #ifndef MKQL_DISABLE_CODEGEN
  137. static Value* Gen(Value* left, Value* right, const TCodegenContext&, BasicBlock*& block)
  138. {
  139. return CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_ULE, left, right, "less_value", block);
  140. }
  141. static Value* GenTz(Value* left, Value* right, const TCodegenContext&, BasicBlock*& block)
  142. {
  143. return CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_ULE, left, right, "less_timezone", block);
  144. }
  145. #endif
  146. };
  147. template<NUdf::EDataSlot Slot>
  148. struct TCustomMin {
  149. static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& left, const NUdf::TUnboxedValuePod& right) {
  150. const bool r = CompareCustoms<Slot>(left, right) > 0;
  151. (r ? left : right).DeleteUnreferenced();
  152. return r ? right : left;
  153. }
  154. #ifndef MKQL_DISABLE_CODEGEN
  155. static Value* Generate(Value* left, Value* right, const TCodegenContext& ctx, BasicBlock*& block)
  156. {
  157. auto& context = ctx.Codegen.GetContext();
  158. const auto res = CallBinaryUnboxedValueFunction(&CompareCustoms<Slot>, Type::getInt32Ty(context), left, right, ctx.Codegen, block);
  159. const auto comp = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SGT, res, ConstantInt::get(res->getType(), 0), "greater", block);
  160. const auto max = SelectInst::Create(comp, left, right, "max", block);
  161. ValueCleanup(EValueRepresentation::String, max, ctx, block);
  162. const auto min = SelectInst::Create(comp, right, left, "min", block);
  163. return min;
  164. }
  165. #endif
  166. };
  167. }
  168. void RegisterMin(IBuiltinFunctionRegistry& registry) {
  169. RegisterBinaryNumericFunctionOpt<TMin, TBinaryArgsOpt>(registry, "Min");
  170. RegisterBooleanSameTypesFunction<TAggrMin, TBinaryArgsOpt>(registry, "Min");
  171. RegisterDatetimeSameTypesFunction<TAggrMin, TBinaryArgsOpt>(registry, "Min");
  172. RegisterTzDatetimeSameTypesFunction<TTzMin, TBinaryArgsOpt>(registry, "Min");
  173. RegisterCustomSameTypesFunction<NUdf::TDataType<NUdf::TDecimal>, TDecimalMin, TBinaryArgsOpt>(registry, "Min");
  174. RegisterCustomSameTypesFunction<NUdf::TDataType<char*>, TCustomMin, TBinaryArgsOpt>(registry, "Min");
  175. RegisterCustomSameTypesFunction<NUdf::TDataType<NUdf::TUtf8>, TCustomMin, TBinaryArgsOpt>(registry, "Min");
  176. }
  177. void RegisterAggrMin(IBuiltinFunctionRegistry& registry) {
  178. RegisterNumericAggregateFunction<TAggrMin, TBinaryArgsSameOpt>(registry, "AggrMin");
  179. RegisterBooleanAggregateFunction<TAggrMin, TBinaryArgsSameOpt>(registry, "AggrMin");
  180. RegisterDatetimeAggregateFunction<TAggrMin, TBinaryArgsSameOpt>(registry, "AggrMin");
  181. RegisterBigDateAggregateFunction<TAggrMin, TBinaryArgsSameOpt>(registry, "AggrMin");
  182. RegisterTzDatetimeAggregateFunction<TAggrTzMin, TBinaryArgsSameOpt>(registry, "AggrMin");
  183. RegisterCustomAggregateFunction<NUdf::TDataType<NUdf::TDecimal>, TDecimalAggrMin, TBinaryArgsSameOpt>(registry, "AggrMin");
  184. RegisterCustomAggregateFunction<NUdf::TDataType<char*>, TCustomMin, TBinaryArgsSameOpt>(registry, "AggrMin");
  185. RegisterCustomAggregateFunction<NUdf::TDataType<NUdf::TUtf8>, TCustomMin, TBinaryArgsSameOpt>(registry, "AggrMin");
  186. }
  187. } // namespace NMiniKQL
  188. } // namespace NKikimr