aot_emit_conversion.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "aot_emit_conversion.h"
  6. #include "aot_emit_exception.h"
  7. #include "aot_emit_numberic.h"
  8. #include "../aot/aot_intrinsic.h"
  9. #include "../aot/aot_runtime.h"
  10. static LLVMValueRef
  11. call_fcmp_intrinsic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  12. enum AOTFloatCond cond, LLVMRealPredicate op,
  13. LLVMValueRef lhs, LLVMValueRef rhs, LLVMTypeRef src_type,
  14. const char *name)
  15. {
  16. LLVMValueRef res = NULL;
  17. if (comp_ctx->disable_llvm_intrinsics
  18. && aot_intrinsic_check_capability(
  19. comp_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp")) {
  20. LLVMTypeRef param_types[3];
  21. LLVMValueRef opcond = LLVMConstInt(I32_TYPE, cond, true);
  22. param_types[0] = I32_TYPE;
  23. param_types[1] = src_type;
  24. param_types[2] = src_type;
  25. res = aot_call_llvm_intrinsic(
  26. comp_ctx, func_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp",
  27. I32_TYPE, param_types, 3, opcond, lhs, rhs);
  28. if (!res) {
  29. goto fail;
  30. }
  31. res = LLVMBuildIntCast(comp_ctx->builder, res, INT1_TYPE, "bit_cast");
  32. }
  33. else {
  34. res = LLVMBuildFCmp(comp_ctx->builder, op, lhs, rhs, name);
  35. }
  36. fail:
  37. return res;
  38. }
  39. static bool
  40. trunc_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  41. LLVMValueRef operand, LLVMTypeRef src_type,
  42. LLVMTypeRef dest_type, LLVMValueRef min_value,
  43. LLVMValueRef max_value, char *name, bool sign)
  44. {
  45. LLVMBasicBlockRef check_nan_succ, check_overflow_succ;
  46. LLVMValueRef is_less, is_greater, res;
  47. res = call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_UNO, LLVMRealUNO,
  48. operand, operand, src_type, "fcmp_is_nan");
  49. if (!res) {
  50. aot_set_last_error("llvm build fcmp failed.");
  51. goto fail;
  52. }
  53. if (!(check_nan_succ = LLVMAppendBasicBlockInContext(
  54. comp_ctx->context, func_ctx->func, "check_nan_succ"))) {
  55. aot_set_last_error("llvm add basic block failed.");
  56. goto fail;
  57. }
  58. LLVMMoveBasicBlockAfter(check_nan_succ,
  59. LLVMGetInsertBlock(comp_ctx->builder));
  60. if (!(aot_emit_exception(comp_ctx, func_ctx,
  61. EXCE_INVALID_CONVERSION_TO_INTEGER, true, res,
  62. check_nan_succ)))
  63. goto fail;
  64. is_less =
  65. call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_LE, LLVMRealOLE, operand,
  66. min_value, src_type, "fcmp_min_value");
  67. if (!is_less) {
  68. aot_set_last_error("llvm build fcmp failed.");
  69. goto fail;
  70. }
  71. is_greater =
  72. call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_GE, LLVMRealOGE, operand,
  73. max_value, src_type, "fcmp_min_value");
  74. if (!is_greater) {
  75. aot_set_last_error("llvm build fcmp failed.");
  76. goto fail;
  77. }
  78. if (!(res = LLVMBuildOr(comp_ctx->builder, is_less, is_greater,
  79. "is_overflow"))) {
  80. aot_set_last_error("llvm build logic and failed.");
  81. goto fail;
  82. }
  83. /* Check if float value out of range */
  84. if (!(check_overflow_succ = LLVMAppendBasicBlockInContext(
  85. comp_ctx->context, func_ctx->func, "check_overflow_succ"))) {
  86. aot_set_last_error("llvm add basic block failed.");
  87. goto fail;
  88. }
  89. LLVMMoveBasicBlockAfter(check_overflow_succ,
  90. LLVMGetInsertBlock(comp_ctx->builder));
  91. if (!(aot_emit_exception(comp_ctx, func_ctx, EXCE_INTEGER_OVERFLOW, true,
  92. res, check_overflow_succ)))
  93. goto fail;
  94. if (comp_ctx->disable_llvm_intrinsics
  95. && aot_intrinsic_check_capability(comp_ctx, name)) {
  96. LLVMTypeRef param_types[1];
  97. param_types[0] = src_type;
  98. res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, name, dest_type,
  99. param_types, 1, operand);
  100. }
  101. else {
  102. if (sign)
  103. res = LLVMBuildFPToSI(comp_ctx->builder, operand, dest_type, name);
  104. else
  105. res = LLVMBuildFPToUI(comp_ctx->builder, operand, dest_type, name);
  106. }
  107. if (!res) {
  108. aot_set_last_error("llvm build conversion failed.");
  109. return false;
  110. }
  111. if (dest_type == I32_TYPE)
  112. PUSH_I32(res);
  113. else if (dest_type == I64_TYPE)
  114. PUSH_I64(res);
  115. return true;
  116. fail:
  117. return false;
  118. }
  119. #define ADD_BASIC_BLOCK(block, name) \
  120. do { \
  121. if (!(block = LLVMAppendBasicBlockInContext(comp_ctx->context, \
  122. func_ctx->func, name))) { \
  123. aot_set_last_error("llvm add basic block failed."); \
  124. goto fail; \
  125. } \
  126. \
  127. LLVMMoveBasicBlockAfter(block, LLVMGetInsertBlock(comp_ctx->builder)); \
  128. } while (0)
  129. static bool
  130. trunc_sat_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  131. LLVMValueRef operand, LLVMTypeRef src_type,
  132. LLVMTypeRef dest_type, LLVMValueRef min_value,
  133. LLVMValueRef max_value, char *name, bool sign)
  134. {
  135. LLVMBasicBlockRef check_nan_succ, check_less_succ, check_greater_succ;
  136. LLVMBasicBlockRef is_nan_block, is_less_block, is_greater_block, res_block;
  137. LLVMValueRef is_less, is_greater, res, phi;
  138. LLVMValueRef zero = (dest_type == I32_TYPE) ? I32_ZERO : I64_ZERO;
  139. LLVMValueRef vmin, vmax;
  140. if (!(res =
  141. call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_UNO, LLVMRealUNO,
  142. operand, operand, src_type, "fcmp_is_nan"))) {
  143. aot_set_last_error("llvm build fcmp failed.");
  144. goto fail;
  145. }
  146. ADD_BASIC_BLOCK(check_nan_succ, "check_nan_succ");
  147. ADD_BASIC_BLOCK(is_nan_block, "is_nan_block");
  148. ADD_BASIC_BLOCK(check_less_succ, "check_less_succ");
  149. ADD_BASIC_BLOCK(is_less_block, "is_less_block");
  150. ADD_BASIC_BLOCK(check_greater_succ, "check_greater_succ");
  151. ADD_BASIC_BLOCK(is_greater_block, "is_greater_block");
  152. ADD_BASIC_BLOCK(res_block, "res_block");
  153. if (!LLVMBuildCondBr(comp_ctx->builder, res, is_nan_block,
  154. check_nan_succ)) {
  155. aot_set_last_error("llvm build cond br failed.");
  156. goto fail;
  157. }
  158. /* Start to translate is_nan block */
  159. LLVMPositionBuilderAtEnd(comp_ctx->builder, is_nan_block);
  160. if (!LLVMBuildBr(comp_ctx->builder, res_block)) {
  161. aot_set_last_error("llvm build br failed.");
  162. goto fail;
  163. }
  164. /* Start to translate check_nan_succ block */
  165. LLVMPositionBuilderAtEnd(comp_ctx->builder, check_nan_succ);
  166. if (!(is_less = call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_LE,
  167. LLVMRealOLE, operand, min_value,
  168. src_type, "fcmp_min_value"))) {
  169. aot_set_last_error("llvm build fcmp failed.");
  170. goto fail;
  171. }
  172. if (!LLVMBuildCondBr(comp_ctx->builder, is_less, is_less_block,
  173. check_less_succ)) {
  174. aot_set_last_error("llvm build cond br failed.");
  175. goto fail;
  176. }
  177. /* Start to translate is_less block */
  178. LLVMPositionBuilderAtEnd(comp_ctx->builder, is_less_block);
  179. if (!LLVMBuildBr(comp_ctx->builder, res_block)) {
  180. aot_set_last_error("llvm build br failed.");
  181. goto fail;
  182. }
  183. /* Start to translate check_less_succ block */
  184. LLVMPositionBuilderAtEnd(comp_ctx->builder, check_less_succ);
  185. if (!(is_greater = call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_GE,
  186. LLVMRealOGE, operand, max_value,
  187. src_type, "fcmp_max_value"))) {
  188. aot_set_last_error("llvm build fcmp failed.");
  189. goto fail;
  190. }
  191. if (!LLVMBuildCondBr(comp_ctx->builder, is_greater, is_greater_block,
  192. check_greater_succ)) {
  193. aot_set_last_error("llvm build cond br failed.");
  194. goto fail;
  195. }
  196. /* Start to translate is_greater block */
  197. LLVMPositionBuilderAtEnd(comp_ctx->builder, is_greater_block);
  198. if (!LLVMBuildBr(comp_ctx->builder, res_block)) {
  199. aot_set_last_error("llvm build br failed.");
  200. goto fail;
  201. }
  202. /* Start to translate check_greater_succ block */
  203. LLVMPositionBuilderAtEnd(comp_ctx->builder, check_greater_succ);
  204. if (comp_ctx->disable_llvm_intrinsics
  205. && aot_intrinsic_check_capability(comp_ctx, name)) {
  206. LLVMTypeRef param_types[1];
  207. param_types[0] = src_type;
  208. res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, name, dest_type,
  209. param_types, 1, operand);
  210. }
  211. else {
  212. char intrinsic[128];
  213. /* Integer width is always 32 or 64 here. */
  214. snprintf(intrinsic, sizeof(intrinsic), "i%d_trunc_f%d_%c",
  215. LLVMGetIntTypeWidth(dest_type),
  216. LLVMGetTypeKind(src_type) == LLVMFloatTypeKind ? 32 : 64,
  217. sign ? 's' : 'u');
  218. if (comp_ctx->disable_llvm_intrinsics
  219. && aot_intrinsic_check_capability(comp_ctx, intrinsic)) {
  220. res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic,
  221. dest_type, &src_type, 1, operand);
  222. }
  223. else {
  224. if (sign) {
  225. res = LLVMBuildFPToSI(comp_ctx->builder, operand, dest_type,
  226. name);
  227. }
  228. else {
  229. res = LLVMBuildFPToUI(comp_ctx->builder, operand, dest_type,
  230. name);
  231. }
  232. }
  233. }
  234. if (!res) {
  235. aot_set_last_error("llvm build conversion failed.");
  236. return false;
  237. }
  238. if (!LLVMBuildBr(comp_ctx->builder, res_block)) {
  239. aot_set_last_error("llvm build br failed.");
  240. goto fail;
  241. }
  242. /* Start to translate res_block */
  243. LLVMPositionBuilderAtEnd(comp_ctx->builder, res_block);
  244. /* Create result phi */
  245. if (!(phi = LLVMBuildPhi(comp_ctx->builder, dest_type,
  246. "trunc_sat_result_phi"))) {
  247. aot_set_last_error("llvm build phi failed.");
  248. return false;
  249. }
  250. /* Add phi incoming values */
  251. if (dest_type == I32_TYPE) {
  252. if (sign) {
  253. vmin = I32_CONST(INT32_MIN);
  254. vmax = I32_CONST(INT32_MAX);
  255. }
  256. else {
  257. vmin = I32_CONST(0);
  258. vmax = I32_CONST(UINT32_MAX);
  259. }
  260. }
  261. else if (dest_type == I64_TYPE) {
  262. if (sign) {
  263. vmin = I64_CONST(INT64_MIN);
  264. vmax = I64_CONST(INT64_MAX);
  265. }
  266. else {
  267. vmin = I64_CONST(0);
  268. vmax = I64_CONST(UINT64_MAX);
  269. }
  270. }
  271. LLVMAddIncoming(phi, &zero, &is_nan_block, 1);
  272. LLVMAddIncoming(phi, &vmin, &is_less_block, 1);
  273. LLVMAddIncoming(phi, &vmax, &is_greater_block, 1);
  274. LLVMAddIncoming(phi, &res, &check_greater_succ, 1);
  275. if (dest_type == I32_TYPE)
  276. PUSH_I32(phi);
  277. else if (dest_type == I64_TYPE)
  278. PUSH_I64(phi);
  279. return true;
  280. fail:
  281. return false;
  282. }
  283. bool
  284. aot_compile_op_i32_wrap_i64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
  285. {
  286. LLVMValueRef value, res;
  287. POP_I64(value);
  288. if (!(res = LLVMBuildTrunc(comp_ctx->builder, value, I32_TYPE,
  289. "i32_wrap_i64"))) {
  290. aot_set_last_error("llvm build conversion failed.");
  291. return false;
  292. }
  293. PUSH_I32(res);
  294. return true;
  295. fail:
  296. return false;
  297. }
  298. bool
  299. aot_compile_op_i32_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  300. bool sign, bool saturating)
  301. {
  302. LLVMValueRef value;
  303. LLVMValueRef min_value, max_value;
  304. POP_F32(value);
  305. if (!comp_ctx->is_indirect_mode) {
  306. if (sign) {
  307. min_value = F32_CONST(-2147483904.0f);
  308. max_value = F32_CONST(2147483648.0f);
  309. }
  310. else {
  311. min_value = F32_CONST(-1.0f);
  312. max_value = F32_CONST(4294967296.0f);
  313. }
  314. }
  315. else {
  316. WASMValue wasm_value;
  317. if (sign) {
  318. wasm_value.f32 = -2147483904.0f;
  319. min_value = aot_load_const_from_table(
  320. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32);
  321. wasm_value.f32 = 2147483648.0f;
  322. max_value = aot_load_const_from_table(
  323. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32);
  324. }
  325. else {
  326. wasm_value.f32 = -1.0f;
  327. min_value = aot_load_const_from_table(
  328. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32);
  329. wasm_value.f32 = 4294967296.0f;
  330. max_value = aot_load_const_from_table(
  331. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32);
  332. }
  333. }
  334. CHECK_LLVM_CONST(min_value);
  335. CHECK_LLVM_CONST(max_value);
  336. if (!saturating)
  337. return trunc_float_to_int(
  338. comp_ctx, func_ctx, value, F32_TYPE, I32_TYPE, min_value, max_value,
  339. sign ? "i32_trunc_f32_s" : "i32_trunc_f32_u", sign);
  340. else
  341. return trunc_sat_float_to_int(
  342. comp_ctx, func_ctx, value, F32_TYPE, I32_TYPE, min_value, max_value,
  343. sign ? "i32_trunc_sat_f32_s" : "i32_trunc_sat_f32_u", sign);
  344. fail:
  345. return false;
  346. }
  347. bool
  348. aot_compile_op_i32_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  349. bool sign, bool saturating)
  350. {
  351. LLVMValueRef value;
  352. LLVMValueRef min_value, max_value;
  353. POP_F64(value);
  354. if (!comp_ctx->is_indirect_mode) {
  355. if (sign) {
  356. min_value = F64_CONST(-2147483649.0);
  357. max_value = F64_CONST(2147483648.0);
  358. }
  359. else {
  360. min_value = F64_CONST(-1.0);
  361. max_value = F64_CONST(4294967296.0);
  362. }
  363. }
  364. else {
  365. WASMValue wasm_value;
  366. if (sign) {
  367. wasm_value.f64 = -2147483649.0;
  368. min_value = aot_load_const_from_table(
  369. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64);
  370. wasm_value.f64 = 2147483648.0;
  371. max_value = aot_load_const_from_table(
  372. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64);
  373. }
  374. else {
  375. wasm_value.f64 = -1.0;
  376. min_value = aot_load_const_from_table(
  377. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64);
  378. wasm_value.f64 = 4294967296.0;
  379. max_value = aot_load_const_from_table(
  380. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64);
  381. }
  382. }
  383. CHECK_LLVM_CONST(min_value);
  384. CHECK_LLVM_CONST(max_value);
  385. if (!saturating)
  386. return trunc_float_to_int(
  387. comp_ctx, func_ctx, value, F64_TYPE, I32_TYPE, min_value, max_value,
  388. sign ? "i32_trunc_f64_s" : "i32_trunc_f64_u", sign);
  389. else
  390. return trunc_sat_float_to_int(
  391. comp_ctx, func_ctx, value, F64_TYPE, I32_TYPE, min_value, max_value,
  392. sign ? "i32_trunc_sat_f64_s" : "i32_trunc_sat_f64_u", sign);
  393. fail:
  394. return false;
  395. }
  396. bool
  397. aot_compile_op_i64_extend_i32(AOTCompContext *comp_ctx,
  398. AOTFuncContext *func_ctx, bool sign)
  399. {
  400. LLVMValueRef value, res;
  401. POP_I32(value);
  402. if (sign)
  403. res = LLVMBuildSExt(comp_ctx->builder, value, I64_TYPE,
  404. "i64_extend_i32_s");
  405. else
  406. res = LLVMBuildZExt(comp_ctx->builder, value, I64_TYPE,
  407. "i64_extend_i32_u");
  408. if (!res) {
  409. aot_set_last_error("llvm build conversion failed.");
  410. return false;
  411. }
  412. PUSH_I64(res);
  413. return true;
  414. fail:
  415. return false;
  416. }
  417. bool
  418. aot_compile_op_i64_extend_i64(AOTCompContext *comp_ctx,
  419. AOTFuncContext *func_ctx, int8 bitwidth)
  420. {
  421. LLVMValueRef value, res, cast_value = NULL;
  422. POP_I64(value);
  423. if (bitwidth == 8) {
  424. cast_value = LLVMBuildIntCast2(comp_ctx->builder, value, INT8_TYPE,
  425. true, "i8_intcast_i64");
  426. }
  427. else if (bitwidth == 16) {
  428. cast_value = LLVMBuildIntCast2(comp_ctx->builder, value, INT16_TYPE,
  429. true, "i16_intcast_i64");
  430. }
  431. else if (bitwidth == 32) {
  432. cast_value = LLVMBuildIntCast2(comp_ctx->builder, value, I32_TYPE, true,
  433. "i32_intcast_i64");
  434. }
  435. if (!cast_value) {
  436. aot_set_last_error("llvm build conversion failed.");
  437. return false;
  438. }
  439. res = LLVMBuildSExt(comp_ctx->builder, cast_value, I64_TYPE,
  440. "i64_extend_i64_s");
  441. if (!res) {
  442. aot_set_last_error("llvm build conversion failed.");
  443. return false;
  444. }
  445. PUSH_I64(res);
  446. return true;
  447. fail:
  448. return false;
  449. }
  450. bool
  451. aot_compile_op_i32_extend_i32(AOTCompContext *comp_ctx,
  452. AOTFuncContext *func_ctx, int8 bitwidth)
  453. {
  454. LLVMValueRef value, res, cast_value = NULL;
  455. POP_I32(value);
  456. if (bitwidth == 8) {
  457. cast_value = LLVMBuildIntCast2(comp_ctx->builder, value, INT8_TYPE,
  458. true, "i8_intcast_i32");
  459. }
  460. else if (bitwidth == 16) {
  461. cast_value = LLVMBuildIntCast2(comp_ctx->builder, value, INT16_TYPE,
  462. true, "i16_intcast_i32");
  463. }
  464. if (!cast_value) {
  465. aot_set_last_error("llvm build conversion failed.");
  466. return false;
  467. }
  468. res = LLVMBuildSExt(comp_ctx->builder, cast_value, I32_TYPE,
  469. "i32_extend_i32_s");
  470. if (!res) {
  471. aot_set_last_error("llvm build conversion failed.");
  472. return false;
  473. }
  474. PUSH_I32(res);
  475. return true;
  476. fail:
  477. return false;
  478. }
  479. bool
  480. aot_compile_op_i64_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  481. bool sign, bool saturating)
  482. {
  483. LLVMValueRef value;
  484. LLVMValueRef min_value, max_value;
  485. POP_F32(value);
  486. if (!comp_ctx->is_indirect_mode) {
  487. if (sign) {
  488. min_value = F32_CONST(-9223373136366403584.0f);
  489. max_value = F32_CONST(9223372036854775808.0f);
  490. }
  491. else {
  492. min_value = F32_CONST(-1.0f);
  493. max_value = F32_CONST(18446744073709551616.0f);
  494. }
  495. }
  496. else {
  497. WASMValue wasm_value;
  498. if (sign) {
  499. wasm_value.f32 = -9223373136366403584.0f;
  500. min_value = aot_load_const_from_table(
  501. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32);
  502. wasm_value.f32 = 9223372036854775808.0f;
  503. max_value = aot_load_const_from_table(
  504. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32);
  505. }
  506. else {
  507. wasm_value.f32 = -1.0f;
  508. min_value = aot_load_const_from_table(
  509. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32);
  510. wasm_value.f32 = 18446744073709551616.0f;
  511. max_value = aot_load_const_from_table(
  512. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32);
  513. }
  514. }
  515. CHECK_LLVM_CONST(min_value);
  516. CHECK_LLVM_CONST(max_value);
  517. if (!saturating)
  518. return trunc_float_to_int(
  519. comp_ctx, func_ctx, value, F32_TYPE, I64_TYPE, min_value, max_value,
  520. sign ? "i64_trunc_f32_s" : "i64_trunc_f32_u", sign);
  521. else
  522. return trunc_sat_float_to_int(
  523. comp_ctx, func_ctx, value, F32_TYPE, I64_TYPE, min_value, max_value,
  524. sign ? "i64_trunc_sat_f32_s" : "i64_trunc_sat_f32_u", sign);
  525. fail:
  526. return false;
  527. }
  528. bool
  529. aot_compile_op_i64_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  530. bool sign, bool saturating)
  531. {
  532. LLVMValueRef value;
  533. LLVMValueRef min_value, max_value;
  534. POP_F64(value);
  535. if (!comp_ctx->is_indirect_mode) {
  536. if (sign) {
  537. min_value = F64_CONST(-9223372036854777856.0);
  538. max_value = F64_CONST(9223372036854775808.0);
  539. }
  540. else {
  541. min_value = F64_CONST(-1.0);
  542. max_value = F64_CONST(18446744073709551616.0);
  543. }
  544. }
  545. else {
  546. WASMValue wasm_value;
  547. if (sign) {
  548. wasm_value.f64 = -9223372036854777856.0;
  549. min_value = aot_load_const_from_table(
  550. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64);
  551. wasm_value.f64 = 9223372036854775808.0;
  552. max_value = aot_load_const_from_table(
  553. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64);
  554. }
  555. else {
  556. wasm_value.f64 = -1.0;
  557. min_value = aot_load_const_from_table(
  558. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64);
  559. wasm_value.f64 = 18446744073709551616.0;
  560. max_value = aot_load_const_from_table(
  561. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64);
  562. }
  563. }
  564. CHECK_LLVM_CONST(min_value);
  565. CHECK_LLVM_CONST(max_value);
  566. if (!saturating)
  567. return trunc_float_to_int(
  568. comp_ctx, func_ctx, value, F64_TYPE, I64_TYPE, min_value, max_value,
  569. sign ? "i64_trunc_f64_s" : "i64_trunc_f64_u", sign);
  570. else
  571. return trunc_sat_float_to_int(
  572. comp_ctx, func_ctx, value, F64_TYPE, I64_TYPE, min_value, max_value,
  573. sign ? "i64_trunc_sat_f64_s" : "i64_trunc_sat_f64_u", sign);
  574. fail:
  575. return false;
  576. }
  577. bool
  578. aot_compile_op_f32_convert_i32(AOTCompContext *comp_ctx,
  579. AOTFuncContext *func_ctx, bool sign)
  580. {
  581. LLVMValueRef value, res;
  582. POP_I32(value);
  583. if (comp_ctx->disable_llvm_intrinsics
  584. && aot_intrinsic_check_capability(
  585. comp_ctx, sign ? "f32_convert_i32_s" : "f32_convert_i32_u")) {
  586. LLVMTypeRef param_types[1];
  587. param_types[0] = I32_TYPE;
  588. res = aot_call_llvm_intrinsic(comp_ctx, func_ctx,
  589. sign ? "f32_convert_i32_s"
  590. : "f32_convert_i32_u",
  591. F32_TYPE, param_types, 1, value);
  592. }
  593. else {
  594. if (sign)
  595. res = LLVMBuildSIToFP(comp_ctx->builder, value, F32_TYPE,
  596. "f32_convert_i32_s");
  597. else
  598. res = LLVMBuildUIToFP(comp_ctx->builder, value, F32_TYPE,
  599. "f32_convert_i32_u");
  600. }
  601. if (!res) {
  602. aot_set_last_error("llvm build conversion failed.");
  603. return false;
  604. }
  605. PUSH_F32(res);
  606. return true;
  607. fail:
  608. return false;
  609. }
  610. bool
  611. aot_compile_op_f32_convert_i64(AOTCompContext *comp_ctx,
  612. AOTFuncContext *func_ctx, bool sign)
  613. {
  614. LLVMValueRef value, res;
  615. POP_I64(value);
  616. if (comp_ctx->disable_llvm_intrinsics
  617. && aot_intrinsic_check_capability(
  618. comp_ctx, sign ? "f32_convert_i64_s" : "f32_convert_i64_u")) {
  619. LLVMTypeRef param_types[1];
  620. param_types[0] = I64_TYPE;
  621. res = aot_call_llvm_intrinsic(comp_ctx, func_ctx,
  622. sign ? "f32_convert_i64_s"
  623. : "f32_convert_i64_u",
  624. F32_TYPE, param_types, 1, value);
  625. }
  626. else {
  627. if (sign)
  628. res = LLVMBuildSIToFP(comp_ctx->builder, value, F32_TYPE,
  629. "f32_convert_i64_s");
  630. else
  631. res = LLVMBuildUIToFP(comp_ctx->builder, value, F32_TYPE,
  632. "f32_convert_i64_u");
  633. }
  634. if (!res) {
  635. aot_set_last_error("llvm build conversion failed.");
  636. return false;
  637. }
  638. PUSH_F32(res);
  639. return true;
  640. fail:
  641. return false;
  642. }
  643. bool
  644. aot_compile_op_f32_demote_f64(AOTCompContext *comp_ctx,
  645. AOTFuncContext *func_ctx)
  646. {
  647. LLVMValueRef value, res;
  648. POP_F64(value);
  649. if (comp_ctx->disable_llvm_intrinsics
  650. && aot_intrinsic_check_capability(comp_ctx, "f32_demote_f64")) {
  651. LLVMTypeRef param_types[1];
  652. param_types[0] = F64_TYPE;
  653. res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, "f32_demote_f64",
  654. F32_TYPE, param_types, 1, value);
  655. }
  656. else {
  657. res = LLVMBuildFPTrunc(comp_ctx->builder, value, F32_TYPE,
  658. "f32_demote_f64");
  659. }
  660. if (!res) {
  661. aot_set_last_error("llvm build conversion failed.");
  662. return false;
  663. }
  664. PUSH_F32(res);
  665. return true;
  666. fail:
  667. return false;
  668. }
  669. bool
  670. aot_compile_op_f64_convert_i32(AOTCompContext *comp_ctx,
  671. AOTFuncContext *func_ctx, bool sign)
  672. {
  673. LLVMValueRef value, res;
  674. POP_I32(value);
  675. if (comp_ctx->disable_llvm_intrinsics
  676. && aot_intrinsic_check_capability(
  677. comp_ctx, sign ? "f64_convert_i32_s" : "f64_convert_i32_u")) {
  678. LLVMTypeRef param_types[1];
  679. param_types[0] = I32_TYPE;
  680. res = aot_call_llvm_intrinsic(comp_ctx, func_ctx,
  681. sign ? "f64_convert_i32_s"
  682. : "f64_convert_i32_u",
  683. F64_TYPE, param_types, 1, value);
  684. }
  685. else {
  686. if (sign)
  687. res = LLVMBuildSIToFP(comp_ctx->builder, value, F64_TYPE,
  688. "f64_convert_i32_s");
  689. else
  690. res = LLVMBuildUIToFP(comp_ctx->builder, value, F64_TYPE,
  691. "f64_convert_i32_u");
  692. }
  693. if (!res) {
  694. aot_set_last_error("llvm build conversion failed.");
  695. return false;
  696. }
  697. PUSH_F64(res);
  698. return true;
  699. fail:
  700. return false;
  701. }
  702. bool
  703. aot_compile_op_f64_convert_i64(AOTCompContext *comp_ctx,
  704. AOTFuncContext *func_ctx, bool sign)
  705. {
  706. LLVMValueRef value, res;
  707. POP_I64(value);
  708. if (comp_ctx->disable_llvm_intrinsics
  709. && aot_intrinsic_check_capability(
  710. comp_ctx, sign ? "f64_convert_i64_s" : "f64_convert_i64_u")) {
  711. LLVMTypeRef param_types[1];
  712. param_types[0] = I64_TYPE;
  713. res = aot_call_llvm_intrinsic(comp_ctx, func_ctx,
  714. sign ? "f64_convert_i64_s"
  715. : "f64_convert_i64_u",
  716. F64_TYPE, param_types, 1, value);
  717. }
  718. else {
  719. if (sign)
  720. res = LLVMBuildSIToFP(comp_ctx->builder, value, F64_TYPE,
  721. "f64_convert_i64_s");
  722. else
  723. res = LLVMBuildUIToFP(comp_ctx->builder, value, F64_TYPE,
  724. "f64_convert_i64_u");
  725. }
  726. if (!res) {
  727. aot_set_last_error("llvm build conversion failed.");
  728. return false;
  729. }
  730. PUSH_F64(res);
  731. return true;
  732. fail:
  733. return false;
  734. }
  735. bool
  736. aot_compile_op_f64_promote_f32(AOTCompContext *comp_ctx,
  737. AOTFuncContext *func_ctx)
  738. {
  739. LLVMValueRef value, res;
  740. POP_F32(value);
  741. if (comp_ctx->disable_llvm_intrinsics
  742. && aot_intrinsic_check_capability(comp_ctx, "f64_promote_f32")) {
  743. LLVMTypeRef param_types[1];
  744. param_types[0] = F32_TYPE;
  745. res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, "f64_promote_f32",
  746. F64_TYPE, param_types, 1, value);
  747. }
  748. else {
  749. res = LLVMBuildFPExt(comp_ctx->builder, value, F64_TYPE,
  750. "f64_promote_f32");
  751. }
  752. if (!res) {
  753. aot_set_last_error("llvm build conversion failed.");
  754. return false;
  755. }
  756. PUSH_F64(res);
  757. /* Avoid the promote being optimized away */
  758. PUSH_F64(F64_CONST(1.0));
  759. return aot_compile_op_f64_arithmetic(comp_ctx, func_ctx, FLOAT_MUL);
  760. fail:
  761. return false;
  762. }
  763. bool
  764. aot_compile_op_i64_reinterpret_f64(AOTCompContext *comp_ctx,
  765. AOTFuncContext *func_ctx)
  766. {
  767. LLVMValueRef value;
  768. POP_F64(value);
  769. if (!(value =
  770. LLVMBuildBitCast(comp_ctx->builder, value, I64_TYPE, "i64"))) {
  771. aot_set_last_error("llvm build fp to si failed.");
  772. return false;
  773. }
  774. PUSH_I64(value);
  775. return true;
  776. fail:
  777. return false;
  778. }
  779. bool
  780. aot_compile_op_i32_reinterpret_f32(AOTCompContext *comp_ctx,
  781. AOTFuncContext *func_ctx)
  782. {
  783. LLVMValueRef value;
  784. POP_F32(value);
  785. if (!(value =
  786. LLVMBuildBitCast(comp_ctx->builder, value, I32_TYPE, "i32"))) {
  787. aot_set_last_error("llvm build fp to si failed.");
  788. return false;
  789. }
  790. PUSH_I32(value);
  791. return true;
  792. fail:
  793. return false;
  794. }
  795. bool
  796. aot_compile_op_f64_reinterpret_i64(AOTCompContext *comp_ctx,
  797. AOTFuncContext *func_ctx)
  798. {
  799. LLVMValueRef value;
  800. POP_I64(value);
  801. if (!(value =
  802. LLVMBuildBitCast(comp_ctx->builder, value, F64_TYPE, "f64"))) {
  803. aot_set_last_error("llvm build si to fp failed.");
  804. return false;
  805. }
  806. PUSH_F64(value);
  807. return true;
  808. fail:
  809. return false;
  810. }
  811. bool
  812. aot_compile_op_f32_reinterpret_i32(AOTCompContext *comp_ctx,
  813. AOTFuncContext *func_ctx)
  814. {
  815. LLVMValueRef value;
  816. POP_I32(value);
  817. if (!(value =
  818. LLVMBuildBitCast(comp_ctx->builder, value, F32_TYPE, "f32"))) {
  819. aot_set_last_error("llvm build si to fp failed.");
  820. return false;
  821. }
  822. PUSH_F32(value);
  823. return true;
  824. fail:
  825. return false;
  826. }