Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build-scripts/config_common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions core/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions core/iwasm/compilation/aot.c
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions core/iwasm/compilation/aot.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
16 changes: 14 additions & 2 deletions core/iwasm/compilation/aot_compiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
}
Expand All @@ -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) {
Expand All @@ -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;
Expand Down
12 changes: 6 additions & 6 deletions core/iwasm/compilation/aot_emit_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to cast as the used field is in WASMCompilationHint as well.

// same weight llvm MDBuilder::createLikelyBranchWeights assigns
const uint32_t likely_weight = (1U << 20) - 1;
const uint32_t unlikely_weight = 1;
Expand Down Expand Up @@ -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))
Expand Down
71 changes: 67 additions & 4 deletions core/iwasm/compilation/aot_emit_function.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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))
Expand Down
3 changes: 2 additions & 1 deletion core/iwasm/compilation/aot_emit_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion core/iwasm/compilation/aot_llvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
5 changes: 4 additions & 1 deletion core/iwasm/compilation/aot_llvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions core/iwasm/compilation/aot_llvm_extra.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this function ubiquitously available?
i suspect it isn't.

}
28 changes: 24 additions & 4 deletions core/iwasm/interpreter/wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
Expand All @@ -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;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this used field only for diagnostic purposes?

};
struct WASMCompilationHintBranchHint {
struct WASMCompilationHint *next;
enum WASMCompilationHintType type;
uint32 offset;
bool used;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i feel it's simpler to have struct WASMCompilationHint common instead of duplicating individual fields.


// 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 {
Expand Down Expand Up @@ -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

Expand Down
Loading
Loading