Просмотр исходного кода

xip: Lookup float constants from table to reduce relocations (#894)

Lookup float/double constants from exec_env->native_symbol table
but not construct them with LLVMBuildConst if XIP mode is enabled,
these constants are introduced by f32/f64.const opcodes and some
float/double conversion opcodes, and make wamrc generate some
relocations in text section of AOT XIP file. This patch eliminates such
relocations when "--enable-indirect-mode" is added to wamrc.
Wenyong Huang 4 лет назад
Родитель
Сommit
5be427bfa2

+ 39 - 7
core/iwasm/aot/aot_loader.c

@@ -465,6 +465,12 @@ get_native_symbol_by_name(const char *name)
     return func;
 }
 
+static bool
+str2uint32(const char *buf, uint32 *p_res);
+
+static bool
+str2uint64(const char *buf, uint64 *p_res);
+
 static bool
 load_native_symbol_section(const uint8 *buf, const uint8 *buf_end,
                            AOTModule *module, bool is_load_from_file_buf,
@@ -487,11 +493,39 @@ load_native_symbol_section(const uint8 *buf, const uint8 *buf_end,
 
         for (i = cnt - 1; i >= 0; i--) {
             read_string(p, p_end, symbol);
-            module->native_symbol_list[i] = get_native_symbol_by_name(symbol);
-            if (module->native_symbol_list[i] == NULL) {
-                set_error_buf_v(error_buf, error_buf_size,
-                                "missing native symbol: %s", symbol);
-                goto fail;
+            if (!strncmp(symbol, "f32#", 4)) {
+                uint32 u32;
+                /* Resolve the raw int bits of f32 const */
+                if (!str2uint32(symbol + 4, &u32)) {
+                    set_error_buf_v(error_buf, error_buf_size,
+                                    "resolve symbol %s failed", symbol);
+                    goto fail;
+                }
+                *(uint32 *)(&module->native_symbol_list[i]) = u32;
+            }
+            else if (!strncmp(symbol, "f64#", 4)) {
+                uint64 u64;
+                /* Resolve the raw int bits of f64 const */
+                if (!str2uint64(symbol + 4, &u64)) {
+                    set_error_buf_v(error_buf, error_buf_size,
+                                    "resolve symbol %s failed", symbol);
+                    goto fail;
+                }
+                *(uint64 *)(&module->native_symbol_list[i]) = u64;
+            }
+            else if (!strncmp(symbol, "__ignore", 8)) {
+                /* Padding bytes to make f64 on 8-byte aligned address,
+                   or it is the second 32-bit slot in 32-bit system */
+                continue;
+            }
+            else {
+                module->native_symbol_list[i] =
+                    get_native_symbol_by_name(symbol);
+                if (module->native_symbol_list[i] == NULL) {
+                    set_error_buf_v(error_buf, error_buf_size,
+                                    "missing native symbol: %s", symbol);
+                    goto fail;
+                }
             }
         }
     }
@@ -1711,7 +1745,6 @@ is_literal_relocation(const char *reloc_sec_name)
     return !strcmp(reloc_sec_name, ".rela.literal");
 }
 
-#if defined(BH_PLATFORM_WINDOWS)
 static bool
 str2uint32(const char *buf, uint32 *p_res)
 {
@@ -1757,7 +1790,6 @@ str2uint64(const char *buf, uint64 *p_res)
     *p_res = res;
     return true;
 }
-#endif
 
 static bool
 do_text_relocation(AOTModule *module, AOTRelocationGroup *group,

+ 1 - 1
core/iwasm/compilation/aot.h

@@ -268,7 +268,7 @@ typedef struct AOTCompData {
 
 typedef struct AOTNativeSymbol {
     bh_list_link link;
-    const char *symbol;
+    char symbol[32];
     int32 index;
 } AOTNativeSymbol;
 

+ 30 - 6
core/iwasm/compilation/aot_emit_const.c

@@ -36,9 +36,21 @@ aot_compile_op_f32_const(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     LLVMValueRef alloca, value;
 
     if (!isnan(f32_const)) {
-        value = F32_CONST(f32_const);
-        CHECK_LLVM_CONST(value);
-        PUSH_F32(value);
+        if (!comp_ctx->is_indirect_mode) {
+            value = F32_CONST(f32_const);
+            CHECK_LLVM_CONST(value);
+            PUSH_F32(value);
+        }
+        else {
+            WASMValue wasm_value;
+            memcpy(&wasm_value.f32, &f32_const, sizeof(float32));
+            value = aot_load_const_from_table(comp_ctx, func_ctx->native_symbol,
+                                              &wasm_value, VALUE_TYPE_F32);
+            if (!value) {
+                return false;
+            }
+            PUSH_F32(value);
+        }
     }
     else {
         int32 i32_const;
@@ -77,9 +89,21 @@ aot_compile_op_f64_const(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     LLVMValueRef alloca, value;
 
     if (!isnan(f64_const)) {
-        value = F64_CONST(f64_const);
-        CHECK_LLVM_CONST(value);
-        PUSH_F64(value);
+        if (!comp_ctx->is_indirect_mode) {
+            value = F64_CONST(f64_const);
+            CHECK_LLVM_CONST(value);
+            PUSH_F64(value);
+        }
+        else {
+            WASMValue wasm_value;
+            memcpy(&wasm_value.f64, &f64_const, sizeof(float64));
+            value = aot_load_const_from_table(comp_ctx, func_ctx->native_symbol,
+                                              &wasm_value, VALUE_TYPE_F64);
+            if (!value) {
+                return false;
+            }
+            PUSH_F64(value);
+        }
     }
     else {
         int64 i64_const;

+ 112 - 20
core/iwasm/compilation/aot_emit_conversion.c

@@ -348,14 +348,37 @@ aot_compile_op_i32_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
     POP_F32(value);
 
-    if (sign) {
-        min_value = F32_CONST(-2147483904.0f);
-        max_value = F32_CONST(2147483648.0f);
+    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 {
-        min_value = F32_CONST(-1.0f);
-        max_value = F32_CONST(4294967296.0f);
+        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(
@@ -378,14 +401,37 @@ aot_compile_op_i32_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
     POP_F64(value);
 
-    if (sign) {
-        min_value = F64_CONST(-2147483649.0);
-        max_value = F64_CONST(2147483648.0);
+    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 {
-        min_value = F64_CONST(-1.0);
-        max_value = F64_CONST(4294967296.0);
+        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(
@@ -509,14 +555,37 @@ aot_compile_op_i64_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
     POP_F32(value);
 
-    if (sign) {
-        min_value = F32_CONST(-9223373136366403584.0f);
-        max_value = F32_CONST(9223372036854775808.0f);
+    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 {
-        min_value = F32_CONST(-1.0f);
-        max_value = F32_CONST(18446744073709551616.0f);
+        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(
@@ -539,14 +608,37 @@ aot_compile_op_i64_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
     POP_F64(value);
 
-    if (sign) {
-        min_value = F64_CONST(-9223372036854777856.0);
-        max_value = F64_CONST(9223372036854775808.0);
+    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 {
-        min_value = F64_CONST(-1.0);
-        max_value = F64_CONST(18446744073709551616.0);
+        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(

+ 101 - 11
core/iwasm/compilation/aot_llvm.c

@@ -2004,6 +2004,30 @@ aot_destroy_comp_context(AOTCompContext *comp_ctx)
     wasm_runtime_free(comp_ctx);
 }
 
+static bool
+insert_native_symbol(AOTCompContext *comp_ctx, const char *symbol, int32 idx)
+{
+    AOTNativeSymbol *sym = wasm_runtime_malloc(sizeof(AOTNativeSymbol));
+
+    if (!sym) {
+        aot_set_last_error("alloc native symbol failed.");
+        return false;
+    }
+
+    memset(sym, 0, sizeof(AOTNativeSymbol));
+    bh_assert(strlen(symbol) <= sizeof(sym->symbol));
+    snprintf(sym->symbol, sizeof(sym->symbol), "%s", symbol);
+    sym->index = idx;
+
+    if (BH_LIST_ERROR == bh_list_insert(&comp_ctx->native_symbols, sym)) {
+        wasm_runtime_free(sym);
+        aot_set_last_error("insert native symbol to list failed.");
+        return false;
+    }
+
+    return true;
+}
+
 int32
 aot_get_native_symbol_index(AOTCompContext *comp_ctx, const char *symbol)
 {
@@ -2025,22 +2049,30 @@ aot_get_native_symbol_index(AOTCompContext *comp_ctx, const char *symbol)
     /* Given symbol is not exist in list, then we alloc a new index for it */
 
     if (idx < 0) {
-        sym = wasm_runtime_malloc(sizeof(AOTNativeSymbol));
-
-        if (!sym) {
-            aot_set_last_error("alloc native symbol failed.");
-            return idx;
+        if (comp_ctx->pointer_size == sizeof(uint32)
+            && !strncmp(symbol, "f64#", 4)) {
+            idx = bh_list_length(&comp_ctx->native_symbols);
+            /* Add 4 bytes padding on 32-bit target to make sure that
+               the f64 const is stored on 8-byte aligned address */
+            if ((idx & 1) && !strncmp(comp_ctx->target_arch, "i386", 4)) {
+                if (!insert_native_symbol(comp_ctx, "__ignore", idx)) {
+                    return -1;
+                }
+            }
         }
 
         idx = bh_list_length(&comp_ctx->native_symbols);
-        sym->symbol = symbol;
-        sym->index = idx;
-
-        if (BH_LIST_ERROR == bh_list_insert(&comp_ctx->native_symbols, sym)) {
-            wasm_runtime_free(sym);
-            aot_set_last_error("alloc index for native symbol failed.");
+        if (!insert_native_symbol(comp_ctx, symbol, idx)) {
             return -1;
         }
+
+        if (comp_ctx->pointer_size == sizeof(uint32)
+            && !strncmp(symbol, "f64#", 4)) {
+            /* f64 const occupies 2 pointer slots on 32-bit target */
+            if (!insert_native_symbol(comp_ctx, "__ignore", idx + 1)) {
+                return -1;
+            }
+        }
     }
 
     return idx;
@@ -2445,3 +2477,61 @@ aot_get_func_from_table(const AOTCompContext *comp_ctx, LLVMValueRef base,
 fail:
     return NULL;
 }
+
+LLVMValueRef
+aot_load_const_from_table(AOTCompContext *comp_ctx, LLVMValueRef base,
+                          const WASMValue *value, uint8 value_type)
+{
+    LLVMValueRef const_index, const_addr, const_value;
+    LLVMTypeRef const_ptr_type;
+    char buf[128] = { 0 };
+    int32 index;
+
+    switch (value_type) {
+        case VALUE_TYPE_F32:
+            /* Store the raw int bits of f32 const as a hex string */
+            snprintf(buf, sizeof(buf), "f32#%08X", value->i32);
+            const_ptr_type = F32_PTR_TYPE;
+            break;
+        case VALUE_TYPE_F64:
+            /* Store the raw int bits of f64 const as a hex string */
+            snprintf(buf, sizeof(buf), "f64#%016" PRIx64, value->i64);
+            const_ptr_type = F64_PTR_TYPE;
+            break;
+        default:
+            bh_assert(0);
+            return NULL;
+    }
+
+    /* Load f32/f64 const from exec_env->native_symbol[index] */
+
+    index = aot_get_native_symbol_index(comp_ctx, buf);
+    if (index < 0) {
+        return NULL;
+    }
+
+    if (!(const_index = I32_CONST(index))) {
+        aot_set_last_error("construct const index failed.");
+        return NULL;
+    }
+
+    if (!(const_addr = LLVMBuildInBoundsGEP(
+              comp_ctx->builder, base, &const_index, 1, "const_addr_tmp"))) {
+        aot_set_last_error("get const addr by index failed.");
+        return NULL;
+    }
+
+    if (!(const_addr = LLVMBuildBitCast(comp_ctx->builder, const_addr,
+                                        const_ptr_type, "const_addr"))) {
+        aot_set_last_error("cast const fialed.");
+        return NULL;
+    }
+
+    if (!(const_value =
+              LLVMBuildLoad(comp_ctx->builder, const_addr, "const_value"))) {
+        aot_set_last_error("load const failed.");
+        return NULL;
+    }
+
+    return const_value;
+}

+ 4 - 0
core/iwasm/compilation/aot_llvm.h

@@ -442,6 +442,10 @@ LLVMValueRef
 aot_get_func_from_table(const AOTCompContext *comp_ctx, LLVMValueRef base,
                         LLVMTypeRef func_type, int32 index);
 
+LLVMValueRef
+aot_load_const_from_table(AOTCompContext *comp_ctx, LLVMValueRef base,
+                          const WASMValue *value, uint8 value_type);
+
 bool
 aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str);