mkql_builtins_codegen.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. #include "mkql_builtins_codegen.h" // Y_IGNORE
  2. #ifndef MKQL_DISABLE_CODEGEN
  3. #include "mkql_builtins_codegen_llvm.h" // Y_IGNORE
  4. namespace NKikimr {
  5. namespace NMiniKQL {
  6. using namespace llvm;
  7. Value* GenerateUnaryWithoutCheck(Value* arg, const TCodegenContext& ctx, BasicBlock*& block, TUnaryGenFunc generator) {
  8. return generator(arg, ctx, block);
  9. }
  10. Value* GenerateUnaryWithCheck(Value* arg, const TCodegenContext& ctx, BasicBlock*& block, TUnaryGenFunc generator) {
  11. auto& context = ctx.Codegen.GetContext();
  12. const auto valType = Type::getInt128Ty(context);
  13. const auto zero = ConstantInt::get(valType, 0ULL);
  14. const auto check = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, arg, zero, "check", block);
  15. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  16. const auto good = BasicBlock::Create(context, "good", ctx.Func);
  17. const auto result = PHINode::Create(valType, 2, "result", done);
  18. result->addIncoming(zero, block);
  19. BranchInst::Create(done, good, check, block);
  20. block = good;
  21. const auto data = generator(arg, ctx, block);
  22. result->addIncoming(data, block);
  23. BranchInst::Create(done, block);
  24. block = done;
  25. return result;
  26. }
  27. template<bool CheckLeft, bool CheckRight>
  28. Value* GenerateBinary(Value* left, Value* right, const TCodegenContext& ctx, BasicBlock*& block, TBinaryGenFunc generator) {
  29. auto& context = ctx.Codegen.GetContext();
  30. const auto valType = Type::getInt128Ty(context);
  31. const auto zero = ConstantInt::get(valType, 0ULL);
  32. if (CheckLeft && CheckRight) {
  33. const auto tls = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, left, zero, "tls", block);;
  34. const auto trs = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, right, zero, "trs", block);;
  35. const auto check = BinaryOperator::CreateOr(tls, trs, "or", block);
  36. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  37. const auto good = BasicBlock::Create(context, "good", ctx.Func);
  38. const auto result = PHINode::Create(valType, 2, "result", done);
  39. result->addIncoming(zero, block);
  40. BranchInst::Create(done, good, check, block);
  41. block = good;
  42. const auto data = generator(left, right, ctx, block);
  43. result->addIncoming(data, block);
  44. BranchInst::Create(done, block);
  45. block = done;
  46. return result;
  47. } else if (CheckLeft || CheckRight) {
  48. const auto check = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, CheckLeft ? left : right, zero, "check", block);
  49. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  50. const auto good = BasicBlock::Create(context, "good", ctx.Func);
  51. const auto result = PHINode::Create(valType, 2, "result", done);
  52. result->addIncoming(zero, block);
  53. BranchInst::Create(done, good, check, block);
  54. block = good;
  55. const auto data = generator(left, right, ctx, block);
  56. result->addIncoming(data, block);
  57. BranchInst::Create(done, block);
  58. block = done;
  59. return result;
  60. } else {
  61. return generator(left, right, ctx, block);
  62. }
  63. }
  64. Value* GenerateAggregate(Value* left, Value* right, const TCodegenContext& ctx, BasicBlock*& block, TBinaryGenFunc generator) {
  65. auto& context = ctx.Codegen.GetContext();
  66. const auto valType = Type::getInt128Ty(context);
  67. const auto zero = ConstantInt::get(valType, 0ULL);
  68. const auto tls = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, left, zero, "tls", block);;
  69. const auto trs = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, right, zero, "trs", block);;
  70. const auto check = BinaryOperator::CreateOr(tls, trs, "or", block);
  71. const auto null = BasicBlock::Create(context, "null", 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(valType, 2, "result", done);
  75. BranchInst::Create(null, good, check, block);
  76. block = null;
  77. const auto both = BinaryOperator::CreateOr(left, right, "both", block);
  78. result->addIncoming(both, block);
  79. BranchInst::Create(done, block);
  80. block = good;
  81. const auto data = generator(left, right, ctx, block);
  82. result->addIncoming(data, block);
  83. BranchInst::Create(done, block);
  84. block = done;
  85. return result;
  86. }
  87. Value* GenerateCompareAggregate(Value* left, Value* right, const TCodegenContext& ctx, BasicBlock*& block, TBinaryGenFunc generator, CmpInst::Predicate predicate) {
  88. auto& context = ctx.Codegen.GetContext();
  89. const auto valType = Type::getInt128Ty(context);
  90. const auto zero = ConstantInt::get(valType, 0ULL);
  91. const auto tls = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_NE, left, zero, "tls", block);
  92. const auto trs = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_NE, right, zero, "trs", block);
  93. const auto check = BinaryOperator::CreateAnd(tls, trs, "and", block);
  94. const auto null = BasicBlock::Create(context, "null", ctx.Func);
  95. const auto good = BasicBlock::Create(context, "good", ctx.Func);
  96. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  97. const auto result = PHINode::Create(valType, 2, "result", done);
  98. BranchInst::Create(good, null, check, block);
  99. block = good;
  100. const auto data = generator(left, right, ctx, block);
  101. result->addIncoming(data, block);
  102. BranchInst::Create(done, block);
  103. block = null;
  104. const auto test = CmpInst::Create(Instruction::ICmp, predicate, tls, trs, "test", block);
  105. const auto wide = MakeBoolean(test, context, block);
  106. result->addIncoming(wide, block);
  107. BranchInst::Create(done, block);
  108. block = done;
  109. return result;
  110. }
  111. template<bool CheckFirst>
  112. Value* GenerateTernary(Value* first, Value* second, Value* third, const TCodegenContext& ctx, BasicBlock*& block, TTernaryGenFunc generator) {
  113. auto& context = ctx.Codegen.GetContext();
  114. const auto valType = Type::getInt128Ty(context);
  115. if (CheckFirst) {
  116. const auto zero = ConstantInt::get(valType, 0ULL);
  117. const auto check = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, first, zero, "check", block);
  118. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  119. const auto good = BasicBlock::Create(context, "good", ctx.Func);
  120. const auto result = PHINode::Create(valType, 2, "result", done);
  121. result->addIncoming(zero, block);
  122. BranchInst::Create(done, good, check, block);
  123. block = good;
  124. const auto data = generator(first, second, third, ctx, block);
  125. result->addIncoming(data, block);
  126. BranchInst::Create(done, block);
  127. block = done;
  128. return result;
  129. } else {
  130. return generator(first, second, third, ctx, block);
  131. }
  132. }
  133. template Value* GenerateBinary<false, false>(Value* lhs, Value* rhs, const TCodegenContext& ctx, BasicBlock*& block, TBinaryGenFunc generator);
  134. template Value* GenerateBinary<true, false>(Value* lhs, Value* rhs, const TCodegenContext& ctx, BasicBlock*& block, TBinaryGenFunc generator);
  135. template Value* GenerateBinary<false, true>(Value* lhs, Value* rhs, const TCodegenContext& ctx, BasicBlock*& block, TBinaryGenFunc generator);
  136. template Value* GenerateBinary<true, true>(Value* lhs, Value* rhs, const TCodegenContext& ctx, BasicBlock*& block, TBinaryGenFunc generator);
  137. template Value* GenerateTernary<true>(Value* first, Value* second, Value* third, const TCodegenContext& ctx, BasicBlock*& block, TTernaryGenFunc generator);
  138. template Value* GenerateTernary<false>(Value* first, Value* second, Value* third, const TCodegenContext& ctx, BasicBlock*& block, TTernaryGenFunc generator);
  139. template<>
  140. std::string GetFuncNameForType<bool>(const char*) {
  141. return std::string(); // Stub for MSVC linker
  142. }
  143. template<>
  144. std::string GetFuncNameForType<i8>(const char* name) {
  145. return std::string(name) += ".i8";
  146. }
  147. template<>
  148. std::string GetFuncNameForType<ui8>(const char* name) {
  149. return std::string(name) += ".i8";
  150. }
  151. template<>
  152. std::string GetFuncNameForType<i16>(const char* name) {
  153. return std::string(name) += ".i16";
  154. }
  155. template<>
  156. std::string GetFuncNameForType<ui16>(const char* name) {
  157. return std::string(name) += ".i16";
  158. }
  159. template<>
  160. std::string GetFuncNameForType<i32>(const char* name) {
  161. return std::string(name) += ".i32";
  162. }
  163. template<>
  164. std::string GetFuncNameForType<ui32>(const char* name) {
  165. return std::string(name) += ".i32";
  166. }
  167. template<>
  168. std::string GetFuncNameForType<i64>(const char* name) {
  169. return std::string(name) += ".i64";
  170. }
  171. template<>
  172. std::string GetFuncNameForType<ui64>(const char* name) {
  173. return std::string(name) += ".i64";
  174. }
  175. template<>
  176. std::string GetFuncNameForType<float>(const char* name) {
  177. return std::string(name) += ".f32";
  178. }
  179. template<>
  180. std::string GetFuncNameForType<double>(const char* name) {
  181. return std::string(name) += ".f64";
  182. }
  183. }
  184. }
  185. #endif