Jelajahi Sumber

aot: add new u64 intrinsics (#4168)

Raul Hernandez 9 bulan lalu
induk
melakukan
8245aefc77

+ 32 - 0
core/iwasm/aot/aot_intrinsic.c

@@ -485,6 +485,30 @@ aot_intrinsic_i64_bit_and(uint64 l, uint64 r)
     return l & r;
 }
 
+uint64
+aot_intrinsic_i64_mul(uint64 l, uint64 r)
+{
+    return l * r;
+}
+
+uint64
+aot_intrinsic_i64_shl(uint64 l, uint64 r)
+{
+    return l << r;
+}
+
+uint64
+aot_intrinsic_i64_shr_s(uint64 l, uint64 r)
+{
+    return (int64)l >> r;
+}
+
+uint64
+aot_intrinsic_i64_shr_u(uint64 l, uint64 r)
+{
+    return l >> r;
+}
+
 #if WASM_ENABLE_WAMR_COMPILER != 0 || WASM_ENABLE_JIT != 0
 
 typedef struct {
@@ -561,6 +585,10 @@ static const aot_intrinsic g_intrinsic_mapping[] = {
     { "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},
+    { "i64.mul", "aot_intrinsic_i64_mul", AOT_INTRINSIC_FLAG_I64_MUL},
+    { "i64.shl", "aot_intrinsic_i64_shl", AOT_INTRINSIC_FLAG_I64_SHL},
+    { "i64.shr_s", "aot_intrinsic_i64_shr_s", AOT_INTRINSIC_FLAG_I64_SHR_S},
+    { "i64.shr_u", "aot_intrinsic_i64_shr_u", AOT_INTRINSIC_FLAG_I64_SHR_U},
 };
 /* clang-format on */
 
@@ -601,6 +629,10 @@ add_i64_common_intrinsics(AOTCompContext *comp_ctx)
     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);
+    add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_MUL);
+    add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_SHL);
+    add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_SHR_S);
+    add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_SHR_U);
 }
 
 static void

+ 16 - 0
core/iwasm/aot/aot_intrinsic.h

@@ -98,6 +98,10 @@ extern "C" {
 #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)
+#define AOT_INTRINSIC_FLAG_I64_MUL      AOT_INTRINSIC_FLAG(1, 34)
+#define AOT_INTRINSIC_FLAG_I64_SHL      AOT_INTRINSIC_FLAG(1, 35)
+#define AOT_INTRINSIC_FLAG_I64_SHR_S    AOT_INTRINSIC_FLAG(1, 36)
+#define AOT_INTRINSIC_FLAG_I64_SHR_U    AOT_INTRINSIC_FLAG(1, 37)
 
 /* clang-format on */
 
@@ -287,6 +291,18 @@ aot_intrinsic_i64_bit_or(uint64 l, uint64 r);
 uint64
 aot_intrinsic_i64_bit_and(uint64 l, uint64 r);
 
+uint64
+aot_intrinsic_i64_mul(uint64 l, uint64 r);
+
+uint64
+aot_intrinsic_i64_shl(uint64 l, uint64 r);
+
+uint64
+aot_intrinsic_i64_shr_s(uint64 l, uint64 r);
+
+uint64
+aot_intrinsic_i64_shr_u(uint64 l, uint64 r);
+
 #if WASM_ENABLE_WAMR_COMPILER != 0 || WASM_ENABLE_JIT != 0
 const char *
 aot_intrinsic_get_symbol(const char *llvm_intrinsic);

+ 4 - 0
core/iwasm/aot/aot_reloc.h

@@ -122,6 +122,10 @@ typedef struct {
     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_i64_mul),       \
+    REG_SYM(aot_intrinsic_i64_shl),       \
+    REG_SYM(aot_intrinsic_i64_shr_s),     \
+    REG_SYM(aot_intrinsic_i64_shr_u),     \
     REG_SYM(aot_intrinsic_i32_div_s),     \
     REG_SYM(aot_intrinsic_i32_div_u),     \
     REG_SYM(aot_intrinsic_i32_rem_s),     \

+ 44 - 20
core/iwasm/compilation/aot_emit_numberic.c

@@ -653,15 +653,22 @@ compile_int_sub(AOTCompContext *comp_ctx, LLVMValueRef left, LLVMValueRef right,
 }
 
 static LLVMValueRef
-compile_int_mul(AOTCompContext *comp_ctx, LLVMValueRef left, LLVMValueRef right,
-                bool is_i32)
+compile_int_mul(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                LLVMValueRef left, LLVMValueRef right, bool is_i32)
 {
     /* If one of the operands is 0, just return constant 0 */
     if (IS_CONST_ZERO(left) || IS_CONST_ZERO(right))
         return is_i32 ? I32_ZERO : I64_ZERO;
 
     /* Build mul */
-    return LLVMBuildMul(comp_ctx->builder, left, right, "mul");
+    LLVMTypeRef param_types[2];
+    param_types[1] = param_types[0] = is_i32 ? I32_TYPE : I64_TYPE;
+
+    LLVMValueRef res;
+    LLVM_BUILD_OP_OR_INTRINSIC(Mul, left, right, res,
+                               is_i32 ? "i32.mul" : "i64.mul", "mul", false);
+
+    return res;
 }
 
 static bool
@@ -679,8 +686,9 @@ compile_op_int_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                               "compile int sub fail.");
             return true;
         case INT_MUL:
-            DEF_INT_BINARY_OP(compile_int_mul(comp_ctx, left, right, is_i32),
-                              "compile int mul fail.");
+            DEF_INT_BINARY_OP(
+                compile_int_mul(comp_ctx, func_ctx, left, right, is_i32),
+                "compile int mul fail.");
             return true;
         case INT_DIV_S:
         case INT_DIV_U:
@@ -726,43 +734,57 @@ fail:
 }
 
 static LLVMValueRef
-compile_int_shl(AOTCompContext *comp_ctx, LLVMValueRef left, LLVMValueRef right,
-                bool is_i32)
+compile_int_shl(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                LLVMValueRef left, LLVMValueRef right, bool is_i32)
 {
     LLVMValueRef res;
 
     SHIFT_COUNT_MASK;
 
     /* Build shl */
-    LLVM_BUILD_OP(Shl, left, right, res, "shl", NULL);
+    LLVMTypeRef param_types[2];
+    param_types[1] = param_types[0] = is_i32 ? I32_TYPE : I64_TYPE;
+
+    LLVM_BUILD_OP_OR_INTRINSIC(Shl, left, right, res,
+                               is_i32 ? "i32.shl" : "i64.shl", "shl", false);
 
     return res;
 }
 
 static LLVMValueRef
-compile_int_shr_s(AOTCompContext *comp_ctx, LLVMValueRef left,
-                  LLVMValueRef right, bool is_i32)
+compile_int_shr_s(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                  LLVMValueRef left, LLVMValueRef right, bool is_i32)
 {
     LLVMValueRef res;
 
     SHIFT_COUNT_MASK;
 
     /* Build shl */
-    LLVM_BUILD_OP(AShr, left, right, res, "shr_s", NULL);
+    LLVMTypeRef param_types[2];
+    param_types[1] = param_types[0] = is_i32 ? I32_TYPE : I64_TYPE;
+
+    LLVM_BUILD_OP_OR_INTRINSIC(AShr, left, right, res,
+                               is_i32 ? "i32.shr_s" : "i64.shr_s", "shr_s",
+                               false);
 
     return res;
 }
 
 static LLVMValueRef
-compile_int_shr_u(AOTCompContext *comp_ctx, LLVMValueRef left,
-                  LLVMValueRef right, bool is_i32)
+compile_int_shr_u(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                  LLVMValueRef left, LLVMValueRef right, bool is_i32)
 {
     LLVMValueRef res;
 
     SHIFT_COUNT_MASK;
 
     /* Build shl */
-    LLVM_BUILD_OP(LShr, left, right, res, "shr_u", NULL);
+    LLVMTypeRef param_types[2];
+    param_types[1] = param_types[0] = is_i32 ? I32_TYPE : I64_TYPE;
+
+    LLVM_BUILD_OP_OR_INTRINSIC(LShr, left, right, res,
+                               is_i32 ? "i32.shr_u" : "i64.shr_u", "shr_u",
+                               false);
 
     return res;
 }
@@ -814,16 +836,18 @@ compile_op_int_shift(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 {
     switch (shift_op) {
         case INT_SHL:
-            DEF_INT_BINARY_OP(compile_int_shl(comp_ctx, left, right, is_i32),
-                              NULL);
+            DEF_INT_BINARY_OP(
+                compile_int_shl(comp_ctx, func_ctx, left, right, is_i32), NULL);
             return true;
         case INT_SHR_S:
-            DEF_INT_BINARY_OP(compile_int_shr_s(comp_ctx, left, right, is_i32),
-                              NULL);
+            DEF_INT_BINARY_OP(
+                compile_int_shr_s(comp_ctx, func_ctx, left, right, is_i32),
+                NULL);
             return true;
         case INT_SHR_U:
-            DEF_INT_BINARY_OP(compile_int_shr_u(comp_ctx, left, right, is_i32),
-                              NULL);
+            DEF_INT_BINARY_OP(
+                compile_int_shr_u(comp_ctx, func_ctx, left, right, is_i32),
+                NULL);
             return true;
         case INT_ROTL:
             DEF_INT_BINARY_OP(