aot_emit_compare.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "aot_emit_compare.h"
  6. #include "../aot/aot_intrinsic.h"
  7. static bool
  8. int_cond_to_llvm_op(IntCond cond, LLVMIntPredicate *op)
  9. {
  10. if (cond < INT_EQZ || cond > INT_GE_U)
  11. return false;
  12. switch (cond) {
  13. case INT_EQZ:
  14. case INT_EQ:
  15. *op = LLVMIntEQ;
  16. break;
  17. case INT_NE:
  18. *op = LLVMIntNE;
  19. break;
  20. case INT_LT_S:
  21. *op = LLVMIntSLT;
  22. break;
  23. case INT_LT_U:
  24. *op = LLVMIntULT;
  25. break;
  26. case INT_GT_S:
  27. *op = LLVMIntSGT;
  28. break;
  29. case INT_GT_U:
  30. *op = LLVMIntUGT;
  31. break;
  32. case INT_LE_S:
  33. *op = LLVMIntSLE;
  34. break;
  35. case INT_LE_U:
  36. *op = LLVMIntULE;
  37. break;
  38. case INT_GE_S:
  39. *op = LLVMIntSGE;
  40. break;
  41. case INT_GE_U:
  42. *op = LLVMIntUGE;
  43. break;
  44. default:
  45. return false;
  46. }
  47. return true;
  48. }
  49. static bool
  50. float_cond_to_llvm_op(FloatCond cond, LLVMRealPredicate *op)
  51. {
  52. if (cond < FLOAT_EQ || cond > FLOAT_GE)
  53. return false;
  54. switch (cond) {
  55. case FLOAT_EQ:
  56. *op = LLVMRealOEQ;
  57. break;
  58. case FLOAT_NE:
  59. *op = LLVMRealUNE;
  60. break;
  61. case FLOAT_LT:
  62. *op = LLVMRealOLT;
  63. break;
  64. case FLOAT_GT:
  65. *op = LLVMRealOGT;
  66. break;
  67. case FLOAT_LE:
  68. *op = LLVMRealOLE;
  69. break;
  70. case FLOAT_GE:
  71. *op = LLVMRealOGE;
  72. break;
  73. default:
  74. return false;
  75. }
  76. return true;
  77. }
  78. bool
  79. aot_compile_op_i32_compare(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  80. IntCond cond)
  81. {
  82. LLVMIntPredicate op;
  83. LLVMValueRef lhs, rhs, res;
  84. if (!int_cond_to_llvm_op(cond, &op)) {
  85. aot_set_last_error("invalid WASM condition opcode");
  86. return false;
  87. }
  88. if (cond == INT_EQZ)
  89. rhs = I32_ZERO;
  90. else
  91. POP_I32(rhs);
  92. POP_I32(lhs);
  93. if (!(res = LLVMBuildICmp(comp_ctx->builder, op, lhs, rhs, "i32_cmp"))) {
  94. aot_set_last_error("llvm build compare failed.");
  95. return false;
  96. }
  97. PUSH_COND(res);
  98. return true;
  99. fail:
  100. return false;
  101. }
  102. bool
  103. aot_compile_op_i64_compare(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  104. IntCond cond)
  105. {
  106. LLVMIntPredicate op;
  107. LLVMValueRef lhs, rhs, res;
  108. if (!int_cond_to_llvm_op(cond, &op)) {
  109. aot_set_last_error("invalid WASM condition opcode");
  110. return false;
  111. }
  112. if (cond == INT_EQZ)
  113. rhs = I64_CONST(0);
  114. else
  115. POP_I64(rhs);
  116. POP_I64(lhs);
  117. if (!(res = LLVMBuildICmp(comp_ctx->builder, op, lhs, rhs, "i64_cmp"))) {
  118. aot_set_last_error("llvm build compare failed.");
  119. return false;
  120. }
  121. PUSH_COND(res);
  122. return true;
  123. fail:
  124. return false;
  125. }
  126. bool
  127. aot_compile_op_f32_compare(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  128. FloatCond cond)
  129. {
  130. LLVMRealPredicate op;
  131. LLVMValueRef lhs, rhs, res;
  132. if (!float_cond_to_llvm_op(cond, &op)) {
  133. aot_set_last_error("invalid WASM condition opcode");
  134. return false;
  135. }
  136. POP_F32(rhs);
  137. POP_F32(lhs);
  138. if (comp_ctx->disable_llvm_intrinsics
  139. && aot_intrinsic_check_capability(comp_ctx, "f32_cmp")) {
  140. LLVMTypeRef param_types[3];
  141. LLVMValueRef opcond = LLVMConstInt(I32_TYPE, cond, true);
  142. param_types[0] = I32_TYPE;
  143. param_types[1] = F32_TYPE;
  144. param_types[2] = F32_TYPE;
  145. res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, "f32_cmp", I32_TYPE,
  146. param_types, 3, opcond, lhs, rhs);
  147. if (!res) {
  148. goto fail;
  149. }
  150. res = LLVMBuildIntCast(comp_ctx->builder, res, INT1_TYPE, "bit_cast");
  151. }
  152. else {
  153. res = LLVMBuildFCmp(comp_ctx->builder, op, lhs, rhs, "f32_cmp");
  154. }
  155. if (!res) {
  156. aot_set_last_error("llvm build compare failed.");
  157. return false;
  158. }
  159. PUSH_COND(res);
  160. return true;
  161. fail:
  162. return false;
  163. }
  164. bool
  165. aot_compile_op_f64_compare(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  166. FloatCond cond)
  167. {
  168. LLVMRealPredicate op;
  169. LLVMValueRef lhs, rhs, res;
  170. if (!float_cond_to_llvm_op(cond, &op)) {
  171. aot_set_last_error("invalid WASM condition opcode");
  172. return false;
  173. }
  174. POP_F64(rhs);
  175. POP_F64(lhs);
  176. if (comp_ctx->disable_llvm_intrinsics
  177. && aot_intrinsic_check_capability(comp_ctx, "f64_cmp")) {
  178. LLVMTypeRef param_types[3];
  179. LLVMValueRef opcond = LLVMConstInt(I32_TYPE, cond, true);
  180. param_types[0] = I32_TYPE;
  181. param_types[1] = F64_TYPE;
  182. param_types[2] = F64_TYPE;
  183. res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, "f64_cmp", I32_TYPE,
  184. param_types, 3, opcond, lhs, rhs);
  185. if (!res) {
  186. goto fail;
  187. }
  188. res = LLVMBuildIntCast(comp_ctx->builder, res, INT1_TYPE, "bit_cast");
  189. }
  190. else {
  191. res = LLVMBuildFCmp(comp_ctx->builder, op, lhs, rhs, "f64_cmp");
  192. }
  193. if (!res) {
  194. aot_set_last_error("llvm build compare failed.");
  195. return false;
  196. }
  197. PUSH_COND(res);
  198. return true;
  199. fail:
  200. return false;
  201. }
  202. bool
  203. aot_compile_op_ref_eq(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
  204. {
  205. LLVMValueRef gc_obj1 = NULL, gc_obj2 = NULL, res;
  206. POP_GC_REF(gc_obj1);
  207. POP_GC_REF(gc_obj2);
  208. /* LLVM pointer values pointers are compared using LLVMBuildICmp */
  209. res = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ, gc_obj1, gc_obj2,
  210. "cmp_gc_obj_eq");
  211. if (!res) {
  212. aot_set_last_error("llvm build compare failed.");
  213. return false;
  214. }
  215. PUSH_COND(res);
  216. return true;
  217. fail:
  218. return false;
  219. }