diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 52c6d94afa..a9ecd8fb67 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -778,6 +778,7 @@ message ( " \"Sign-extension Operators\"\n" " \"WebAssembly C and C++ API\"\n" " \"Branch Hinting\"\n" +" \"Compilation Hints\"\n" " Configurable. 0 is OFF. 1 is ON:\n" " \"Bulk Memory Operation\" via WAMR_BUILD_BULK_MEMORY: ${WAMR_BUILD_BULK_MEMORY}\n" " \"Bulk-memory-opt\" via WAMR_BUILD_BULK_MEMORY_OPT: ${WAMR_BUILD_BULK_MEMORY_OPT}\n" diff --git a/core/config.h b/core/config.h index cb5db1d0cf..f3482e8f47 100644 --- a/core/config.h +++ b/core/config.h @@ -591,6 +591,10 @@ unless used elsewhere */ #define WASM_ENABLE_BRANCH_HINTS 0 #endif +#ifndef WASM_ENABLE_COMPILATION_HINTS +#define WASM_ENABLE_COMPILATION_HINTS 0 +#endif + #ifndef WASM_ENABLE_GC #define WASM_ENABLE_GC 0 #endif diff --git a/core/iwasm/compilation/aot.c b/core/iwasm/compilation/aot.c index 8e3eeec134..d4f75b30aa 100644 --- a/core/iwasm/compilation/aot.c +++ b/core/iwasm/compilation/aot.c @@ -416,7 +416,7 @@ aot_create_funcs(const WASMModule *module, uint32 pointer_size) aot_func->local_types_wp = func->local_types; aot_func->code = func->code; aot_func->code_size = func->code_size; -#if WASM_ENABLE_BRANCH_HINTS != 0 +#if WASM_ENABLE_BRANCH_HINTS != 0 || WASM_ENABLE_COMPILATION_HINTS != 0 aot_func->code_body_begin = func->code_body_begin; #endif @@ -875,7 +875,7 @@ aot_create_comp_data(WASMModule *module, const char *target_arch, comp_data->name_section_buf_end = module->name_section_buf_end; #endif -#if WASM_ENABLE_BRANCH_HINTS != 0 +#if WASM_ENABLE_BRANCH_HINTS != 0 || WASM_ENABLE_COMPILATION_HINTS != 0 comp_data->function_hints = module->function_hints; #endif diff --git a/core/iwasm/compilation/aot.h b/core/iwasm/compilation/aot.h index f1ecccfb37..1ce7ef0fbe 100644 --- a/core/iwasm/compilation/aot.h +++ b/core/iwasm/compilation/aot.h @@ -217,7 +217,7 @@ typedef struct AOTFunc { /* offset of each local, including function parameters and local variables */ uint16 *local_offsets; -#if WASM_ENABLE_BRANCH_HINTS != 0 +#if WASM_ENABLE_BRANCH_HINTS != 0 || WASM_ENABLE_COMPILATION_HINTS != 0 uint8 *code_body_begin; #endif } AOTFunc; @@ -300,7 +300,7 @@ typedef struct AOTCompData { dwarf_extractor_handle_t extractor; #endif -#if WASM_ENABLE_BRANCH_HINTS != 0 +#if WASM_ENABLE_BRANCH_HINTS != 0 || WASM_ENABLE_COMPILATION_HINTS != 0 struct WASMCompilationHint **function_hints; #endif } AOTCompData; diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index 29026e8008..e8d60c0896 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -1233,6 +1233,12 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) case WASM_OP_CALL_INDIRECT: { +#if WASM_ENABLE_COMPILATION_HINTS != 0 + const uint32 instr_offset = + (frame_ip - 0x1) - (func_ctx->aot_func->code_body_begin); +#else + const uint32 instr_offset = 0; +#endif uint32 tbl_idx; read_leb_uint32(frame_ip, frame_ip_end, type_idx); @@ -1246,7 +1252,7 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) } if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx, - tbl_idx)) + tbl_idx, instr_offset)) return false; break; } @@ -1269,6 +1275,12 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) case WASM_OP_RETURN_CALL_INDIRECT: { +#if WASM_ENABLE_COMPILATION_HINTS != 0 + const uint32 instr_offset = + (frame_ip - 0x1) - (func_ctx->aot_func->code_body_begin); +#else + const uint32 instr_offset = 0; +#endif uint32 tbl_idx; if (!comp_ctx->enable_tail_call) { @@ -1286,7 +1298,7 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) } if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx, - tbl_idx)) + tbl_idx, instr_offset)) return false; if (!aot_compile_op_return(comp_ctx, func_ctx, &frame_ip)) return false; diff --git a/core/iwasm/compilation/aot_emit_control.c b/core/iwasm/compilation/aot_emit_control.c index 6817295f86..93045f2aeb 100644 --- a/core/iwasm/compilation/aot_emit_control.c +++ b/core/iwasm/compilation/aot_emit_control.c @@ -272,14 +272,14 @@ aot_emit_branch_hint(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, { struct WASMCompilationHint *hint = func_ctx->function_hints; while (hint != NULL) { - if (hint->type == WASM_COMPILATION_BRANCH_HINT - && ((struct WASMCompilationHintBranchHint *)hint)->offset - == offset) { + if (hint->type == WASM_COMPILATION_HINT_BRANCH + && hint->offset == offset) { break; } hint = hint->next; } if (hint != NULL) { + ((struct WASMCompilationHintBranchHint *)hint)->used = true; // same weight llvm MDBuilder::createLikelyBranchWeights assigns const uint32_t likely_weight = (1U << 20) - 1; const uint32_t unlikely_weight = 1; @@ -1094,11 +1094,11 @@ aot_compile_conditional_br(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint64 size; // ip is advanced by one byte for the opcode -#if WASM_ENABLE_BRANCH_HINTS != 0 - uint32 instr_offset = +#if WASM_ENABLE_BRANCH_HINTS != 0 || WASM_ENABLE_COMPILATION_HINTS != 0 + const uint32 instr_offset = (*p_frame_ip - 0x1) - (func_ctx->aot_func->code_body_begin); #else - uint32 instr_offset = 0; + const uint32 instr_offset = 0; #endif uint64 br_depth; if (!read_leb(p_frame_ip, *p_frame_ip + 5, 32, false, &br_depth, NULL, 0)) diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index a1bc46332c..ccdcaa0829 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -112,6 +112,65 @@ check_exception_thrown(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) return true; } +#if WASM_ENABLE_COMPILATION_HINTS != 0 +static void +aot_emit_call_target_hint(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + uint32 offset, LLVMValueRef call_instr) +{ + struct WASMCompilationHint *hint = func_ctx->function_hints; + while (hint != NULL) { + if (hint->type == WASM_COMPILATION_HINT_CALL_TARGETS + && ((struct WASMCompilationHintCallTargets *)hint)->offset + == offset) { + break; + } + hint = hint->next; + } + if (hint != NULL) { + hint->used = true; + struct WASMCompilationHintCallTargets *ct_hint = + (struct WASMCompilationHintCallTargets *)hint; + + const unsigned md_node_cnt = ct_hint->target_count * 2 + 3; + LLVMMetadataRef *md_nodes = + wasm_runtime_malloc(md_node_cnt * sizeof(LLVMMetadataRef)); + if (!md_nodes) { + aot_set_last_error("allocate memory failed."); + return; + } + + md_nodes[0] = + LLVMMDStringInContext2(comp_ctx->context, "VP", strlen("VP")); + md_nodes[1] = LLVMValueAsMetadata(I32_CONST(0)); + // since wasm encodes a call frequency in full percent, we forward this + // to llvm as 100 calls to match the percentages + // (could be enhanced with the instruction frequency hints) + md_nodes[2] = LLVMValueAsMetadata(I64_CONST(100)); + + for (size_t i = 0; i < ct_hint->target_count; ++i) { + struct WASMCompilationHintCallTargetsHint *target = + &ct_hint->hints[i]; + char target_func_name[48]; + snprintf(target_func_name, sizeof(target_func_name), "%s%d", + AOT_FUNC_PREFIX, + target->func_idx - comp_ctx->comp_data->import_func_count); + const uint64_t func_name_hash = + aot_func_name_hash(target_func_name); + md_nodes[i * 2 + 3] = + LLVMValueAsMetadata(I64_CONST(func_name_hash)); + md_nodes[i * 2 + 3 + 1] = + LLVMValueAsMetadata(I64_CONST(target->call_frequency)); + } + LLVMMetadataRef meta_data = + LLVMMDNodeInContext2(comp_ctx->context, md_nodes, md_node_cnt); + LLVMValueRef meta_data_as_value = + LLVMMetadataAsValue(comp_ctx->context, meta_data); + LLVMSetMetadata(call_instr, 2, meta_data_as_value); + wasm_runtime_free(md_nodes); + } +} +#endif + /* Check whether there was exception thrown, if yes, return directly */ static bool check_call_return(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, @@ -1929,7 +1988,7 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMValueRef *param_values, uint32 param_count, uint32 param_cell_num, uint32 result_count, uint8 *wasm_ret_types, LLVMValueRef *value_rets, - LLVMValueRef *p_res) + LLVMValueRef *p_res, uint32 instr_offset) { LLVMTypeRef func_type, func_ptr_type, func_param_types[6]; LLVMTypeRef ret_type, ret_ptr_type, elem_ptr_type; @@ -2074,14 +2133,14 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, cell_num += wasm_value_type_cell_num_internal(wasm_ret_types[i], comp_ctx->pointer_size); } - *p_res = res; return true; } bool aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - uint32 type_idx, uint32 tbl_idx) + uint32 type_idx, uint32 tbl_idx, + uint32 instr_offset) { AOTFuncType *func_type; LLVMValueRef tbl_idx_value, elem_idx, func_idx; @@ -2620,7 +2679,7 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, if (!call_aot_call_indirect_func( comp_ctx, func_ctx, func_type, ftype_idx, tbl_idx_value, elem_idx, param_types + 1, param_values + 1, func_param_count, param_cell_num, - func_result_count, wasm_ret_types, value_rets, &res)) + func_result_count, wasm_ret_types, value_rets, &res, instr_offset)) goto fail; /* Check whether exception was thrown when executing the function */ @@ -2681,6 +2740,10 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } +#if WASM_ENABLE_COMPILATION_HINTS != 0 + aot_emit_call_target_hint(comp_ctx, func_ctx, instr_offset, value_ret); +#endif + /* Check whether exception was thrown when executing the function */ if ((comp_ctx->enable_bound_check || is_win_platform(comp_ctx)) && !check_exception_thrown(comp_ctx, func_ctx)) diff --git a/core/iwasm/compilation/aot_emit_function.h b/core/iwasm/compilation/aot_emit_function.h index 45f7bbe596..2852a0a08e 100644 --- a/core/iwasm/compilation/aot_emit_function.h +++ b/core/iwasm/compilation/aot_emit_function.h @@ -18,7 +18,8 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - uint32 type_idx, uint32 tbl_idx); + uint32 type_idx, uint32 tbl_idx, + uint32 instr_offset); bool aot_compile_op_ref_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index ab351e6d44..6c178fea86 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -1963,7 +1963,7 @@ aot_create_func_context(const AOTCompData *comp_data, AOTCompContext *comp_ctx, goto fail; } -#if WASM_ENABLE_BRANCH_HINTS != 0 +#if WASM_ENABLE_BRANCH_HINTS != 0 || WASM_ENABLE_COMPILATION_HINTS != 0 func_ctx->function_hints = comp_ctx->comp_data->function_hints ? comp_ctx->comp_data->function_hints[func_index] diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index 5bd75a38ce..ed241dd220 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -270,7 +270,7 @@ typedef struct AOTFuncContext { #if WASM_ENABLE_DEBUG_AOT != 0 LLVMMetadataRef debug_func; #endif -#if WASM_ENABLE_BRANCH_HINTS != 0 +#if WASM_ENABLE_BRANCH_HINTS != 0 || WASM_ENABLE_COMPILATION_HINTS != 0 struct WASMCompilationHint *function_hints; #endif @@ -674,6 +674,9 @@ unsigned int aot_estimate_stack_usage_for_function_call(const AOTCompContext *comp_ctx, const AOTFuncType *callee_func_type); +uint64_t +aot_func_name_hash(const char *name); + #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/core/iwasm/compilation/aot_llvm_extra.cpp b/core/iwasm/compilation/aot_llvm_extra.cpp index 35b25c8300..09dc10f881 100644 --- a/core/iwasm/compilation/aot_llvm_extra.cpp +++ b/core/iwasm/compilation/aot_llvm_extra.cpp @@ -433,3 +433,9 @@ aot_compress_aot_func_names(AOTCompContext *comp_ctx, uint32 *p_size) *p_size = compressed_str_len; return compressed_str; } + +uint64_t +aot_func_name_hash(const char *name) +{ + return MD5Hash(StringRef(name)); +} diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 87552455e6..44fe749ddb 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -752,7 +752,7 @@ struct WASMFunction { #endif #endif -#if WASM_ENABLE_BRANCH_HINTS != 0 +#if WASM_ENABLE_BRANCH_HINTS != 0 || WASM_ENABLE_COMPILATION_HINTS != 0 uint8 *code_body_begin; #endif }; @@ -765,21 +765,41 @@ struct WASMTag { }; #endif -#if WASM_ENABLE_BRANCH_HINTS != 0 +#if WASM_ENABLE_BRANCH_HINTS != 0 || WASM_ENABLE_COMPILATION_HINTS != 0 enum WASMCompilationHintType { DUMMY = 0, - WASM_COMPILATION_BRANCH_HINT = 0, + WASM_COMPILATION_HINT_BRANCH = 1, + WASM_COMPILATION_HINT_CALL_TARGETS = 2, }; struct WASMCompilationHint { struct WASMCompilationHint *next; enum WASMCompilationHintType type; + uint32 offset; + bool used; }; struct WASMCompilationHintBranchHint { struct WASMCompilationHint *next; enum WASMCompilationHintType type; uint32 offset; + bool used; + + // custom field bool is_likely; }; +struct WASMCompilationHintCallTargetsHint { + uint32 func_idx; + uint32 call_frequency; +}; +struct WASMCompilationHintCallTargets { + struct WASMCompilationHint *next; + enum WASMCompilationHintType type; + uint32 offset; + bool used; + + // custom fields + size_t target_count; + struct WASMCompilationHintCallTargetsHint *hints; +}; #endif struct WASMGlobal { @@ -1070,7 +1090,7 @@ struct WASMModule { const uint8 *name_section_buf_end; #endif -#if WASM_ENABLE_BRANCH_HINTS != 0 +#if WASM_ENABLE_BRANCH_HINTS != 0 || WASM_ENABLE_COMPILATION_HINTS != 0 struct WASMCompilationHint **function_hints; #endif diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 19ca249496..0c39ab3b57 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -3908,7 +3908,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, /* Resolve local set count */ p_code_end = p_code + code_size; -#if WASM_ENABLE_BRANCH_HINTS != 0 +#if WASM_ENABLE_BRANCH_HINTS != 0 || WASM_ENABLE_COMPILATION_HINTS != 0 uint8 *p_body_start = (uint8 *)p_code; #endif local_count = 0; @@ -3991,7 +3991,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, if (local_count > 0) func->local_types = (uint8 *)func + sizeof(WASMFunction); func->code_size = code_size; -#if WASM_ENABLE_BRANCH_HINTS != 0 +#if WASM_ENABLE_BRANCH_HINTS != 0 || WASM_ENABLE_COMPILATION_HINTS != 0 func->code_body_begin = p_body_start; #endif /* @@ -5566,11 +5566,14 @@ handle_name_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, } #endif -#if WASM_ENABLE_BRANCH_HINTS != 0 +#if WASM_ENABLE_BRANCH_HINTS != 0 || WASM_ENABLE_COMPILATION_HINTS != 0 +typedef bool (*CompileHintSig)(const uint8 *, const uint8 *, uint32, void *, + char *, uint32, WASMModule *); static bool -handle_branch_hint_section(const uint8 *buf, const uint8 *buf_end, +read_code_metadata_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, char *error_buf, - uint32 error_buf_size) + uint32 error_buf_size, size_t hint_struct_size, + const CompileHintSig hint_processor) { if (module->function_hints == NULL) { module->function_hints = loader_malloc( @@ -5601,45 +5604,31 @@ handle_branch_hint_section(const uint8 *buf, const uint8 *buf_end, uint32 num_hints; read_leb_uint32(buf, buf_end, num_hints); - struct WASMCompilationHintBranchHint *new_hints = loader_malloc( - sizeof(struct WASMCompilationHintBranchHint) * num_hints, error_buf, - error_buf_size); + struct WASMCompilationHint *new_hints = loader_malloc( + hint_struct_size * num_hints, error_buf, error_buf_size); for (uint32 j = 0; j < num_hints; ++j) { - struct WASMCompilationHintBranchHint *new_hint = &new_hints[j]; + struct WASMCompilationHint *new_hint = + new_hints + j * hint_struct_size; new_hint->next = NULL; - new_hint->type = WASM_COMPILATION_BRANCH_HINT; + new_hint->used = false; read_leb_uint32(buf, buf_end, new_hint->offset); uint32 size; read_leb_uint32(buf, buf_end, size); - if (size != 1) { - set_error_buf_v(error_buf, error_buf_size, - "invalid branch hint size, expected 1, got %d.", - size); - wasm_runtime_free(new_hint); - goto fail; - } - uint8 data = *buf++; - if (data == 0x00) - new_hint->is_likely = false; - else if (data == 0x01) - new_hint->is_likely = true; - else { - set_error_buf_v(error_buf, error_buf_size, - "invalid branch hint, expected 0 or 1, got %d", - data); - wasm_runtime_free(new_hint); + if (!hint_processor(buf, buf_end, size, (void *)new_hint, error_buf, + error_buf_size, module)) { + wasm_runtime_free(new_hints); goto fail; } - - current_hint->next = (struct WASMCompilationHint *)new_hint; - current_hint = (struct WASMCompilationHint *)new_hint; + buf += size; + current_hint->next = new_hint; + current_hint = new_hint; } } if (buf != buf_end) { set_error_buf(error_buf, error_buf_size, - "invalid branch hint section, not filled until end"); + "invalid compilation hint section, not filled until end"); goto fail; } return true; @@ -5648,6 +5637,116 @@ handle_branch_hint_section(const uint8 *buf, const uint8 *buf_end, } #endif +#if WASM_ENABLE_BRANCH_HINTS != 0 +bool +handle_compilation_hint_branch_hint_processor(const uint8 *buf, + const uint8 *buf_end, + const uint32 hint_size, + void *hint_store, char *error_buf, + uint32 error_buf_size, + WASMModule *module) +{ + (void)module; + struct WASMCompilationHintBranchHint *hint = hint_store; + hint->type = WASM_COMPILATION_HINT_BRANCH; + if (hint_size != 1) { + set_error_buf_v(error_buf, error_buf_size, + "invalid branch hint size, expected 1, got %d.", + hint_size); + return false; + } + CHECK_BUF(buf, buf_end, 1); + const uint8 data = read_uint8(buf); + if (data == 0x00) + hint->is_likely = false; + else if (data == 0x01) + hint->is_likely = true; + else { + set_error_buf_v(error_buf, error_buf_size, + "invalid branch hint value, expected 0 or 1, got %d", + data); + goto fail; + } + return true; +fail: + return false; +} +static bool +handle_branch_hint_section(const uint8 *buf, const uint8 *buf_end, + WASMModule *module, char *error_buf, + uint32 error_buf_size) +{ + return read_code_metadata_section( + buf, buf_end, module, error_buf, error_buf_size, + sizeof(struct WASMCompilationHintCallTargets), + handle_compilation_hint_branch_hint_processor); +} +#endif + +#if WASM_ENABLE_COMPILATION_HINTS != 0 +bool +handle_compilation_hint_call_targets_processor( + const uint8 *buf, const uint8 *buf_end, const uint32 hint_size, + void *hint_store, char *error_buf, uint32 error_buf_size, + WASMModule *module) +{ + struct WASMCompilationHintCallTargets *hint = hint_store; + hint->type = WASM_COMPILATION_HINT_CALL_TARGETS; + CHECK_BUF(buf, buf_end, hint_size); + hint->target_count = 0; + + const uint8 *orig_buf = buf; + const uint8 *hint_end = buf + hint_size; + // first pass: count hints + while (buf < hint_end) { + uint32 func_idx; + read_leb_uint32(buf, buf_end, func_idx); + check_function_index(module, func_idx, error_buf, error_buf_size); + uint32 call_frequency; + read_leb_uint32(buf, buf_end, call_frequency); + (void)call_frequency; + hint->target_count += 1; + } + if (buf != hint_end) { + set_error_buf_v(error_buf, error_buf_size, + "incomplete call targets hint"); + goto fail; + } + + hint->hints = (struct WASMCompilationHintCallTargetsHint *)loader_malloc( + sizeof(struct WASMCompilationHintCallTargetsHint) * hint->target_count, + error_buf, error_buf_size); + if (!hint->hints) { + return false; + } + + // second pass: store hint information + buf = orig_buf; + for (size_t i = 0; i < hint->target_count; ++i) { + struct WASMCompilationHintCallTargetsHint *target_hint = + &hint->hints[i]; + read_leb_uint32(buf, buf_end, target_hint->func_idx); + read_leb_uint32(buf, buf_end, target_hint->call_frequency); + } + return true; +fail: + return false; +} + +static bool +handle_compilation_hint_call_targets_section(const uint8 *buf, + const uint8 *buf_end, + WASMModule *module, + char *error_buf, + uint32 error_buf_size) +{ + return read_code_metadata_section( + buf, buf_end, module, error_buf, error_buf_size, + sizeof(struct WASMCompilationHintCallTargets), + handle_compilation_hint_call_targets_processor); +} +#endif + static bool load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, bool is_load_from_file_buf, char *error_buf, @@ -5706,12 +5805,34 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, return false; } LOG_VERBOSE("Load branch hint section success."); + return true; } #else if (name_len == 25 && memcmp((const char *)p, "metadata.code.branch_hint", 25) == 0) { LOG_VERBOSE("Found branch hint section, but branch hints are disabled " "in this build, skipping."); + return true; + } +#endif + +#if WASM_ENABLE_COMPILATION_HINTS != 0 + if (name_len == 26 + && memcmp((const char *)p, "metadata.code.call_targets", 26) == 0) { + p += name_len; + if (!handle_compilation_hint_call_targets_section( + p, p_end, module, error_buf, error_buf_size)) { + return false; + } + LOG_VERBOSE("Load call target compilation hint section success."); + return true; + } +#else + if (name_len == 26 + && memcmp((const char *)p, "metadata.code.call_targets", 26) == 0) { + LOG_VERBOSE("Found compilation hints call targets section, but " + "compilation hints are disabled in this build, skipping."); + return true; } #endif @@ -7500,13 +7621,35 @@ wasm_loader_unload(WASMModule *module) } #endif #endif -#if WASM_ENABLE_BRANCH_HINTS != 0 +#if WASM_ENABLE_BRANCH_HINTS != 0 || WASM_ENABLE_COMPILATION_HINTS != 0 for (i = 0; i < module->function_count; i++) { - // be carefull when adding more hints. This only works as long as - // the hint structs have been allocated all at once as an array. - // With only branch-hints at the moment, this is the case. - if (module->function_hints != NULL && module->function_hints[i] != NULL) - wasm_runtime_free(module->function_hints[i]); + if (module->function_hints != NULL + && module->function_hints[i] != NULL) { + // properly free all additionally allocated data: + // each code metadata section parsed adds a chain of hints to the + // function hints. That chain of WASMCompilationHint specializations + // is allocated as an array. We need to find the starts of the + // separate arrays to free them all properly. + struct WASMCompilationHint *curr = module->function_hints[i]; + struct WASMCompilationHint *last_chain_start = curr; + while (curr != NULL) { + if (!curr->used) { + printf("Unused hint for function %u, offset: %x\n", + i + module->import_count, curr->offset); + } + if (curr->type != last_chain_start->type) { + // we switched chains -> deallocate previous chain and reset + wasm_runtime_free(last_chain_start); + last_chain_start = curr; + } + if (curr->type == WASM_COMPILATION_HINT_CALL_TARGETS) { + wasm_runtime_free( + ((struct WASMCompilationHintCallTargets *)curr)->hints); + } + curr = curr->next; + } + wasm_runtime_free(last_chain_start); + } } if (module->function_hints != NULL) wasm_runtime_free(module->function_hints); diff --git a/doc/stability_wasm_proposals.md b/doc/stability_wasm_proposals.md index c8b90d5e44..03a5b2c71e 100644 --- a/doc/stability_wasm_proposals.md +++ b/doc/stability_wasm_proposals.md @@ -31,7 +31,7 @@ Users can turn those features on or off by using compilation options. If a relev ## Off-by-default Wasm Proposals | Proposal | >= Phase 4 | Compilation Option | -| ----------------------------- | ---------- | ---------------------------------| +| ----------------------------- | ---------- |----------------------------------| | Extended Constant Expressions | Yes | `WAMR_BUILD_EXTENDED_CONST_EXPR` | | Garbage Collection | Yes | `WAMR_BUILD_GC` | | Legacy Exception Handling[^3] | No | `WAMR_BUILD_EXCE_HANDLING` | @@ -41,6 +41,7 @@ Users can turn those features on or off by using compilation options. If a relev | Tail Call | Yes | `WAMR_BUILD_TAIL_CALL` | | Threads[^5] | Yes | `WAMR_BUILD_SHARED_MEMORY` | | Typed Function References | Yes | `WAMR_BUILD_GC` | +| Compilation Hints | No | `WASM_ENABLE_COMPILATION_HINTS` | [^3]: interpreter only. [a legacy version](https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/legacy/Exceptions.md). diff --git a/product-mini/platforms/common/wasm_proposal.c b/product-mini/platforms/common/wasm_proposal.c index 8a4c3d44f9..da6088a18d 100644 --- a/product-mini/platforms/common/wasm_proposal.c +++ b/product-mini/platforms/common/wasm_proposal.c @@ -17,6 +17,8 @@ wasm_proposal_print_status(void) printf(" - Non-trapping float-to-int Conversions\n"); printf(" - Sign-extension Operators\n"); printf(" - WebAssembly C and C++ API\n"); + printf(" - Branch Hinting\n"); + printf(" - Compilation Hints\n"); printf(" Compilation Configurable. 0 is OFF. 1 is ON:\n"); printf(" - Bulk Memory Operation via WASM_ENABLE_BULK_MEMORY: %u\n", WASM_ENABLE_BULK_MEMORY); @@ -41,7 +43,6 @@ wasm_proposal_print_status(void) printf(" - Typed Function References via WASM_ENABLE_GC: %u\n", WASM_ENABLE_GC); printf(" Unsupported (>= Phase4):\n"); - printf(" - Branch Hinting\n"); printf(" - Custom Annotation Syntax in the Text Format\n"); printf(" - Exception Handling\n"); printf(" - JS String Builtins\n"); diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index 513fd0049c..b6ca896860 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -49,6 +49,7 @@ add_definitions(-DWASM_ENABLE_TAIL_CALL=1) add_definitions(-DWASM_ENABLE_REF_TYPES=1) add_definitions(-DWASM_ENABLE_CALL_INDIRECT_OVERLONG=1) add_definitions(-DWASM_ENABLE_BRANCH_HINTS=1) +add_definitions(-DWASM_ENABLE_COMPILATION_HINTS=1) add_definitions(-DWASM_ENABLE_CUSTOM_NAME_SECTION=1) add_definitions(-DWASM_ENABLE_AOT_STACK_FRAME=1) add_definitions(-DWASM_ENABLE_DUMP_CALL_STACK=1)