Browse Source

Fix missing float cmp for XIP (#1699)

Huang Qi 3 years ago
parent
commit
4b0660cf24

+ 16 - 0
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

+ 8 - 0
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);
 

+ 2 - 0
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                \

+ 42 - 6
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.");