diff --git a/core/iwasm/aot/aot_intrinsic.c b/core/iwasm/aot/aot_intrinsic.c index 54669cbde..7ac4b4743 100644 --- a/core/iwasm/aot/aot_intrinsic.c +++ b/core/iwasm/aot/aot_intrinsic.c @@ -72,6 +72,8 @@ static const aot_intrinsic g_intrinsic_mapping[] = { { "i64.div_u", "aot_intrinsic_i64_div_u", AOT_INTRINSIC_FLAG_I64_DIV_U}, { "i64.rem_s", "aot_intrinsic_i64_rem_s", AOT_INTRINSIC_FLAG_I64_REM_S}, { "i64.rem_u", "aot_intrinsic_i64_rem_u", AOT_INTRINSIC_FLAG_I64_REM_U}, + { "i64.or", "aot_intrinsic_i64_bit_or", AOT_INTRINSIC_FLAG_I64_BIT_OR}, + { "i64.and", "aot_intrinsic_i64_bit_and", AOT_INTRINSIC_FLAG_I64_BIT_AND}, }; /* clang-format on */ @@ -524,6 +526,18 @@ aot_intrinsic_i64_rem_u(uint64 l, uint64 r) return l % r; } +uint64 +aot_intrinsic_i64_bit_or(uint64 l, uint64 r) +{ + return l | r; +} + +uint64 +aot_intrinsic_i64_bit_and(uint64 l, uint64 r) +{ + return l & r; +} + const char * aot_intrinsic_get_symbol(const char *llvm_intrinsic) { @@ -558,6 +572,8 @@ add_i64_common_intrinsics(AOTCompContext *comp_ctx) add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_DIV_U); add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_REM_S); add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_REM_U); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_BIT_OR); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_BIT_AND); } static void diff --git a/core/iwasm/aot/aot_intrinsic.h b/core/iwasm/aot/aot_intrinsic.h index 8962445b7..ae66037f2 100644 --- a/core/iwasm/aot/aot_intrinsic.h +++ b/core/iwasm/aot/aot_intrinsic.h @@ -93,6 +93,8 @@ extern "C" { #define AOT_INTRINSIC_FLAG_I64_DIV_U AOT_INTRINSIC_FLAG(1, 29) #define AOT_INTRINSIC_FLAG_I64_REM_S AOT_INTRINSIC_FLAG(1, 30) #define AOT_INTRINSIC_FLAG_I64_REM_U AOT_INTRINSIC_FLAG(1, 31) +#define AOT_INTRINSIC_FLAG_I64_BIT_OR AOT_INTRINSIC_FLAG(1, 32) +#define AOT_INTRINSIC_FLAG_I64_BIT_AND AOT_INTRINSIC_FLAG(1, 33) /* clang-format on */ @@ -267,6 +269,12 @@ aot_intrinsic_i64_rem_s(int64 l, int64 r); uint64 aot_intrinsic_i64_rem_u(uint64 l, uint64 r); +uint64 +aot_intrinsic_i64_bit_or(uint64 l, uint64 r); + +uint64 +aot_intrinsic_i64_bit_and(uint64 l, uint64 r); + const char * aot_intrinsic_get_symbol(const char *llvm_intrinsic); diff --git a/core/iwasm/aot/aot_reloc.h b/core/iwasm/aot/aot_reloc.h index 34a37a7be..1ae52302c 100644 --- a/core/iwasm/aot/aot_reloc.h +++ b/core/iwasm/aot/aot_reloc.h @@ -112,6 +112,8 @@ typedef struct { REG_SYM(aot_intrinsic_i64_div_u), \ REG_SYM(aot_intrinsic_i64_rem_s), \ REG_SYM(aot_intrinsic_i64_rem_u), \ + REG_SYM(aot_intrinsic_i64_bit_or), \ + REG_SYM(aot_intrinsic_i64_bit_and), \ REG_SYM(aot_intrinsic_i32_div_u), \ #define REG_COMMON_SYMBOLS \ diff --git a/core/iwasm/compilation/aot_emit_numberic.c b/core/iwasm/compilation/aot_emit_numberic.c index 61259c931..283bce9dc 100644 --- a/core/iwasm/compilation/aot_emit_numberic.c +++ b/core/iwasm/compilation/aot_emit_numberic.c @@ -234,15 +234,49 @@ compile_op_float_min_max(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, nan = LLVMConstRealOfString(ret_type, "NaN"); char *intrinsic = is_min ? (is_f32 ? "llvm.minnum.f32" : "llvm.minnum.f64") : (is_f32 ? "llvm.maxnum.f32" : "llvm.maxnum.f64"); + bool is_i32 = is_f32; CHECK_LLVM_CONST(nan); param_types[0] = param_types[1] = ret_type; - if (!(is_nan = LLVMBuildFCmp(comp_ctx->builder, LLVMRealUNO, left, right, - "is_nan")) - || !(is_eq = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOEQ, left, right, - "is_eq"))) { + if (comp_ctx->disable_llvm_intrinsics + && aot_intrinsic_check_capability(comp_ctx, + is_f32 ? "f32_cmp" : "f64_cmp")) { + LLVMTypeRef param_types[3]; + LLVMValueRef opcond = LLVMConstInt(I32_TYPE, FLOAT_UNO, true); + param_types[0] = I32_TYPE; + param_types[1] = is_f32 ? F32_TYPE : F64_TYPE; + param_types[2] = param_types[1]; + is_nan = aot_call_llvm_intrinsic( + comp_ctx, func_ctx, is_f32 ? "f32_cmp" : "f64_cmp", I32_TYPE, + param_types, 3, opcond, left, right); + + opcond = LLVMConstInt(I32_TYPE, FLOAT_EQ, true); + is_eq = aot_call_llvm_intrinsic( + comp_ctx, func_ctx, is_f32 ? "f32_cmp" : "f64_cmp", I32_TYPE, + param_types, 3, opcond, left, right); + + if (!is_nan || !is_eq) { + return NULL; + } + + if (!(is_nan = LLVMBuildIntCast(comp_ctx->builder, is_nan, INT1_TYPE, + "bit_cast_is_nan"))) { + aot_set_last_error("llvm build is_nan bit cast fail."); + return NULL; + } + + if (!(is_eq = LLVMBuildIntCast(comp_ctx->builder, is_eq, INT1_TYPE, + "bit_cast_is_eq"))) { + aot_set_last_error("llvm build is_eq bit cast fail."); + return NULL; + } + } + else if (!(is_nan = LLVMBuildFCmp(comp_ctx->builder, LLVMRealUNO, left, + right, "is_nan")) + || !(is_eq = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOEQ, left, + right, "is_eq"))) { aot_set_last_error("llvm build fcmp fail."); return NULL; } @@ -258,9 +292,11 @@ compile_op_float_min_max(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } if (is_min) - LLVM_BUILD_OP(Or, left_int, right_int, tmp, "tmp_int", NULL); + LLVM_BUILD_OP_OR_INTRINSIC(Or, left_int, right_int, tmp, "i64.or", + "tmp_int", false); else - LLVM_BUILD_OP(And, left_int, right_int, tmp, "tmp_int", NULL); + LLVM_BUILD_OP_OR_INTRINSIC(And, left_int, right_int, tmp, "i64.and", + "tmp_int", false); if (!(tmp = LLVMBuildBitCast(comp_ctx->builder, tmp, ret_type, "tmp"))) { aot_set_last_error("llvm build bitcast fail.");