simd_int_arith.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  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. };
  207. /* TODO: try int_x86_mmx_pavg_b and int_x86_mmx_pavg_w */
  208. /* (v1 + v2 + 1) / 2 */
  209. static bool
  210. simd_v128_avg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  211. enum integer_avgr_u itype)
  212. {
  213. LLVMValueRef lhs, rhs, ones, result;
  214. LLVMTypeRef vector_ext_type;
  215. LLVMTypeRef vector_type[] = {
  216. V128_i8x16_TYPE,
  217. V128_i16x8_TYPE,
  218. };
  219. unsigned lanes[] = { 16, 8 };
  220. if (!(rhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
  221. vector_type[itype], "rhs"))
  222. || !(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
  223. vector_type[itype], "lhs"))) {
  224. return false;
  225. }
  226. if (!(vector_ext_type = LLVMVectorType(I64_TYPE, lanes[itype]))) {
  227. HANDLE_FAILURE("LLVMVectorType");
  228. return false;
  229. }
  230. if (!(lhs = LLVMBuildZExt(comp_ctx->builder, lhs, vector_ext_type,
  231. "zext_to_i64"))
  232. || !(rhs = LLVMBuildZExt(comp_ctx->builder, rhs, vector_ext_type,
  233. "zext_to_i64"))) {
  234. HANDLE_FAILURE("LLVMBuildZExt");
  235. return false;
  236. }
  237. /* by default, add will do signed/unsigned overflow */
  238. if (!(result = LLVMBuildAdd(comp_ctx->builder, lhs, rhs, "l_add_r"))) {
  239. HANDLE_FAILURE("LLVMBuildAdd");
  240. return false;
  241. }
  242. if (!(ones = simd_build_splat_const_integer_vector(comp_ctx, I64_TYPE, 1,
  243. lanes[itype]))) {
  244. return false;
  245. }
  246. if (!(result = LLVMBuildAdd(comp_ctx->builder, result, ones, "plus_1"))) {
  247. HANDLE_FAILURE("LLVMBuildAdd");
  248. return false;
  249. }
  250. if (!(result = LLVMBuildLShr(comp_ctx->builder, result, ones, "avg"))) {
  251. HANDLE_FAILURE("LLVMBuildLShr");
  252. return false;
  253. }
  254. if (!(result = LLVMBuildTrunc(comp_ctx->builder, result, vector_type[itype],
  255. "to_orig_type"))) {
  256. HANDLE_FAILURE("LLVMBuildTrunc");
  257. return false;
  258. }
  259. return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
  260. }
  261. bool
  262. aot_compile_simd_i8x16_avgr_u(AOTCompContext *comp_ctx,
  263. AOTFuncContext *func_ctx)
  264. {
  265. return simd_v128_avg(comp_ctx, func_ctx, e_avgr_u_i8x16);
  266. }
  267. bool
  268. aot_compile_simd_i16x8_avgr_u(AOTCompContext *comp_ctx,
  269. AOTFuncContext *func_ctx)
  270. {
  271. return simd_v128_avg(comp_ctx, func_ctx, e_avgr_u_i16x8);
  272. }
  273. bool
  274. aot_compile_simd_i32x4_dot_i16x8(AOTCompContext *comp_ctx,
  275. AOTFuncContext *func_ctx)
  276. {
  277. LLVMValueRef vec1, vec2, even_mask, odd_mask, zero, result;
  278. LLVMTypeRef vector_ext_type;
  279. LLVMValueRef even_element[] = {
  280. LLVM_CONST(i32_zero),
  281. LLVM_CONST(i32_two),
  282. LLVM_CONST(i32_four),
  283. LLVM_CONST(i32_six),
  284. };
  285. LLVMValueRef odd_element[] = {
  286. LLVM_CONST(i32_one),
  287. LLVM_CONST(i32_three),
  288. LLVM_CONST(i32_five),
  289. LLVM_CONST(i32_seven),
  290. };
  291. if (!(vec1 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i16x8_TYPE,
  292. "vec1"))
  293. || !(vec2 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
  294. V128_i16x8_TYPE, "vec2"))) {
  295. return false;
  296. }
  297. if (!(vector_ext_type = LLVMVectorType(I32_TYPE, 8))) {
  298. HANDLE_FAILURE("LLVMVectorType");
  299. return false;
  300. }
  301. /* sext <v8i16> to <v8i32> */
  302. if (!(vec1 = LLVMBuildSExt(comp_ctx->builder, vec1, vector_ext_type,
  303. "vec1_v8i32"))
  304. || !(vec2 = LLVMBuildSExt(comp_ctx->builder, vec2, vector_ext_type,
  305. "vec2_v8i32"))) {
  306. HANDLE_FAILURE("LLVMBuildSExt");
  307. return false;
  308. }
  309. if (!(result = LLVMBuildMul(comp_ctx->builder, vec1, vec2, "product"))) {
  310. HANDLE_FAILURE("LLVMBuildMul");
  311. return false;
  312. }
  313. /* pick elements with even indexes and odd indexes */
  314. if (!(even_mask = LLVMConstVector(even_element, 4))
  315. || !(odd_mask = LLVMConstVector(odd_element, 4))) {
  316. HANDLE_FAILURE("LLVMConstVector");
  317. return false;
  318. }
  319. if (!(zero = simd_build_splat_const_integer_vector(comp_ctx, I32_TYPE, 0,
  320. 8))) {
  321. return false;
  322. }
  323. if (!(vec1 = LLVMBuildShuffleVector(comp_ctx->builder, result, zero,
  324. even_mask, "even_result"))
  325. || !(vec2 = LLVMBuildShuffleVector(comp_ctx->builder, result, zero,
  326. odd_mask, "odd_result"))) {
  327. HANDLE_FAILURE("LLVMBuildShuffleVector");
  328. return false;
  329. }
  330. if (!(result = LLVMBuildAdd(comp_ctx->builder, vec1, vec2, "new_vec"))) {
  331. HANDLE_FAILURE("LLVMBuildAdd");
  332. return false;
  333. }
  334. return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
  335. }