aot_emit_conversion.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943
  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. && aot_intrinsic_check_capability(comp_ctx, "f32.const")) {
  307. WASMValue wasm_value;
  308. if (sign) {
  309. wasm_value.f32 = -2147483904.0f;
  310. min_value = aot_load_const_from_table(
  311. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32);
  312. wasm_value.f32 = 2147483648.0f;
  313. max_value = aot_load_const_from_table(
  314. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32);
  315. }
  316. else {
  317. wasm_value.f32 = -1.0f;
  318. min_value = aot_load_const_from_table(
  319. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32);
  320. wasm_value.f32 = 4294967296.0f;
  321. max_value = aot_load_const_from_table(
  322. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32);
  323. }
  324. }
  325. else {
  326. if (sign) {
  327. min_value = F32_CONST(-2147483904.0f);
  328. max_value = F32_CONST(2147483648.0f);
  329. }
  330. else {
  331. min_value = F32_CONST(-1.0f);
  332. max_value = F32_CONST(4294967296.0f);
  333. }
  334. }
  335. CHECK_LLVM_CONST(min_value);
  336. CHECK_LLVM_CONST(max_value);
  337. if (!saturating)
  338. return trunc_float_to_int(
  339. comp_ctx, func_ctx, value, F32_TYPE, I32_TYPE, min_value, max_value,
  340. sign ? "i32_trunc_f32_s" : "i32_trunc_f32_u", sign);
  341. else
  342. return trunc_sat_float_to_int(
  343. comp_ctx, func_ctx, value, F32_TYPE, I32_TYPE, min_value, max_value,
  344. sign ? "i32_trunc_sat_f32_s" : "i32_trunc_sat_f32_u", sign);
  345. fail:
  346. return false;
  347. }
  348. bool
  349. aot_compile_op_i32_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  350. bool sign, bool saturating)
  351. {
  352. LLVMValueRef value;
  353. LLVMValueRef min_value, max_value;
  354. POP_F64(value);
  355. if (comp_ctx->is_indirect_mode
  356. && aot_intrinsic_check_capability(comp_ctx, "f64.const")) {
  357. WASMValue wasm_value;
  358. if (sign) {
  359. wasm_value.f64 = -2147483649.0;
  360. min_value = aot_load_const_from_table(
  361. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64);
  362. wasm_value.f64 = 2147483648.0;
  363. max_value = aot_load_const_from_table(
  364. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64);
  365. }
  366. else {
  367. wasm_value.f64 = -1.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 = 4294967296.0;
  371. max_value = aot_load_const_from_table(
  372. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64);
  373. }
  374. }
  375. else {
  376. if (sign) {
  377. min_value = F64_CONST(-2147483649.0);
  378. max_value = F64_CONST(2147483648.0);
  379. }
  380. else {
  381. min_value = F64_CONST(-1.0);
  382. max_value = F64_CONST(4294967296.0);
  383. }
  384. }
  385. CHECK_LLVM_CONST(min_value);
  386. CHECK_LLVM_CONST(max_value);
  387. if (!saturating)
  388. return trunc_float_to_int(
  389. comp_ctx, func_ctx, value, F64_TYPE, I32_TYPE, min_value, max_value,
  390. sign ? "i32_trunc_f64_s" : "i32_trunc_f64_u", sign);
  391. else
  392. return trunc_sat_float_to_int(
  393. comp_ctx, func_ctx, value, F64_TYPE, I32_TYPE, min_value, max_value,
  394. sign ? "i32_trunc_sat_f64_s" : "i32_trunc_sat_f64_u", sign);
  395. fail:
  396. return false;
  397. }
  398. bool
  399. aot_compile_op_i64_extend_i32(AOTCompContext *comp_ctx,
  400. AOTFuncContext *func_ctx, bool sign)
  401. {
  402. LLVMValueRef value, res;
  403. POP_I32(value);
  404. if (sign)
  405. res = LLVMBuildSExt(comp_ctx->builder, value, I64_TYPE,
  406. "i64_extend_i32_s");
  407. else
  408. res = LLVMBuildZExt(comp_ctx->builder, value, I64_TYPE,
  409. "i64_extend_i32_u");
  410. if (!res) {
  411. aot_set_last_error("llvm build conversion failed.");
  412. return false;
  413. }
  414. PUSH_I64(res);
  415. return true;
  416. fail:
  417. return false;
  418. }
  419. bool
  420. aot_compile_op_i64_extend_i64(AOTCompContext *comp_ctx,
  421. AOTFuncContext *func_ctx, int8 bitwidth)
  422. {
  423. LLVMValueRef value, res, cast_value = NULL;
  424. POP_I64(value);
  425. if (bitwidth == 8) {
  426. cast_value = LLVMBuildIntCast2(comp_ctx->builder, value, INT8_TYPE,
  427. true, "i8_intcast_i64");
  428. }
  429. else if (bitwidth == 16) {
  430. cast_value = LLVMBuildIntCast2(comp_ctx->builder, value, INT16_TYPE,
  431. true, "i16_intcast_i64");
  432. }
  433. else if (bitwidth == 32) {
  434. cast_value = LLVMBuildIntCast2(comp_ctx->builder, value, I32_TYPE, true,
  435. "i32_intcast_i64");
  436. }
  437. if (!cast_value) {
  438. aot_set_last_error("llvm build conversion failed.");
  439. return false;
  440. }
  441. res = LLVMBuildSExt(comp_ctx->builder, cast_value, I64_TYPE,
  442. "i64_extend_i64_s");
  443. if (!res) {
  444. aot_set_last_error("llvm build conversion failed.");
  445. return false;
  446. }
  447. PUSH_I64(res);
  448. return true;
  449. fail:
  450. return false;
  451. }
  452. bool
  453. aot_compile_op_i32_extend_i32(AOTCompContext *comp_ctx,
  454. AOTFuncContext *func_ctx, int8 bitwidth)
  455. {
  456. LLVMValueRef value, res, cast_value = NULL;
  457. POP_I32(value);
  458. if (bitwidth == 8) {
  459. cast_value = LLVMBuildIntCast2(comp_ctx->builder, value, INT8_TYPE,
  460. true, "i8_intcast_i32");
  461. }
  462. else if (bitwidth == 16) {
  463. cast_value = LLVMBuildIntCast2(comp_ctx->builder, value, INT16_TYPE,
  464. true, "i16_intcast_i32");
  465. }
  466. if (!cast_value) {
  467. aot_set_last_error("llvm build conversion failed.");
  468. return false;
  469. }
  470. res = LLVMBuildSExt(comp_ctx->builder, cast_value, I32_TYPE,
  471. "i32_extend_i32_s");
  472. if (!res) {
  473. aot_set_last_error("llvm build conversion failed.");
  474. return false;
  475. }
  476. PUSH_I32(res);
  477. return true;
  478. fail:
  479. return false;
  480. }
  481. bool
  482. aot_compile_op_i64_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  483. bool sign, bool saturating)
  484. {
  485. LLVMValueRef value;
  486. LLVMValueRef min_value, max_value;
  487. POP_F32(value);
  488. if (comp_ctx->is_indirect_mode
  489. && aot_intrinsic_check_capability(comp_ctx, "f32.const")) {
  490. WASMValue wasm_value;
  491. if (sign) {
  492. wasm_value.f32 = -9223373136366403584.0f;
  493. min_value = aot_load_const_from_table(
  494. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32);
  495. wasm_value.f32 = 9223372036854775808.0f;
  496. max_value = aot_load_const_from_table(
  497. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32);
  498. }
  499. else {
  500. wasm_value.f32 = -1.0f;
  501. min_value = aot_load_const_from_table(
  502. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32);
  503. wasm_value.f32 = 18446744073709551616.0f;
  504. max_value = aot_load_const_from_table(
  505. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32);
  506. }
  507. }
  508. else {
  509. if (sign) {
  510. min_value = F32_CONST(-9223373136366403584.0f);
  511. max_value = F32_CONST(9223372036854775808.0f);
  512. }
  513. else {
  514. min_value = F32_CONST(-1.0f);
  515. max_value = F32_CONST(18446744073709551616.0f);
  516. }
  517. }
  518. CHECK_LLVM_CONST(min_value);
  519. CHECK_LLVM_CONST(max_value);
  520. if (!saturating)
  521. return trunc_float_to_int(
  522. comp_ctx, func_ctx, value, F32_TYPE, I64_TYPE, min_value, max_value,
  523. sign ? "i64_trunc_f32_s" : "i64_trunc_f32_u", sign);
  524. else
  525. return trunc_sat_float_to_int(
  526. comp_ctx, func_ctx, value, F32_TYPE, I64_TYPE, min_value, max_value,
  527. sign ? "i64_trunc_sat_f32_s" : "i64_trunc_sat_f32_u", sign);
  528. fail:
  529. return false;
  530. }
  531. bool
  532. aot_compile_op_i64_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  533. bool sign, bool saturating)
  534. {
  535. LLVMValueRef value;
  536. LLVMValueRef min_value, max_value;
  537. POP_F64(value);
  538. if (comp_ctx->is_indirect_mode
  539. && aot_intrinsic_check_capability(comp_ctx, "f64.const")) {
  540. WASMValue wasm_value;
  541. if (sign) {
  542. wasm_value.f64 = -9223372036854777856.0;
  543. min_value = aot_load_const_from_table(
  544. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64);
  545. wasm_value.f64 = 9223372036854775808.0;
  546. max_value = aot_load_const_from_table(
  547. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64);
  548. }
  549. else {
  550. wasm_value.f64 = -1.0;
  551. min_value = aot_load_const_from_table(
  552. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64);
  553. wasm_value.f64 = 18446744073709551616.0;
  554. max_value = aot_load_const_from_table(
  555. comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64);
  556. }
  557. }
  558. else {
  559. if (sign) {
  560. min_value = F64_CONST(-9223372036854777856.0);
  561. max_value = F64_CONST(9223372036854775808.0);
  562. }
  563. else {
  564. min_value = F64_CONST(-1.0);
  565. max_value = F64_CONST(18446744073709551616.0);
  566. }
  567. }
  568. CHECK_LLVM_CONST(min_value);
  569. CHECK_LLVM_CONST(max_value);
  570. if (!saturating)
  571. return trunc_float_to_int(
  572. comp_ctx, func_ctx, value, F64_TYPE, I64_TYPE, min_value, max_value,
  573. sign ? "i64_trunc_f64_s" : "i64_trunc_f64_u", sign);
  574. else
  575. return trunc_sat_float_to_int(
  576. comp_ctx, func_ctx, value, F64_TYPE, I64_TYPE, min_value, max_value,
  577. sign ? "i64_trunc_sat_f64_s" : "i64_trunc_sat_f64_u", sign);
  578. fail:
  579. return false;
  580. }
  581. bool
  582. aot_compile_op_f32_convert_i32(AOTCompContext *comp_ctx,
  583. AOTFuncContext *func_ctx, bool sign)
  584. {
  585. LLVMValueRef value, res;
  586. POP_I32(value);
  587. if (comp_ctx->disable_llvm_intrinsics
  588. && aot_intrinsic_check_capability(
  589. comp_ctx, sign ? "f32_convert_i32_s" : "f32_convert_i32_u")) {
  590. LLVMTypeRef param_types[1];
  591. param_types[0] = I32_TYPE;
  592. res = aot_call_llvm_intrinsic(comp_ctx, func_ctx,
  593. sign ? "f32_convert_i32_s"
  594. : "f32_convert_i32_u",
  595. F32_TYPE, param_types, 1, value);
  596. }
  597. else {
  598. if (sign)
  599. res = LLVMBuildSIToFP(comp_ctx->builder, value, F32_TYPE,
  600. "f32_convert_i32_s");
  601. else
  602. res = LLVMBuildUIToFP(comp_ctx->builder, value, F32_TYPE,
  603. "f32_convert_i32_u");
  604. }
  605. if (!res) {
  606. aot_set_last_error("llvm build conversion failed.");
  607. return false;
  608. }
  609. PUSH_F32(res);
  610. return true;
  611. fail:
  612. return false;
  613. }
  614. bool
  615. aot_compile_op_f32_convert_i64(AOTCompContext *comp_ctx,
  616. AOTFuncContext *func_ctx, bool sign)
  617. {
  618. LLVMValueRef value, res;
  619. POP_I64(value);
  620. if (comp_ctx->disable_llvm_intrinsics
  621. && aot_intrinsic_check_capability(
  622. comp_ctx, sign ? "f32_convert_i64_s" : "f32_convert_i64_u")) {
  623. LLVMTypeRef param_types[1];
  624. param_types[0] = I64_TYPE;
  625. res = aot_call_llvm_intrinsic(comp_ctx, func_ctx,
  626. sign ? "f32_convert_i64_s"
  627. : "f32_convert_i64_u",
  628. F32_TYPE, param_types, 1, value);
  629. }
  630. else {
  631. if (sign)
  632. res = LLVMBuildSIToFP(comp_ctx->builder, value, F32_TYPE,
  633. "f32_convert_i64_s");
  634. else
  635. res = LLVMBuildUIToFP(comp_ctx->builder, value, F32_TYPE,
  636. "f32_convert_i64_u");
  637. }
  638. if (!res) {
  639. aot_set_last_error("llvm build conversion failed.");
  640. return false;
  641. }
  642. PUSH_F32(res);
  643. return true;
  644. fail:
  645. return false;
  646. }
  647. bool
  648. aot_compile_op_f32_demote_f64(AOTCompContext *comp_ctx,
  649. AOTFuncContext *func_ctx)
  650. {
  651. LLVMValueRef value, res;
  652. POP_F64(value);
  653. if (comp_ctx->disable_llvm_intrinsics
  654. && aot_intrinsic_check_capability(comp_ctx, "f32_demote_f64")) {
  655. LLVMTypeRef param_types[1];
  656. param_types[0] = F64_TYPE;
  657. res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, "f32_demote_f64",
  658. F32_TYPE, param_types, 1, value);
  659. }
  660. else {
  661. res = LLVMBuildFPTrunc(comp_ctx->builder, value, F32_TYPE,
  662. "f32_demote_f64");
  663. }
  664. if (!res) {
  665. aot_set_last_error("llvm build conversion failed.");
  666. return false;
  667. }
  668. PUSH_F32(res);
  669. return true;
  670. fail:
  671. return false;
  672. }
  673. bool
  674. aot_compile_op_f64_convert_i32(AOTCompContext *comp_ctx,
  675. AOTFuncContext *func_ctx, bool sign)
  676. {
  677. LLVMValueRef value, res;
  678. POP_I32(value);
  679. if (comp_ctx->disable_llvm_intrinsics
  680. && aot_intrinsic_check_capability(
  681. comp_ctx, sign ? "f64_convert_i32_s" : "f64_convert_i32_u")) {
  682. LLVMTypeRef param_types[1];
  683. param_types[0] = I32_TYPE;
  684. res = aot_call_llvm_intrinsic(comp_ctx, func_ctx,
  685. sign ? "f64_convert_i32_s"
  686. : "f64_convert_i32_u",
  687. F64_TYPE, param_types, 1, value);
  688. }
  689. else {
  690. if (sign)
  691. res = LLVMBuildSIToFP(comp_ctx->builder, value, F64_TYPE,
  692. "f64_convert_i32_s");
  693. else
  694. res = LLVMBuildUIToFP(comp_ctx->builder, value, F64_TYPE,
  695. "f64_convert_i32_u");
  696. }
  697. if (!res) {
  698. aot_set_last_error("llvm build conversion failed.");
  699. return false;
  700. }
  701. PUSH_F64(res);
  702. return true;
  703. fail:
  704. return false;
  705. }
  706. bool
  707. aot_compile_op_f64_convert_i64(AOTCompContext *comp_ctx,
  708. AOTFuncContext *func_ctx, bool sign)
  709. {
  710. LLVMValueRef value, res;
  711. POP_I64(value);
  712. if (comp_ctx->disable_llvm_intrinsics
  713. && aot_intrinsic_check_capability(
  714. comp_ctx, sign ? "f64_convert_i64_s" : "f64_convert_i64_u")) {
  715. LLVMTypeRef param_types[1];
  716. param_types[0] = I64_TYPE;
  717. res = aot_call_llvm_intrinsic(comp_ctx, func_ctx,
  718. sign ? "f64_convert_i64_s"
  719. : "f64_convert_i64_u",
  720. F64_TYPE, param_types, 1, value);
  721. }
  722. else {
  723. if (sign)
  724. res = LLVMBuildSIToFP(comp_ctx->builder, value, F64_TYPE,
  725. "f64_convert_i64_s");
  726. else
  727. res = LLVMBuildUIToFP(comp_ctx->builder, value, F64_TYPE,
  728. "f64_convert_i64_u");
  729. }
  730. if (!res) {
  731. aot_set_last_error("llvm build conversion failed.");
  732. return false;
  733. }
  734. PUSH_F64(res);
  735. return true;
  736. fail:
  737. return false;
  738. }
  739. bool
  740. aot_compile_op_f64_promote_f32(AOTCompContext *comp_ctx,
  741. AOTFuncContext *func_ctx)
  742. {
  743. LLVMValueRef value, res;
  744. POP_F32(value);
  745. if (comp_ctx->disable_llvm_intrinsics
  746. && aot_intrinsic_check_capability(comp_ctx, "f64_promote_f32")) {
  747. LLVMTypeRef param_types[1];
  748. param_types[0] = F32_TYPE;
  749. res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, "f64_promote_f32",
  750. F64_TYPE, param_types, 1, value);
  751. }
  752. else {
  753. res = LLVMBuildFPExt(comp_ctx->builder, value, F64_TYPE,
  754. "f64_promote_f32");
  755. }
  756. if (!res) {
  757. aot_set_last_error("llvm build conversion failed.");
  758. return false;
  759. }
  760. PUSH_F64(res);
  761. /* Avoid the promote being optimized away */
  762. PUSH_F64(F64_CONST(1.0));
  763. return aot_compile_op_f64_arithmetic(comp_ctx, func_ctx, FLOAT_MUL);
  764. fail:
  765. return false;
  766. }
  767. bool
  768. aot_compile_op_i64_reinterpret_f64(AOTCompContext *comp_ctx,
  769. AOTFuncContext *func_ctx)
  770. {
  771. LLVMValueRef value;
  772. POP_F64(value);
  773. if (!(value =
  774. LLVMBuildBitCast(comp_ctx->builder, value, I64_TYPE, "i64"))) {
  775. aot_set_last_error("llvm build fp to si failed.");
  776. return false;
  777. }
  778. PUSH_I64(value);
  779. return true;
  780. fail:
  781. return false;
  782. }
  783. bool
  784. aot_compile_op_i32_reinterpret_f32(AOTCompContext *comp_ctx,
  785. AOTFuncContext *func_ctx)
  786. {
  787. LLVMValueRef value;
  788. POP_F32(value);
  789. if (!(value =
  790. LLVMBuildBitCast(comp_ctx->builder, value, I32_TYPE, "i32"))) {
  791. aot_set_last_error("llvm build fp to si failed.");
  792. return false;
  793. }
  794. PUSH_I32(value);
  795. return true;
  796. fail:
  797. return false;
  798. }
  799. bool
  800. aot_compile_op_f64_reinterpret_i64(AOTCompContext *comp_ctx,
  801. AOTFuncContext *func_ctx)
  802. {
  803. LLVMValueRef value;
  804. POP_I64(value);
  805. if (!(value =
  806. LLVMBuildBitCast(comp_ctx->builder, value, F64_TYPE, "f64"))) {
  807. aot_set_last_error("llvm build si to fp failed.");
  808. return false;
  809. }
  810. PUSH_F64(value);
  811. return true;
  812. fail:
  813. return false;
  814. }
  815. bool
  816. aot_compile_op_f32_reinterpret_i32(AOTCompContext *comp_ctx,
  817. AOTFuncContext *func_ctx)
  818. {
  819. LLVMValueRef value;
  820. POP_I32(value);
  821. if (!(value =
  822. LLVMBuildBitCast(comp_ctx->builder, value, F32_TYPE, "f32"))) {
  823. aot_set_last_error("llvm build si to fp failed.");
  824. return false;
  825. }
  826. PUSH_F32(value);
  827. return true;
  828. fail:
  829. return false;
  830. }