From 5be427bfa26ab4a84e7c1a5dbc8b5e7f9ff5ea86 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 16 Dec 2021 21:39:23 +0800 Subject: [PATCH] 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. --- core/iwasm/aot/aot_loader.c | 46 ++++++- core/iwasm/compilation/aot.h | 2 +- core/iwasm/compilation/aot_emit_const.c | 36 ++++- core/iwasm/compilation/aot_emit_conversion.c | 132 ++++++++++++++++--- core/iwasm/compilation/aot_llvm.c | 112 ++++++++++++++-- core/iwasm/compilation/aot_llvm.h | 4 + 6 files changed, 287 insertions(+), 45 deletions(-) diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 5dacebbf..c550a3f9 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/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, diff --git a/core/iwasm/compilation/aot.h b/core/iwasm/compilation/aot.h index bff20791..3254eaf2 100644 --- a/core/iwasm/compilation/aot.h +++ b/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; diff --git a/core/iwasm/compilation/aot_emit_const.c b/core/iwasm/compilation/aot_emit_const.c index c5736ca3..e8ad99e0 100644 --- a/core/iwasm/compilation/aot_emit_const.c +++ b/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; diff --git a/core/iwasm/compilation/aot_emit_conversion.c b/core/iwasm/compilation/aot_emit_conversion.c index 93c5a998..a1171110 100644 --- a/core/iwasm/compilation/aot_emit_conversion.c +++ b/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( diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 796def61..4f8efc0e 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/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; +} diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index dd29cae3..f43df2b3 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/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);