mkql_builtins_max.cpp 8.9 KB

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