simd_floating_point.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "simd_floating_point.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_v128_float_arith(AOTCompContext *comp_ctx,
  12. AOTFuncContext *func_ctx,
  13. FloatArithmetic arith_op,
  14. LLVMTypeRef vector_type)
  15. {
  16. LLVMValueRef lhs, rhs, result = NULL;
  17. if (!(rhs =
  18. simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, "rhs"))
  19. || !(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
  20. "lhs"))) {
  21. return false;
  22. }
  23. switch (arith_op) {
  24. case FLOAT_ADD:
  25. result = LLVMBuildFAdd(comp_ctx->builder, lhs, rhs, "sum");
  26. break;
  27. case FLOAT_SUB:
  28. result = LLVMBuildFSub(comp_ctx->builder, lhs, rhs, "difference");
  29. break;
  30. case FLOAT_MUL:
  31. result = LLVMBuildFMul(comp_ctx->builder, lhs, rhs, "product");
  32. break;
  33. case FLOAT_DIV:
  34. result = LLVMBuildFDiv(comp_ctx->builder, lhs, rhs, "quotient");
  35. break;
  36. default:
  37. return false;
  38. }
  39. if (!result) {
  40. HANDLE_FAILURE(
  41. "LLVMBuildFAdd/LLVMBuildFSub/LLVMBuildFMul/LLVMBuildFDiv");
  42. return false;
  43. }
  44. return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
  45. }
  46. bool
  47. aot_compile_simd_f32x4_arith(AOTCompContext *comp_ctx,
  48. AOTFuncContext *func_ctx,
  49. FloatArithmetic arith_op)
  50. {
  51. return simd_v128_float_arith(comp_ctx, func_ctx, arith_op,
  52. V128_f32x4_TYPE);
  53. }
  54. bool
  55. aot_compile_simd_f64x2_arith(AOTCompContext *comp_ctx,
  56. AOTFuncContext *func_ctx,
  57. FloatArithmetic arith_op)
  58. {
  59. return simd_v128_float_arith(comp_ctx, func_ctx, arith_op,
  60. V128_f64x2_TYPE);
  61. }
  62. static bool
  63. simd_v128_float_neg(AOTCompContext *comp_ctx,
  64. AOTFuncContext *func_ctx,
  65. LLVMTypeRef vector_type)
  66. {
  67. LLVMValueRef vector, result;
  68. if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
  69. "vector"))) {
  70. return false;
  71. }
  72. if (!(result = LLVMBuildFNeg(comp_ctx->builder, vector, "neg"))) {
  73. HANDLE_FAILURE("LLVMBuildFNeg");
  74. return false;
  75. }
  76. return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
  77. }
  78. bool
  79. aot_compile_simd_f32x4_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
  80. {
  81. return simd_v128_float_neg(comp_ctx, func_ctx, V128_f32x4_TYPE);
  82. }
  83. bool
  84. aot_compile_simd_f64x2_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
  85. {
  86. return simd_v128_float_neg(comp_ctx, func_ctx, V128_f64x2_TYPE);
  87. }
  88. static bool
  89. simd_float_intrinsic(AOTCompContext *comp_ctx,
  90. AOTFuncContext *func_ctx,
  91. LLVMTypeRef vector_type,
  92. const char *intrinsic)
  93. {
  94. LLVMValueRef vector, result;
  95. LLVMTypeRef param_types[1] = { vector_type };
  96. if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
  97. "vector"))) {
  98. return false;
  99. }
  100. if (!(result =
  101. aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic, vector_type,
  102. param_types, 1, vector))) {
  103. HANDLE_FAILURE("LLVMBuildCall");
  104. return false;
  105. }
  106. return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
  107. }
  108. bool
  109. aot_compile_simd_f32x4_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
  110. {
  111. return simd_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE,
  112. "llvm.fabs.v4f32");
  113. }
  114. bool
  115. aot_compile_simd_f64x2_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
  116. {
  117. return simd_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE,
  118. "llvm.fabs.v2f64");
  119. }
  120. bool
  121. aot_compile_simd_f32x4_round(AOTCompContext *comp_ctx,
  122. AOTFuncContext *func_ctx)
  123. {
  124. return simd_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE,
  125. "llvm.round.v4f32");
  126. }
  127. bool
  128. aot_compile_simd_f64x2_round(AOTCompContext *comp_ctx,
  129. AOTFuncContext *func_ctx)
  130. {
  131. return simd_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE,
  132. "llvm.round.v2f64");
  133. }
  134. bool
  135. aot_compile_simd_f32x4_sqrt(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
  136. {
  137. return simd_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE,
  138. "llvm.sqrt.v4f32");
  139. }
  140. bool
  141. aot_compile_simd_f64x2_sqrt(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
  142. {
  143. return simd_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE,
  144. "llvm.sqrt.v2f64");
  145. }
  146. bool
  147. aot_compile_simd_f32x4_ceil(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
  148. {
  149. return simd_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE,
  150. "llvm.ceil.v4f32");
  151. }
  152. bool
  153. aot_compile_simd_f64x2_ceil(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
  154. {
  155. return simd_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE,
  156. "llvm.ceil.v2f64");
  157. }
  158. bool
  159. aot_compile_simd_f32x4_floor(AOTCompContext *comp_ctx,
  160. AOTFuncContext *func_ctx)
  161. {
  162. return simd_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE,
  163. "llvm.floor.v4f32");
  164. }
  165. bool
  166. aot_compile_simd_f64x2_floor(AOTCompContext *comp_ctx,
  167. AOTFuncContext *func_ctx)
  168. {
  169. return simd_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE,
  170. "llvm.floor.v2f64");
  171. }
  172. bool
  173. aot_compile_simd_f32x4_trunc(AOTCompContext *comp_ctx,
  174. AOTFuncContext *func_ctx)
  175. {
  176. return simd_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE,
  177. "llvm.trunc.v4f32");
  178. }
  179. bool
  180. aot_compile_simd_f64x2_trunc(AOTCompContext *comp_ctx,
  181. AOTFuncContext *func_ctx)
  182. {
  183. return simd_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE,
  184. "llvm.trunc.v2f64");
  185. }
  186. bool
  187. aot_compile_simd_f32x4_nearest(AOTCompContext *comp_ctx,
  188. AOTFuncContext *func_ctx)
  189. {
  190. return simd_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE,
  191. "llvm.rint.v4f32");
  192. }
  193. bool
  194. aot_compile_simd_f64x2_nearest(AOTCompContext *comp_ctx,
  195. AOTFuncContext *func_ctx)
  196. {
  197. return simd_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE,
  198. "llvm.rint.v2f64");
  199. }
  200. static bool
  201. simd_float_cmp(AOTCompContext *comp_ctx,
  202. AOTFuncContext *func_ctx,
  203. FloatArithmetic arith_op,
  204. LLVMTypeRef vector_type)
  205. {
  206. LLVMValueRef lhs, rhs, result;
  207. LLVMRealPredicate op = FLOAT_MIN == arith_op ? LLVMRealULT : LLVMRealUGT;
  208. if (!(rhs =
  209. simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, "rhs"))
  210. || !(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
  211. "lhs"))) {
  212. return false;
  213. }
  214. if (!(result = LLVMBuildFCmp(comp_ctx->builder, op, lhs, rhs, "cmp"))) {
  215. HANDLE_FAILURE("LLVMBuildFCmp");
  216. return false;
  217. }
  218. if (!(result =
  219. LLVMBuildSelect(comp_ctx->builder, result, lhs, rhs, "select"))) {
  220. HANDLE_FAILURE("LLVMBuildSelect");
  221. return false;
  222. }
  223. return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
  224. }
  225. /*TODO: sugggest non-IA platforms check with "llvm.minimum.*" and "llvm.maximum.*" firstly */
  226. bool
  227. aot_compile_simd_f32x4_min_max(AOTCompContext *comp_ctx,
  228. AOTFuncContext *func_ctx,
  229. bool run_min)
  230. {
  231. return simd_float_cmp(comp_ctx, func_ctx, run_min ? FLOAT_MIN : FLOAT_MAX,
  232. V128_f32x4_TYPE);
  233. }
  234. bool
  235. aot_compile_simd_f64x2_min_max(AOTCompContext *comp_ctx,
  236. AOTFuncContext *func_ctx,
  237. bool run_min)
  238. {
  239. return simd_float_cmp(comp_ctx, func_ctx, run_min ? FLOAT_MIN : FLOAT_MAX,
  240. V128_f64x2_TYPE);
  241. }
  242. static bool
  243. simd_float_pmin_max(AOTCompContext *comp_ctx,
  244. AOTFuncContext *func_ctx,
  245. LLVMTypeRef vector_type,
  246. const char *intrinsic)
  247. {
  248. LLVMValueRef lhs, rhs, result;
  249. LLVMTypeRef param_types[2];
  250. param_types[0] = vector_type;
  251. param_types[1] = vector_type;
  252. if (!(rhs =
  253. simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, "rhs"))
  254. || !(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type,
  255. "lhs"))) {
  256. return false;
  257. }
  258. if (!(result =
  259. aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic, vector_type,
  260. param_types, 2, lhs, rhs))) {
  261. return false;
  262. }
  263. return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
  264. }
  265. bool
  266. aot_compile_simd_f32x4_pmin_pmax(AOTCompContext *comp_ctx,
  267. AOTFuncContext *func_ctx,
  268. bool run_min)
  269. {
  270. return simd_float_pmin_max(comp_ctx, func_ctx, V128_f32x4_TYPE,
  271. run_min ? "llvm.minnum.v4f32"
  272. : "llvm.maxnum.v4f32");
  273. }
  274. bool
  275. aot_compile_simd_f64x2_pmin_pmax(AOTCompContext *comp_ctx,
  276. AOTFuncContext *func_ctx,
  277. bool run_min)
  278. {
  279. return simd_float_pmin_max(comp_ctx, func_ctx, V128_f64x2_TYPE,
  280. run_min ? "llvm.minnum.v2f64"
  281. : "llvm.maxnum.v2f64");
  282. }
  283. bool
  284. aot_compile_simd_f64x2_demote(AOTCompContext *comp_ctx,
  285. AOTFuncContext *func_ctx)
  286. {
  287. LLVMValueRef vector, elem_0, elem_1, result;
  288. if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
  289. V128_f64x2_TYPE, "vector"))) {
  290. return false;
  291. }
  292. if (!(elem_0 = LLVMBuildExtractElement(comp_ctx->builder, vector,
  293. LLVM_CONST(i32_zero), "elem_0"))
  294. || !(elem_1 = LLVMBuildExtractElement(
  295. comp_ctx->builder, vector, LLVM_CONST(i32_one), "elem_1"))) {
  296. HANDLE_FAILURE("LLVMBuildExtractElement");
  297. return false;
  298. }
  299. /* fptrunc <f64> elem to <f32> */
  300. if (!(elem_0 = LLVMBuildFPTrunc(comp_ctx->builder, elem_0, F32_TYPE,
  301. "elem_0_trunc"))
  302. || !(elem_1 = LLVMBuildFPTrunc(comp_ctx->builder, elem_1, F32_TYPE,
  303. "elem_1_trunc"))) {
  304. HANDLE_FAILURE("LLVMBuildFPTrunc");
  305. return false;
  306. }
  307. if (!(result = LLVMBuildInsertElement(
  308. comp_ctx->builder, LLVM_CONST(f32x4_vec_zero), elem_0,
  309. LLVM_CONST(i32_zero), "new_vector_0"))
  310. || !(result =
  311. LLVMBuildInsertElement(comp_ctx->builder, result, elem_1,
  312. LLVM_CONST(i32_one), "new_vector_1"))) {
  313. HANDLE_FAILURE("LLVMBuildInsertElement");
  314. return false;
  315. }
  316. return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
  317. }
  318. bool
  319. aot_compile_simd_f32x4_promote(AOTCompContext *comp_ctx,
  320. AOTFuncContext *func_ctx)
  321. {
  322. LLVMValueRef vector, elem_0, elem_1, result;
  323. if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx,
  324. V128_f32x4_TYPE, "vector"))) {
  325. return false;
  326. }
  327. if (!(elem_0 = LLVMBuildExtractElement(comp_ctx->builder, vector,
  328. LLVM_CONST(i32_zero), "elem_0"))
  329. || !(elem_1 = LLVMBuildExtractElement(
  330. comp_ctx->builder, vector, LLVM_CONST(i32_one), "elem_1"))) {
  331. HANDLE_FAILURE("LLVMBuildExtractElement");
  332. return false;
  333. }
  334. /* fpext <f32> elem to <f64> */
  335. if (!(elem_0 =
  336. LLVMBuildFPExt(comp_ctx->builder, elem_0, F64_TYPE, "elem_0_ext"))
  337. || !(elem_1 = LLVMBuildFPExt(comp_ctx->builder, elem_1, F64_TYPE,
  338. "elem_1_ext"))) {
  339. HANDLE_FAILURE("LLVMBuildFPExt");
  340. return false;
  341. }
  342. if (!(result = LLVMBuildInsertElement(
  343. comp_ctx->builder, LLVM_CONST(f64x2_vec_zero), elem_0,
  344. LLVM_CONST(i32_zero), "new_vector_0"))
  345. || !(result =
  346. LLVMBuildInsertElement(comp_ctx->builder, result, elem_1,
  347. LLVM_CONST(i32_one), "new_vector_1"))) {
  348. HANDLE_FAILURE("LLVMBuildInsertElement");
  349. return false;
  350. }
  351. return simd_bitcast_and_push_v128(comp_ctx, func_ctx, result, "result");
  352. }