simd_conversions.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "simd_conversions.h"
  6. #include "simd_common.h"
  7. #include "../aot_emit_exception.h"
  8. #include "../aot_emit_numberic.h"
  9. #include "../../aot/aot_runtime.h"
  10. static bool
  11. simd_integer_narrow(AOTCompContext *comp_ctx,
  12. AOTFuncContext *func_ctx,
  13. bool is_signed,
  14. LLVMTypeRef in_vector_type,
  15. LLVMTypeRef out_vector_type,
  16. const char *instrinsic)
  17. {
  18. LLVMValueRef vector1, vector2, result;
  19. LLVMTypeRef param_types[2] = { in_vector_type, in_vector_type };
  20. if (!(vector2 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
  21. in_vector_type, "vec2"))) {
  22. goto fail;
  23. }
  24. if (!(vector1 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
  25. in_vector_type, "vec1"))) {
  26. goto fail;
  27. }
  28. if (!(result =
  29. aot_call_llvm_intrinsic(comp_ctx, instrinsic, out_vector_type,
  30. param_types, 2, vector1, vector2))) {
  31. HANDLE_FAILURE("LLVMBuildCall");
  32. goto fail;
  33. }
  34. if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE,
  35. "ret"))) {
  36. HANDLE_FAILURE("LLVMBuildBitCast");
  37. goto fail;
  38. }
  39. PUSH_V128(result);
  40. return true;
  41. fail:
  42. return false;
  43. }
  44. bool
  45. aot_compile_simd_i8x16_narrow_i16x8(AOTCompContext *comp_ctx,
  46. AOTFuncContext *func_ctx,
  47. bool is_signed)
  48. {
  49. return simd_integer_narrow(
  50. comp_ctx, func_ctx, is_signed, V128_i16x8_TYPE, V128_i8x16_TYPE,
  51. is_signed ? "llvm.x86.sse2.packsswb.128" : "llvm.x86.sse2.packuswb.128");
  52. }
  53. bool
  54. aot_compile_simd_i16x8_narrow_i32x4(AOTCompContext *comp_ctx,
  55. AOTFuncContext *func_ctx,
  56. bool is_signed)
  57. {
  58. return simd_integer_narrow(
  59. comp_ctx, func_ctx, is_signed, V128_i32x4_TYPE, V128_i16x8_TYPE,
  60. is_signed ? "llvm.x86.sse2.packssdw.128" : "llvm.x86.sse41.packusdw");
  61. }
  62. bool
  63. aot_compile_simd_i16x8_widen_i8x16(AOTCompContext *comp_ctx,
  64. AOTFuncContext *func_ctx,
  65. bool is_low_half,
  66. bool is_signed)
  67. {
  68. LLVMValueRef vector, undef, mask_high[8], mask_low[8], mask, shuffled,
  69. result;
  70. uint8 mask_high_value[8] = { 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf },
  71. mask_low_value[8] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 }, i;
  72. if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
  73. V128_i8x16_TYPE, "vec"))) {
  74. goto fail;
  75. }
  76. if (!(undef = LLVMGetUndef(V128_i8x16_TYPE))) {
  77. HANDLE_FAILURE("LLVMGetUndef");
  78. goto fail;
  79. }
  80. /* create a mask */
  81. for (i = 0; i < 8; i++) {
  82. mask_high[i] = LLVMConstInt(I32_TYPE, mask_high_value[i], true);
  83. mask_low[i] = LLVMConstInt(I32_TYPE, mask_low_value[i], true);
  84. }
  85. mask = is_low_half ? LLVMConstVector(mask_low, 8)
  86. : LLVMConstVector(mask_high, 8);
  87. if (!mask) {
  88. HANDLE_FAILURE("LLVMConstVector");
  89. goto fail;
  90. }
  91. /* retrive the low or high half */
  92. if (!(shuffled = LLVMBuildShuffleVector(comp_ctx->builder, vector, undef,
  93. mask, "shuffled"))) {
  94. HANDLE_FAILURE("LLVMBuildShuffleVector");
  95. goto fail;
  96. }
  97. if (is_signed) {
  98. if (!(result = LLVMBuildSExt(comp_ctx->builder, shuffled,
  99. V128_i16x8_TYPE, "ext"))) {
  100. HANDLE_FAILURE("LLVMBuildSExt");
  101. goto fail;
  102. }
  103. }
  104. else {
  105. if (!(result = LLVMBuildZExt(comp_ctx->builder, shuffled,
  106. V128_i16x8_TYPE, "ext"))) {
  107. HANDLE_FAILURE("LLVMBuildZExt");
  108. goto fail;
  109. }
  110. }
  111. if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE,
  112. "ret"))) {
  113. HANDLE_FAILURE("LLVMBuildBitCast");
  114. goto fail;
  115. }
  116. PUSH_V128(result);
  117. return true;
  118. fail:
  119. return false;
  120. }
  121. bool
  122. aot_compile_simd_i32x4_widen_i16x8(AOTCompContext *comp_ctx,
  123. AOTFuncContext *func_ctx,
  124. bool is_low_half,
  125. bool is_signed)
  126. {
  127. LLVMValueRef vector, undef, mask_high[4], mask_low[4], mask, shuffled,
  128. result;
  129. uint8 mask_high_value[4] = { 0x4, 0x5, 0x6, 0x7 },
  130. mask_low_value[4] = { 0x0, 0x1, 0x2, 0x3 }, i;
  131. if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
  132. V128_i16x8_TYPE, "vec"))) {
  133. goto fail;
  134. }
  135. if (!(undef = LLVMGetUndef(V128_i16x8_TYPE))) {
  136. HANDLE_FAILURE("LLVMGetUndef");
  137. goto fail;
  138. }
  139. /* create a mask */
  140. for (i = 0; i < 4; i++) {
  141. mask_high[i] = LLVMConstInt(I32_TYPE, mask_high_value[i], true);
  142. mask_low[i] = LLVMConstInt(I32_TYPE, mask_low_value[i], true);
  143. }
  144. mask = is_low_half ? LLVMConstVector(mask_low, 4)
  145. : LLVMConstVector(mask_high, 4);
  146. if (!mask) {
  147. HANDLE_FAILURE("LLVMConstVector");
  148. goto fail;
  149. }
  150. /* retrive the low or high half */
  151. if (!(shuffled = LLVMBuildShuffleVector(comp_ctx->builder, vector, undef,
  152. mask, "shuffled"))) {
  153. HANDLE_FAILURE("LLVMBuildShuffleVector");
  154. goto fail;
  155. }
  156. if (is_signed) {
  157. if (!(result = LLVMBuildSExt(comp_ctx->builder, shuffled,
  158. V128_i32x4_TYPE, "ext"))) {
  159. HANDLE_FAILURE("LLVMBuildSExt");
  160. goto fail;
  161. }
  162. }
  163. else {
  164. if (!(result = LLVMBuildZExt(comp_ctx->builder, shuffled,
  165. V128_i32x4_TYPE, "ext"))) {
  166. HANDLE_FAILURE("LLVMBuildZExt");
  167. goto fail;
  168. }
  169. }
  170. if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE,
  171. "ret"))) {
  172. HANDLE_FAILURE("LLVMBuildBitCast");
  173. goto fail;
  174. }
  175. PUSH_V128(result);
  176. return true;
  177. fail:
  178. return false;
  179. }
  180. static LLVMValueRef
  181. simd_build_const_f32x4(AOTCompContext *comp_ctx,
  182. AOTFuncContext *func_ctx,
  183. float f)
  184. {
  185. LLVMValueRef elements[4], vector;
  186. if (!(elements[0] = LLVMConstReal(F32_TYPE, f))) {
  187. HANDLE_FAILURE("LLVMConstInt");
  188. goto fail;
  189. }
  190. elements[1] = elements[2] = elements[3] = elements[0];
  191. if (!(vector = LLVMConstVector(elements, 4))) {
  192. HANDLE_FAILURE("LLVMConstVector");
  193. goto fail;
  194. }
  195. return vector;
  196. fail:
  197. return NULL;
  198. }
  199. static LLVMValueRef
  200. simd_build_const_i32x4(AOTCompContext *comp_ctx,
  201. AOTFuncContext *func_ctx,
  202. uint64 integer,
  203. bool is_signed)
  204. {
  205. LLVMValueRef elements[4], vector;
  206. if (!(elements[0] = LLVMConstInt(I32_TYPE, integer, is_signed))) {
  207. HANDLE_FAILURE("LLVMConstInt");
  208. goto fail;
  209. }
  210. elements[1] = elements[2] = elements[3] = elements[0];
  211. if (!(vector = LLVMConstVector(elements, 4))) {
  212. HANDLE_FAILURE("LLVMConstVector");
  213. goto fail;
  214. }
  215. return vector;
  216. fail:
  217. return NULL;
  218. }
  219. bool
  220. aot_compile_simd_i32x4_trunc_sat_f32x4(AOTCompContext *comp_ctx,
  221. AOTFuncContext *func_ctx,
  222. bool is_signed)
  223. {
  224. LLVMValueRef vector, zeros, is_nan, max_float_v, min_float_v, is_ge_max,
  225. is_le_min, result, max_int_v, min_int_v;
  226. uint32 max_ui = 0xFFffFFff, min_ui = 0x0;
  227. int32 max_si = 0x7FFFffff, min_si = 0x80000000;
  228. float max_f_ui = 4294967296.0f, min_f_ui = 0.0f, max_f_si = 2147483647.0f,
  229. min_f_si = -2147483648.0f;
  230. if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
  231. V128_f32x4_TYPE, "vec"))) {
  232. goto fail;
  233. }
  234. if (!(zeros = LLVMConstNull(V128_f32x4_TYPE))) {
  235. HANDLE_FAILURE("LLVMConstNull");
  236. goto fail;
  237. }
  238. if (is_signed) {
  239. if (!(max_float_v =
  240. simd_build_const_f32x4(comp_ctx, func_ctx, max_f_si))) {
  241. goto fail;
  242. }
  243. if (!(min_float_v =
  244. simd_build_const_f32x4(comp_ctx, func_ctx, min_f_si))) {
  245. goto fail;
  246. }
  247. if (!(max_int_v =
  248. simd_build_const_i32x4(comp_ctx, func_ctx, max_si, true))) {
  249. goto fail;
  250. }
  251. if (!(min_int_v =
  252. simd_build_const_i32x4(comp_ctx, func_ctx, min_si, true))) {
  253. goto fail;
  254. }
  255. }
  256. else {
  257. if (!(max_float_v =
  258. simd_build_const_f32x4(comp_ctx, func_ctx, max_f_ui))) {
  259. goto fail;
  260. }
  261. if (!(min_float_v =
  262. simd_build_const_f32x4(comp_ctx, func_ctx, min_f_ui))) {
  263. goto fail;
  264. }
  265. if (!(max_int_v =
  266. simd_build_const_i32x4(comp_ctx, func_ctx, max_ui, false))) {
  267. goto fail;
  268. }
  269. if (!(min_int_v =
  270. simd_build_const_i32x4(comp_ctx, func_ctx, min_ui, false))) {
  271. goto fail;
  272. }
  273. }
  274. if (!(is_nan = LLVMBuildFCmp(comp_ctx->builder, LLVMRealORD, vector, zeros,
  275. "is_nan"))) {
  276. HANDLE_FAILURE("LLVMBuildFCmp");
  277. goto fail;
  278. }
  279. if (!(is_le_min = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOLE, vector,
  280. min_float_v, "le_min"))) {
  281. HANDLE_FAILURE("LLVMBuildFCmp");
  282. goto fail;
  283. }
  284. if (!(is_ge_max = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOGE, vector,
  285. max_float_v, "ge_max"))) {
  286. HANDLE_FAILURE("LLVMBuildFCmp");
  287. goto fail;
  288. }
  289. if (is_signed) {
  290. if (!(result = LLVMBuildFPToSI(comp_ctx->builder, vector,
  291. V128_i32x4_TYPE, "truncated"))) {
  292. HANDLE_FAILURE("LLVMBuildSIToFP");
  293. goto fail;
  294. }
  295. }
  296. else {
  297. if (!(result = LLVMBuildFPToUI(comp_ctx->builder, vector,
  298. V128_i32x4_TYPE, "truncated"))) {
  299. HANDLE_FAILURE("LLVMBuildUIToFP");
  300. goto fail;
  301. }
  302. }
  303. if (!(result = LLVMBuildSelect(comp_ctx->builder, is_ge_max, max_int_v,
  304. result, "sat_w_max"))) {
  305. HANDLE_FAILURE("LLVMBuildSelect");
  306. goto fail;
  307. }
  308. if (!(result = LLVMBuildSelect(comp_ctx->builder, is_le_min, min_int_v,
  309. result, "sat_w_min"))) {
  310. HANDLE_FAILURE("LLVMBuildSelect");
  311. goto fail;
  312. }
  313. if (!(result = LLVMBuildSelect(comp_ctx->builder, is_nan, result,
  314. V128_i32x4_ZERO, "sat_w_nan"))) {
  315. HANDLE_FAILURE("LLVMBuildSelect");
  316. goto fail;
  317. }
  318. if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE,
  319. "ret"))) {
  320. HANDLE_FAILURE("LLVMBuildBitCast");
  321. goto fail;
  322. }
  323. PUSH_V128(result);
  324. return true;
  325. fail:
  326. return false;
  327. }
  328. bool
  329. aot_compile_simd_f32x4_convert_i32x4(AOTCompContext *comp_ctx,
  330. AOTFuncContext *func_ctx,
  331. bool is_signed)
  332. {
  333. LLVMValueRef vector, result;
  334. if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
  335. V128_i32x4_TYPE, "vec"))) {
  336. goto fail;
  337. }
  338. if (is_signed) {
  339. if (!(result = LLVMBuildSIToFP(comp_ctx->builder, vector,
  340. V128_f32x4_TYPE, "converted"))) {
  341. HANDLE_FAILURE("LLVMBuildSIToFP");
  342. goto fail;
  343. }
  344. }
  345. else {
  346. if (!(result = LLVMBuildUIToFP(comp_ctx->builder, vector,
  347. V128_f32x4_TYPE, "converted"))) {
  348. HANDLE_FAILURE("LLVMBuildSIToFP");
  349. goto fail;
  350. }
  351. }
  352. if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE,
  353. "ret"))) {
  354. HANDLE_FAILURE("LLVMBuildBitCast");
  355. goto fail;
  356. }
  357. PUSH_V128(result);
  358. return true;
  359. fail:
  360. return false;
  361. }