/* * Copyright (C) 2019 Intel Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ #include "aot_emit_conversion.h" #include "aot_emit_exception.h" #include "aot_emit_numberic.h" #include "../aot/aot_intrinsic.h" #include "../aot/aot_runtime.h" static LLVMValueRef call_fcmp_intrinsic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, enum AOTFloatCond cond, LLVMRealPredicate op, LLVMValueRef lhs, LLVMValueRef rhs, LLVMTypeRef src_type, const char *name) { LLVMValueRef res = NULL; if (comp_ctx->disable_llvm_intrinsics && aot_intrinsic_check_capability( comp_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp")) { LLVMTypeRef param_types[3]; LLVMValueRef opcond = LLVMConstInt(I32_TYPE, cond, true); param_types[0] = I32_TYPE; param_types[1] = src_type; param_types[2] = src_type; res = aot_call_llvm_intrinsic( comp_ctx, func_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp", I32_TYPE, param_types, 3, opcond, lhs, rhs); if (!res) { goto fail; } res = LLVMBuildIntCast(comp_ctx->builder, res, INT1_TYPE, "bit_cast"); } else { res = LLVMBuildFCmp(comp_ctx->builder, op, lhs, rhs, name); } fail: return res; } static bool trunc_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMValueRef operand, LLVMTypeRef src_type, LLVMTypeRef dest_type, LLVMValueRef min_value, LLVMValueRef max_value, char *name, bool sign) { LLVMBasicBlockRef check_nan_succ, check_overflow_succ; LLVMValueRef is_less, is_greater, res; res = call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_UNO, LLVMRealUNO, operand, operand, src_type, "fcmp_is_nan"); if (!res) { aot_set_last_error("llvm build fcmp failed."); goto fail; } if (!(check_nan_succ = LLVMAppendBasicBlockInContext( comp_ctx->context, func_ctx->func, "check_nan_succ"))) { aot_set_last_error("llvm add basic block failed."); goto fail; } LLVMMoveBasicBlockAfter(check_nan_succ, LLVMGetInsertBlock(comp_ctx->builder)); if (!(aot_emit_exception(comp_ctx, func_ctx, EXCE_INVALID_CONVERSION_TO_INTEGER, true, res, check_nan_succ))) goto fail; is_less = call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_LE, LLVMRealOLE, operand, min_value, src_type, "fcmp_min_value"); if (!is_less) { aot_set_last_error("llvm build fcmp failed."); goto fail; } is_greater = call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_GE, LLVMRealOGE, operand, max_value, src_type, "fcmp_min_value"); if (!is_greater) { aot_set_last_error("llvm build fcmp failed."); goto fail; } if (!(res = LLVMBuildOr(comp_ctx->builder, is_less, is_greater, "is_overflow"))) { aot_set_last_error("llvm build logic and failed."); goto fail; } /* Check if float value out of range */ if (!(check_overflow_succ = LLVMAppendBasicBlockInContext( comp_ctx->context, func_ctx->func, "check_overflow_succ"))) { aot_set_last_error("llvm add basic block failed."); goto fail; } LLVMMoveBasicBlockAfter(check_overflow_succ, LLVMGetInsertBlock(comp_ctx->builder)); if (!(aot_emit_exception(comp_ctx, func_ctx, EXCE_INTEGER_OVERFLOW, true, res, check_overflow_succ))) goto fail; if (comp_ctx->disable_llvm_intrinsics && aot_intrinsic_check_capability(comp_ctx, name)) { LLVMTypeRef param_types[1]; param_types[0] = src_type; res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, name, dest_type, param_types, 1, operand); } else { if (sign) res = LLVMBuildFPToSI(comp_ctx->builder, operand, dest_type, name); else res = LLVMBuildFPToUI(comp_ctx->builder, operand, dest_type, name); } if (!res) { aot_set_last_error("llvm build conversion failed."); return false; } if (dest_type == I32_TYPE) PUSH_I32(res); else if (dest_type == I64_TYPE) PUSH_I64(res); return true; fail: return false; } #define ADD_BASIC_BLOCK(block, name) \ do { \ if (!(block = LLVMAppendBasicBlockInContext(comp_ctx->context, \ func_ctx->func, name))) { \ aot_set_last_error("llvm add basic block failed."); \ goto fail; \ } \ \ LLVMMoveBasicBlockAfter(block, LLVMGetInsertBlock(comp_ctx->builder)); \ } while (0) static bool trunc_sat_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMValueRef operand, LLVMTypeRef src_type, LLVMTypeRef dest_type, LLVMValueRef min_value, LLVMValueRef max_value, char *name, bool sign) { LLVMBasicBlockRef check_nan_succ, check_less_succ, check_greater_succ; LLVMBasicBlockRef is_nan_block, is_less_block, is_greater_block, res_block; LLVMValueRef is_less, is_greater, res, phi; LLVMValueRef zero = (dest_type == I32_TYPE) ? I32_ZERO : I64_ZERO; LLVMValueRef vmin, vmax; if (!(res = call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_UNO, LLVMRealUNO, operand, operand, src_type, "fcmp_is_nan"))) { aot_set_last_error("llvm build fcmp failed."); goto fail; } ADD_BASIC_BLOCK(check_nan_succ, "check_nan_succ"); ADD_BASIC_BLOCK(is_nan_block, "is_nan_block"); ADD_BASIC_BLOCK(check_less_succ, "check_less_succ"); ADD_BASIC_BLOCK(is_less_block, "is_less_block"); ADD_BASIC_BLOCK(check_greater_succ, "check_greater_succ"); ADD_BASIC_BLOCK(is_greater_block, "is_greater_block"); ADD_BASIC_BLOCK(res_block, "res_block"); if (!LLVMBuildCondBr(comp_ctx->builder, res, is_nan_block, check_nan_succ)) { aot_set_last_error("llvm build cond br failed."); goto fail; } /* Start to translate is_nan block */ LLVMPositionBuilderAtEnd(comp_ctx->builder, is_nan_block); if (!LLVMBuildBr(comp_ctx->builder, res_block)) { aot_set_last_error("llvm build br failed."); goto fail; } /* Start to translate check_nan_succ block */ LLVMPositionBuilderAtEnd(comp_ctx->builder, check_nan_succ); if (!(is_less = call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_LE, LLVMRealOLE, operand, min_value, src_type, "fcmp_min_value"))) { aot_set_last_error("llvm build fcmp failed."); goto fail; } if (!LLVMBuildCondBr(comp_ctx->builder, is_less, is_less_block, check_less_succ)) { aot_set_last_error("llvm build cond br failed."); goto fail; } /* Start to translate is_less block */ LLVMPositionBuilderAtEnd(comp_ctx->builder, is_less_block); if (!LLVMBuildBr(comp_ctx->builder, res_block)) { aot_set_last_error("llvm build br failed."); goto fail; } /* Start to translate check_less_succ block */ LLVMPositionBuilderAtEnd(comp_ctx->builder, check_less_succ); if (!(is_greater = call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_GE, LLVMRealOGE, operand, max_value, src_type, "fcmp_max_value"))) { aot_set_last_error("llvm build fcmp failed."); goto fail; } if (!LLVMBuildCondBr(comp_ctx->builder, is_greater, is_greater_block, check_greater_succ)) { aot_set_last_error("llvm build cond br failed."); goto fail; } /* Start to translate is_greater block */ LLVMPositionBuilderAtEnd(comp_ctx->builder, is_greater_block); if (!LLVMBuildBr(comp_ctx->builder, res_block)) { aot_set_last_error("llvm build br failed."); goto fail; } /* Start to translate check_greater_succ block */ LLVMPositionBuilderAtEnd(comp_ctx->builder, check_greater_succ); if (comp_ctx->disable_llvm_intrinsics && aot_intrinsic_check_capability(comp_ctx, name)) { LLVMTypeRef param_types[1]; param_types[0] = src_type; res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, name, dest_type, param_types, 1, operand); } else { char intrinsic[128]; /* Integer width is always 32 or 64 here. */ snprintf(intrinsic, sizeof(intrinsic), "i%d_trunc_f%d_%c", LLVMGetIntTypeWidth(dest_type), LLVMGetTypeKind(src_type) == LLVMFloatTypeKind ? 32 : 64, sign ? 's' : 'u'); if (comp_ctx->disable_llvm_intrinsics && aot_intrinsic_check_capability(comp_ctx, intrinsic)) { res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic, dest_type, &src_type, 1, operand); } else { if (sign) { res = LLVMBuildFPToSI(comp_ctx->builder, operand, dest_type, name); } else { res = LLVMBuildFPToUI(comp_ctx->builder, operand, dest_type, name); } } } if (!res) { aot_set_last_error("llvm build conversion failed."); return false; } if (!LLVMBuildBr(comp_ctx->builder, res_block)) { aot_set_last_error("llvm build br failed."); goto fail; } /* Start to translate res_block */ LLVMPositionBuilderAtEnd(comp_ctx->builder, res_block); /* Create result phi */ if (!(phi = LLVMBuildPhi(comp_ctx->builder, dest_type, "trunc_sat_result_phi"))) { aot_set_last_error("llvm build phi failed."); return false; } /* Add phi incoming values */ if (dest_type == I32_TYPE) { if (sign) { vmin = I32_CONST(INT32_MIN); vmax = I32_CONST(INT32_MAX); } else { vmin = I32_CONST(0); vmax = I32_CONST(UINT32_MAX); } } else if (dest_type == I64_TYPE) { if (sign) { vmin = I64_CONST(INT64_MIN); vmax = I64_CONST(INT64_MAX); } else { vmin = I64_CONST(0); vmax = I64_CONST(UINT64_MAX); } } LLVMAddIncoming(phi, &zero, &is_nan_block, 1); LLVMAddIncoming(phi, &vmin, &is_less_block, 1); LLVMAddIncoming(phi, &vmax, &is_greater_block, 1); LLVMAddIncoming(phi, &res, &check_greater_succ, 1); if (dest_type == I32_TYPE) PUSH_I32(phi); else if (dest_type == I64_TYPE) PUSH_I64(phi); return true; fail: return false; } bool aot_compile_op_i32_wrap_i64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { LLVMValueRef value, res; POP_I64(value); if (!(res = LLVMBuildTrunc(comp_ctx->builder, value, I32_TYPE, "i32_wrap_i64"))) { aot_set_last_error("llvm build conversion failed."); return false; } PUSH_I32(res); return true; fail: return false; } bool aot_compile_op_i32_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool sign, bool saturating) { LLVMValueRef value; LLVMValueRef min_value, max_value; POP_F32(value); if (!comp_ctx->is_indirect_mode) { if (sign) { min_value = F32_CONST(-2147483904.0f); max_value = F32_CONST(2147483648.0f); } else { min_value = F32_CONST(-1.0f); max_value = F32_CONST(4294967296.0f); } } else { WASMValue wasm_value; if (sign) { wasm_value.f32 = -2147483904.0f; min_value = aot_load_const_from_table( comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32); wasm_value.f32 = 2147483648.0f; max_value = aot_load_const_from_table( comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32); } else { wasm_value.f32 = -1.0f; min_value = aot_load_const_from_table( comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32); wasm_value.f32 = 4294967296.0f; max_value = aot_load_const_from_table( comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32); } } CHECK_LLVM_CONST(min_value); CHECK_LLVM_CONST(max_value); if (!saturating) return trunc_float_to_int( comp_ctx, func_ctx, value, F32_TYPE, I32_TYPE, min_value, max_value, sign ? "i32_trunc_f32_s" : "i32_trunc_f32_u", sign); else return trunc_sat_float_to_int( comp_ctx, func_ctx, value, F32_TYPE, I32_TYPE, min_value, max_value, sign ? "i32_trunc_sat_f32_s" : "i32_trunc_sat_f32_u", sign); fail: return false; } bool aot_compile_op_i32_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool sign, bool saturating) { LLVMValueRef value; LLVMValueRef min_value, max_value; POP_F64(value); if (!comp_ctx->is_indirect_mode) { if (sign) { min_value = F64_CONST(-2147483649.0); max_value = F64_CONST(2147483648.0); } else { min_value = F64_CONST(-1.0); max_value = F64_CONST(4294967296.0); } } else { WASMValue wasm_value; if (sign) { wasm_value.f64 = -2147483649.0; min_value = aot_load_const_from_table( comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64); wasm_value.f64 = 2147483648.0; max_value = aot_load_const_from_table( comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64); } else { wasm_value.f64 = -1.0; min_value = aot_load_const_from_table( comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64); wasm_value.f64 = 4294967296.0; max_value = aot_load_const_from_table( comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64); } } CHECK_LLVM_CONST(min_value); CHECK_LLVM_CONST(max_value); if (!saturating) return trunc_float_to_int( comp_ctx, func_ctx, value, F64_TYPE, I32_TYPE, min_value, max_value, sign ? "i32_trunc_f64_s" : "i32_trunc_f64_u", sign); else return trunc_sat_float_to_int( comp_ctx, func_ctx, value, F64_TYPE, I32_TYPE, min_value, max_value, sign ? "i32_trunc_sat_f64_s" : "i32_trunc_sat_f64_u", sign); fail: return false; } bool aot_compile_op_i64_extend_i32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool sign) { LLVMValueRef value, res; POP_I32(value); if (sign) res = LLVMBuildSExt(comp_ctx->builder, value, I64_TYPE, "i64_extend_i32_s"); else res = LLVMBuildZExt(comp_ctx->builder, value, I64_TYPE, "i64_extend_i32_u"); if (!res) { aot_set_last_error("llvm build conversion failed."); return false; } PUSH_I64(res); return true; fail: return false; } bool aot_compile_op_i64_extend_i64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, int8 bitwidth) { LLVMValueRef value, res, cast_value = NULL; POP_I64(value); if (bitwidth == 8) { cast_value = LLVMBuildIntCast2(comp_ctx->builder, value, INT8_TYPE, true, "i8_intcast_i64"); } else if (bitwidth == 16) { cast_value = LLVMBuildIntCast2(comp_ctx->builder, value, INT16_TYPE, true, "i16_intcast_i64"); } else if (bitwidth == 32) { cast_value = LLVMBuildIntCast2(comp_ctx->builder, value, I32_TYPE, true, "i32_intcast_i64"); } if (!cast_value) { aot_set_last_error("llvm build conversion failed."); return false; } res = LLVMBuildSExt(comp_ctx->builder, cast_value, I64_TYPE, "i64_extend_i64_s"); if (!res) { aot_set_last_error("llvm build conversion failed."); return false; } PUSH_I64(res); return true; fail: return false; } bool aot_compile_op_i32_extend_i32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, int8 bitwidth) { LLVMValueRef value, res, cast_value = NULL; POP_I32(value); if (bitwidth == 8) { cast_value = LLVMBuildIntCast2(comp_ctx->builder, value, INT8_TYPE, true, "i8_intcast_i32"); } else if (bitwidth == 16) { cast_value = LLVMBuildIntCast2(comp_ctx->builder, value, INT16_TYPE, true, "i16_intcast_i32"); } if (!cast_value) { aot_set_last_error("llvm build conversion failed."); return false; } res = LLVMBuildSExt(comp_ctx->builder, cast_value, I32_TYPE, "i32_extend_i32_s"); if (!res) { aot_set_last_error("llvm build conversion failed."); return false; } PUSH_I32(res); return true; fail: return false; } bool aot_compile_op_i64_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool sign, bool saturating) { LLVMValueRef value; LLVMValueRef min_value, max_value; POP_F32(value); if (!comp_ctx->is_indirect_mode) { if (sign) { min_value = F32_CONST(-9223373136366403584.0f); max_value = F32_CONST(9223372036854775808.0f); } else { min_value = F32_CONST(-1.0f); max_value = F32_CONST(18446744073709551616.0f); } } else { WASMValue wasm_value; if (sign) { wasm_value.f32 = -9223373136366403584.0f; min_value = aot_load_const_from_table( comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32); wasm_value.f32 = 9223372036854775808.0f; max_value = aot_load_const_from_table( comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32); } else { wasm_value.f32 = -1.0f; min_value = aot_load_const_from_table( comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32); wasm_value.f32 = 18446744073709551616.0f; max_value = aot_load_const_from_table( comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F32); } } CHECK_LLVM_CONST(min_value); CHECK_LLVM_CONST(max_value); if (!saturating) return trunc_float_to_int( comp_ctx, func_ctx, value, F32_TYPE, I64_TYPE, min_value, max_value, sign ? "i64_trunc_f32_s" : "i64_trunc_f32_u", sign); else return trunc_sat_float_to_int( comp_ctx, func_ctx, value, F32_TYPE, I64_TYPE, min_value, max_value, sign ? "i64_trunc_sat_f32_s" : "i64_trunc_sat_f32_u", sign); fail: return false; } bool aot_compile_op_i64_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool sign, bool saturating) { LLVMValueRef value; LLVMValueRef min_value, max_value; POP_F64(value); if (!comp_ctx->is_indirect_mode) { if (sign) { min_value = F64_CONST(-9223372036854777856.0); max_value = F64_CONST(9223372036854775808.0); } else { min_value = F64_CONST(-1.0); max_value = F64_CONST(18446744073709551616.0); } } else { WASMValue wasm_value; if (sign) { wasm_value.f64 = -9223372036854777856.0; min_value = aot_load_const_from_table( comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64); wasm_value.f64 = 9223372036854775808.0; max_value = aot_load_const_from_table( comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64); } else { wasm_value.f64 = -1.0; min_value = aot_load_const_from_table( comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64); wasm_value.f64 = 18446744073709551616.0; max_value = aot_load_const_from_table( comp_ctx, func_ctx->native_symbol, &wasm_value, VALUE_TYPE_F64); } } CHECK_LLVM_CONST(min_value); CHECK_LLVM_CONST(max_value); if (!saturating) return trunc_float_to_int( comp_ctx, func_ctx, value, F64_TYPE, I64_TYPE, min_value, max_value, sign ? "i64_trunc_f64_s" : "i64_trunc_f64_u", sign); else return trunc_sat_float_to_int( comp_ctx, func_ctx, value, F64_TYPE, I64_TYPE, min_value, max_value, sign ? "i64_trunc_sat_f64_s" : "i64_trunc_sat_f64_u", sign); fail: return false; } bool aot_compile_op_f32_convert_i32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool sign) { LLVMValueRef value, res; POP_I32(value); if (comp_ctx->disable_llvm_intrinsics && aot_intrinsic_check_capability( comp_ctx, sign ? "f32_convert_i32_s" : "f32_convert_i32_u")) { LLVMTypeRef param_types[1]; param_types[0] = I32_TYPE; res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, sign ? "f32_convert_i32_s" : "f32_convert_i32_u", F32_TYPE, param_types, 1, value); } else { if (sign) res = LLVMBuildSIToFP(comp_ctx->builder, value, F32_TYPE, "f32_convert_i32_s"); else res = LLVMBuildUIToFP(comp_ctx->builder, value, F32_TYPE, "f32_convert_i32_u"); } if (!res) { aot_set_last_error("llvm build conversion failed."); return false; } PUSH_F32(res); return true; fail: return false; } bool aot_compile_op_f32_convert_i64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool sign) { LLVMValueRef value, res; POP_I64(value); if (comp_ctx->disable_llvm_intrinsics && aot_intrinsic_check_capability( comp_ctx, sign ? "f32_convert_i64_s" : "f32_convert_i64_u")) { LLVMTypeRef param_types[1]; param_types[0] = I64_TYPE; res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, sign ? "f32_convert_i64_s" : "f32_convert_i64_u", F32_TYPE, param_types, 1, value); } else { if (sign) res = LLVMBuildSIToFP(comp_ctx->builder, value, F32_TYPE, "f32_convert_i64_s"); else res = LLVMBuildUIToFP(comp_ctx->builder, value, F32_TYPE, "f32_convert_i64_u"); } if (!res) { aot_set_last_error("llvm build conversion failed."); return false; } PUSH_F32(res); return true; fail: return false; } bool aot_compile_op_f32_demote_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { LLVMValueRef value, res; POP_F64(value); if (comp_ctx->disable_llvm_intrinsics && aot_intrinsic_check_capability(comp_ctx, "f32_demote_f64")) { LLVMTypeRef param_types[1]; param_types[0] = F64_TYPE; res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, "f32_demote_f64", F32_TYPE, param_types, 1, value); } else { res = LLVMBuildFPTrunc(comp_ctx->builder, value, F32_TYPE, "f32_demote_f64"); } if (!res) { aot_set_last_error("llvm build conversion failed."); return false; } PUSH_F32(res); return true; fail: return false; } bool aot_compile_op_f64_convert_i32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool sign) { LLVMValueRef value, res; POP_I32(value); if (comp_ctx->disable_llvm_intrinsics && aot_intrinsic_check_capability( comp_ctx, sign ? "f64_convert_i32_s" : "f64_convert_i32_u")) { LLVMTypeRef param_types[1]; param_types[0] = I32_TYPE; res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, sign ? "f64_convert_i32_s" : "f64_convert_i32_u", F64_TYPE, param_types, 1, value); } else { if (sign) res = LLVMBuildSIToFP(comp_ctx->builder, value, F64_TYPE, "f64_convert_i32_s"); else res = LLVMBuildUIToFP(comp_ctx->builder, value, F64_TYPE, "f64_convert_i32_u"); } if (!res) { aot_set_last_error("llvm build conversion failed."); return false; } PUSH_F64(res); return true; fail: return false; } bool aot_compile_op_f64_convert_i64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool sign) { LLVMValueRef value, res; POP_I64(value); if (comp_ctx->disable_llvm_intrinsics && aot_intrinsic_check_capability( comp_ctx, sign ? "f64_convert_i64_s" : "f64_convert_i64_u")) { LLVMTypeRef param_types[1]; param_types[0] = I64_TYPE; res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, sign ? "f64_convert_i64_s" : "f64_convert_i64_u", F64_TYPE, param_types, 1, value); } else { if (sign) res = LLVMBuildSIToFP(comp_ctx->builder, value, F64_TYPE, "f64_convert_i64_s"); else res = LLVMBuildUIToFP(comp_ctx->builder, value, F64_TYPE, "f64_convert_i64_u"); } if (!res) { aot_set_last_error("llvm build conversion failed."); return false; } PUSH_F64(res); return true; fail: return false; } bool aot_compile_op_f64_promote_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { LLVMValueRef value, res; POP_F32(value); if (comp_ctx->disable_llvm_intrinsics && aot_intrinsic_check_capability(comp_ctx, "f64_promote_f32")) { LLVMTypeRef param_types[1]; param_types[0] = F32_TYPE; res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, "f64_promote_f32", F64_TYPE, param_types, 1, value); } else { res = LLVMBuildFPExt(comp_ctx->builder, value, F64_TYPE, "f64_promote_f32"); } if (!res) { aot_set_last_error("llvm build conversion failed."); return false; } PUSH_F64(res); /* Avoid the promote being optimized away */ PUSH_F64(F64_CONST(1.0)); return aot_compile_op_f64_arithmetic(comp_ctx, func_ctx, FLOAT_MUL); fail: return false; } bool aot_compile_op_i64_reinterpret_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { LLVMValueRef value; POP_F64(value); if (!(value = LLVMBuildBitCast(comp_ctx->builder, value, I64_TYPE, "i64"))) { aot_set_last_error("llvm build fp to si failed."); return false; } PUSH_I64(value); return true; fail: return false; } bool aot_compile_op_i32_reinterpret_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { LLVMValueRef value; POP_F32(value); if (!(value = LLVMBuildBitCast(comp_ctx->builder, value, I32_TYPE, "i32"))) { aot_set_last_error("llvm build fp to si failed."); return false; } PUSH_I32(value); return true; fail: return false; } bool aot_compile_op_f64_reinterpret_i64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { LLVMValueRef value; POP_I64(value); if (!(value = LLVMBuildBitCast(comp_ctx->builder, value, F64_TYPE, "f64"))) { aot_set_last_error("llvm build si to fp failed."); return false; } PUSH_F64(value); return true; fail: return false; } bool aot_compile_op_f32_reinterpret_i32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { LLVMValueRef value; POP_I32(value); if (!(value = LLVMBuildBitCast(comp_ctx->builder, value, F32_TYPE, "f32"))) { aot_set_last_error("llvm build si to fp failed."); return false; } PUSH_F32(value); return true; fail: return false; }