simd_int_arith.c 13 KB

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