simd_int_arith.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "simd_int_arith.h"
  6. #include "simd_common.h"
  7. #include "../aot_emit_exception.h"
  8. #include "../../aot/aot_runtime.h"
  9. static bool
  10. simd_integer_arith(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  11. V128Arithmetic arith_op, LLVMTypeRef vector_type)
  12. {
  13. LLVMValueRef lhs, rhs, result = NULL;
  14. if (!(rhs =
  15. simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, "rhs"))
  16. || !(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
  17. "lhs"))) {
  18. return false;
  19. }
  20. switch (arith_op) {
  21. case V128_ADD:
  22. result = LLVMBuildAdd(comp_ctx->builder, lhs, rhs, "sum");
  23. break;
  24. case V128_SUB:
  25. result = LLVMBuildSub(comp_ctx->builder, lhs, rhs, "difference");
  26. break;
  27. case V128_MUL:
  28. result = LLVMBuildMul(comp_ctx->builder, lhs, rhs, "product");
  29. break;
  30. default:
  31. HANDLE_FAILURE("Unsupport arith_op");
  32. break;
  33. }
  34. if (!result) {
  35. HANDLE_FAILURE("LLVMBuildAdd/LLVMBuildSub/LLVMBuildMul");
  36. return false;
  37. }
  38. return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
  39. }
  40. bool
  41. aot_compile_simd_i8x16_arith(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  42. V128Arithmetic arith_op)
  43. {
  44. return simd_integer_arith(comp_ctx, func_ctx, arith_op, V128_i8x16_TYPE);
  45. }
  46. bool
  47. aot_compile_simd_i16x8_arith(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  48. V128Arithmetic arith_op)
  49. {
  50. return simd_integer_arith(comp_ctx, func_ctx, arith_op, V128_i16x8_TYPE);
  51. }
  52. bool
  53. aot_compile_simd_i32x4_arith(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  54. V128Arithmetic arith_op)
  55. {
  56. return simd_integer_arith(comp_ctx, func_ctx, arith_op, V128_i32x4_TYPE);
  57. }
  58. bool
  59. aot_compile_simd_i64x2_arith(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  60. V128Arithmetic arith_op)
  61. {
  62. return simd_integer_arith(comp_ctx, func_ctx, arith_op, V128_i64x2_TYPE);
  63. }
  64. static bool
  65. simd_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMTypeRef type)
  66. {
  67. LLVMValueRef vector, result;
  68. if (!(vector =
  69. simd_pop_v128_and_bitcast(comp_ctx, func_ctx, type, "vector"))) {
  70. return false;
  71. }
  72. if (!(result = LLVMBuildNeg(comp_ctx->builder, vector, "neg"))) {
  73. HANDLE_FAILURE("LLVMBuildNeg");
  74. return false;
  75. }
  76. return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
  77. }
  78. bool
  79. aot_compile_simd_i8x16_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
  80. {
  81. return simd_neg(comp_ctx, func_ctx, V128_i8x16_TYPE);
  82. }
  83. bool
  84. aot_compile_simd_i16x8_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
  85. {
  86. return simd_neg(comp_ctx, func_ctx, V128_i16x8_TYPE);
  87. }
  88. bool
  89. aot_compile_simd_i32x4_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
  90. {
  91. return simd_neg(comp_ctx, func_ctx, V128_i32x4_TYPE);
  92. }
  93. bool
  94. aot_compile_simd_i64x2_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
  95. {
  96. return simd_neg(comp_ctx, func_ctx, V128_i64x2_TYPE);
  97. }
  98. bool
  99. aot_compile_simd_i8x16_popcnt(AOTCompContext *comp_ctx,
  100. AOTFuncContext *func_ctx)
  101. {
  102. LLVMValueRef vector, result;
  103. if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
  104. V128_i8x16_TYPE, "vector"))) {
  105. return false;
  106. }
  107. if (!(result = aot_call_llvm_intrinsic(comp_ctx, func_ctx,
  108. "llvm.ctpop.v16i8", V128_i8x16_TYPE,
  109. &V128_i8x16_TYPE, 1, vector))) {
  110. return false;
  111. }
  112. return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
  113. }
  114. static bool
  115. simd_v128_cmp(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  116. LLVMTypeRef vector_type, V128Arithmetic arith_op, bool is_signed)
  117. {
  118. LLVMValueRef lhs, rhs, result;
  119. LLVMIntPredicate op;
  120. if (!(rhs =
  121. simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, "rhs"))
  122. || !(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
  123. "lhs"))) {
  124. return false;
  125. }
  126. if (V128_MIN == arith_op) {
  127. op = is_signed ? LLVMIntSLT : LLVMIntULT;
  128. }
  129. else {
  130. op = is_signed ? LLVMIntSGT : LLVMIntUGT;
  131. }
  132. if (!(result = LLVMBuildICmp(comp_ctx->builder, op, lhs, rhs, "cmp"))) {
  133. HANDLE_FAILURE("LLVMBuildICmp");
  134. return false;
  135. }
  136. if (!(result =
  137. LLVMBuildSelect(comp_ctx->builder, result, lhs, rhs, "select"))) {
  138. HANDLE_FAILURE("LLVMBuildSelect");
  139. return false;
  140. }
  141. return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
  142. }
  143. bool
  144. aot_compile_simd_i8x16_cmp(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  145. V128Arithmetic arith_op, bool is_signed)
  146. {
  147. return simd_v128_cmp(comp_ctx, func_ctx, V128_i8x16_TYPE, arith_op,
  148. is_signed);
  149. }
  150. bool
  151. aot_compile_simd_i16x8_cmp(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  152. V128Arithmetic arith_op, bool is_signed)
  153. {
  154. return simd_v128_cmp(comp_ctx, func_ctx, V128_i16x8_TYPE, arith_op,
  155. is_signed);
  156. }
  157. bool
  158. aot_compile_simd_i32x4_cmp(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  159. V128Arithmetic arith_op, bool is_signed)
  160. {
  161. return simd_v128_cmp(comp_ctx, func_ctx, V128_i32x4_TYPE, arith_op,
  162. is_signed);
  163. }
  164. /* llvm.abs.* */
  165. static bool
  166. simd_v128_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  167. char *intrinsic, LLVMTypeRef vector_type)
  168. {
  169. LLVMValueRef vector, result;
  170. LLVMTypeRef param_types[] = { vector_type, INT1_TYPE };
  171. if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
  172. "vec"))) {
  173. return false;
  174. }
  175. if (!(result = aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic,
  176. vector_type, param_types, 2, vector,
  177. /* is_int_min_poison */
  178. LLVM_CONST(i1_zero)))) {
  179. return false;
  180. }
  181. return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
  182. }
  183. bool
  184. aot_compile_simd_i8x16_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
  185. {
  186. return simd_v128_abs(comp_ctx, func_ctx, "llvm.abs.v16i8", V128_i8x16_TYPE);
  187. }
  188. bool
  189. aot_compile_simd_i16x8_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
  190. {
  191. return simd_v128_abs(comp_ctx, func_ctx, "llvm.abs.v8i16", V128_i16x8_TYPE);
  192. }
  193. bool
  194. aot_compile_simd_i32x4_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
  195. {
  196. return simd_v128_abs(comp_ctx, func_ctx, "llvm.abs.v4i32", V128_i32x4_TYPE);
  197. }
  198. bool
  199. aot_compile_simd_i64x2_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
  200. {
  201. return simd_v128_abs(comp_ctx, func_ctx, "llvm.abs.v2i64", V128_i64x2_TYPE);
  202. }
  203. enum integer_avgr_u {
  204. e_avgr_u_i8x16,
  205. e_avgr_u_i16x8,
  206. e_avgr_u_i32x4,
  207. };
  208. /* TODO: try int_x86_mmx_pavg_b and int_x86_mmx_pavg_w */
  209. /* (v1 + v2 + 1) / 2 */
  210. static bool
  211. simd_v128_avg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  212. enum integer_avgr_u itype)
  213. {
  214. LLVMValueRef lhs, rhs, ones, result;
  215. LLVMTypeRef vector_ext_type;
  216. LLVMTypeRef vector_type[] = {
  217. V128_i8x16_TYPE,
  218. V128_i16x8_TYPE,
  219. V128_i32x4_TYPE,
  220. };
  221. unsigned lanes[] = { 16, 8, 4 };
  222. if (!(rhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
  223. vector_type[itype], "rhs"))
  224. || !(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
  225. vector_type[itype], "lhs"))) {
  226. return false;
  227. }
  228. if (!(vector_ext_type = LLVMVectorType(I64_TYPE, lanes[itype]))) {
  229. HANDLE_FAILURE("LLVMVectorType");
  230. return false;
  231. }
  232. if (!(lhs = LLVMBuildZExt(comp_ctx->builder, lhs, vector_ext_type,
  233. "zext_to_i64"))
  234. || !(rhs = LLVMBuildZExt(comp_ctx->builder, rhs, vector_ext_type,
  235. "zext_to_i64"))) {
  236. HANDLE_FAILURE("LLVMBuildZExt");
  237. return false;
  238. }
  239. /* by default, add will do signed/unsigned overflow */
  240. if (!(result = LLVMBuildAdd(comp_ctx->builder, lhs, rhs, "l_add_r"))) {
  241. HANDLE_FAILURE("LLVMBuildAdd");
  242. return false;
  243. }
  244. if (!(ones = simd_build_splat_const_integer_vector(comp_ctx, I64_TYPE, 1,
  245. lanes[itype]))) {
  246. return false;
  247. }
  248. if (!(result = LLVMBuildAdd(comp_ctx->builder, result, ones, "plus_1"))) {
  249. HANDLE_FAILURE("LLVMBuildAdd");
  250. return false;
  251. }
  252. if (!(result = LLVMBuildLShr(comp_ctx->builder, result, ones, "avg"))) {
  253. HANDLE_FAILURE("LLVMBuildLShr");
  254. return false;
  255. }
  256. if (!(result = LLVMBuildTrunc(comp_ctx->builder, result, vector_type[itype],
  257. "to_orig_type"))) {
  258. HANDLE_FAILURE("LLVMBuildTrunc");
  259. return false;
  260. }
  261. return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
  262. }
  263. bool
  264. aot_compile_simd_i8x16_avgr_u(AOTCompContext *comp_ctx,
  265. AOTFuncContext *func_ctx)
  266. {
  267. return simd_v128_avg(comp_ctx, func_ctx, e_avgr_u_i8x16);
  268. }
  269. bool
  270. aot_compile_simd_i16x8_avgr_u(AOTCompContext *comp_ctx,
  271. AOTFuncContext *func_ctx)
  272. {
  273. return simd_v128_avg(comp_ctx, func_ctx, e_avgr_u_i16x8);
  274. }
  275. bool
  276. aot_compile_simd_i32x4_avgr_u(AOTCompContext *comp_ctx,
  277. AOTFuncContext *func_ctx)
  278. {
  279. return simd_v128_avg(comp_ctx, func_ctx, e_avgr_u_i32x4);
  280. }
  281. bool
  282. aot_compile_simd_i32x4_dot_i16x8(AOTCompContext *comp_ctx,
  283. AOTFuncContext *func_ctx)
  284. {
  285. LLVMValueRef vec1, vec2, even_mask, odd_mask, zero, result;
  286. LLVMTypeRef vector_ext_type;
  287. LLVMValueRef even_element[] = {
  288. LLVM_CONST(i32_zero),
  289. LLVM_CONST(i32_two),
  290. LLVM_CONST(i32_four),
  291. LLVM_CONST(i32_six),
  292. };
  293. LLVMValueRef odd_element[] = {
  294. LLVM_CONST(i32_one),
  295. LLVM_CONST(i32_three),
  296. LLVM_CONST(i32_five),
  297. LLVM_CONST(i32_seven),
  298. };
  299. if (!(vec1 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i16x8_TYPE,
  300. "vec1"))
  301. || !(vec2 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
  302. V128_i16x8_TYPE, "vec2"))) {
  303. return false;
  304. }
  305. if (!(vector_ext_type = LLVMVectorType(I32_TYPE, 8))) {
  306. HANDLE_FAILURE("LLVMVectorType");
  307. return false;
  308. }
  309. /* sext <v8i16> to <v8i32> */
  310. if (!(vec1 = LLVMBuildSExt(comp_ctx->builder, vec1, vector_ext_type,
  311. "vec1_v8i32"))
  312. || !(vec2 = LLVMBuildSExt(comp_ctx->builder, vec2, vector_ext_type,
  313. "vec2_v8i32"))) {
  314. HANDLE_FAILURE("LLVMBuildSExt");
  315. return false;
  316. }
  317. if (!(result = LLVMBuildMul(comp_ctx->builder, vec1, vec2, "product"))) {
  318. HANDLE_FAILURE("LLVMBuildMul");
  319. return false;
  320. }
  321. /* pick elements with even indexes and odd indexes */
  322. if (!(even_mask = LLVMConstVector(even_element, 4))
  323. || !(odd_mask = LLVMConstVector(odd_element, 4))) {
  324. HANDLE_FAILURE("LLVMConstVector");
  325. return false;
  326. }
  327. if (!(zero = simd_build_splat_const_integer_vector(comp_ctx, I32_TYPE, 0,
  328. 8))) {
  329. return false;
  330. }
  331. if (!(vec1 = LLVMBuildShuffleVector(comp_ctx->builder, result, zero,
  332. even_mask, "even_result"))
  333. || !(vec2 = LLVMBuildShuffleVector(comp_ctx->builder, result, zero,
  334. odd_mask, "odd_result"))) {
  335. HANDLE_FAILURE("LLVMBuildShuffleVector");
  336. return false;
  337. }
  338. if (!(result = LLVMBuildAdd(comp_ctx->builder, vec1, vec2, "new_vec"))) {
  339. HANDLE_FAILURE("LLVMBuildAdd");
  340. return false;
  341. }
  342. return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
  343. }