This repository has been archived on 2023-11-05. You can view files and clone it, but cannot push or open issues or pull requests.
wasm-micro-runtime/core/iwasm/compilation/aot_emit_variable.c
Wenyong Huang a182926a73
Refactor interpreter/AOT module instance layout (#1559)
Refactor the layout of interpreter and AOT module instance:
- Unify the interp/AOT module instance, use the same WASMModuleInstance/
  WASMMemoryInstance/WASMTableInstance data structures for both interpreter
  and AOT
- Make the offset of most fields the same in module instance for both interpreter
  and AOT, append memory instance structure, global data and table instances to
  the end of module instance for interpreter mode (like AOT mode)
- For extra fields in WASM module instance, use WASMModuleInstanceExtra to
  create a field `e` for interpreter
- Change the LLVM JIT module instance creating process, LLVM JIT uses the WASM
  module and module instance same as interpreter/Fast-JIT mode. So that Fast JIT
  and LLVM JIT can access the same data structures, and make it possible to
  implement the Multi-tier JIT (tier-up from Fast JIT to LLVM JIT) in the future
- Unify some APIs: merge some APIs for module instance and memory instance's
  related operations (only implement one copy)

Note that the AOT ABI is same, the AOT file format, AOT relocation types, how AOT
code accesses the AOT module instance and so on are kept unchanged.

Refer to:
https://github.com/bytecodealliance/wasm-micro-runtime/issues/1384
2022-10-18 10:59:28 +08:00

275 lines
8.9 KiB
C

/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "aot_emit_variable.h"
#include "aot_emit_exception.h"
#include "../aot/aot_runtime.h"
#define CHECK_LOCAL(idx) \
do { \
if (idx >= func_ctx->aot_func->func_type->param_count \
+ func_ctx->aot_func->local_count) { \
aot_set_last_error("local index out of range"); \
return false; \
} \
} while (0)
static uint8
get_local_type(AOTFuncContext *func_ctx, uint32 local_idx)
{
AOTFunc *aot_func = func_ctx->aot_func;
uint32 param_count = aot_func->func_type->param_count;
return local_idx < param_count
? aot_func->func_type->types[local_idx]
: aot_func->local_types[local_idx - param_count];
}
bool
aot_compile_op_get_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 local_idx)
{
char name[32];
LLVMValueRef value;
AOTValue *aot_value_top;
uint8 local_type;
CHECK_LOCAL(local_idx);
local_type = get_local_type(func_ctx, local_idx);
snprintf(name, sizeof(name), "%s%d%s", "local", local_idx, "#");
if (!(value = LLVMBuildLoad2(comp_ctx->builder, TO_LLVM_TYPE(local_type),
func_ctx->locals[local_idx], name))) {
aot_set_last_error("llvm build load fail");
return false;
}
PUSH(value, local_type);
aot_value_top =
func_ctx->block_stack.block_list_end->value_stack.value_list_end;
aot_value_top->is_local = true;
aot_value_top->local_idx = local_idx;
return true;
fail:
return false;
}
bool
aot_compile_op_set_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 local_idx)
{
LLVMValueRef value;
CHECK_LOCAL(local_idx);
POP(value, get_local_type(func_ctx, local_idx));
if (!LLVMBuildStore(comp_ctx->builder, value,
func_ctx->locals[local_idx])) {
aot_set_last_error("llvm build store fail");
return false;
}
aot_checked_addr_list_del(func_ctx, local_idx);
return true;
fail:
return false;
}
bool
aot_compile_op_tee_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 local_idx)
{
LLVMValueRef value;
uint8 type;
CHECK_LOCAL(local_idx);
type = get_local_type(func_ctx, local_idx);
POP(value, type);
if (!LLVMBuildStore(comp_ctx->builder, value,
func_ctx->locals[local_idx])) {
aot_set_last_error("llvm build store fail");
return false;
}
PUSH(value, type);
aot_checked_addr_list_del(func_ctx, local_idx);
return true;
fail:
return false;
}
static bool
compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 global_idx, bool is_set, bool is_aux_stack)
{
AOTCompData *comp_data = comp_ctx->comp_data;
uint32 import_global_count = comp_data->import_global_count;
uint32 global_base_offset;
uint32 global_offset;
uint8 global_type;
LLVMValueRef offset, global_ptr, global, res;
LLVMTypeRef ptr_type = NULL;
if (comp_ctx->is_jit_mode) {
global_base_offset =
offsetof(WASMModuleInstance, global_table_data.bytes)
+ sizeof(WASMMemoryInstance) * comp_ctx->comp_data->memory_count;
}
else {
global_base_offset =
offsetof(AOTModuleInstance, global_table_data.bytes)
+ sizeof(AOTMemoryInstance) * comp_ctx->comp_data->memory_count;
}
bh_assert(global_idx < import_global_count + comp_data->global_count);
if (global_idx < import_global_count) {
global_offset = global_base_offset
+ comp_data->import_globals[global_idx].data_offset;
global_type = comp_data->import_globals[global_idx].type;
}
else {
global_offset =
global_base_offset
+ comp_data->globals[global_idx - import_global_count].data_offset;
global_type = comp_data->globals[global_idx - import_global_count].type;
}
offset = I32_CONST(global_offset);
if (!(global_ptr = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
func_ctx->aot_inst, &offset, 1,
"global_ptr_tmp"))) {
aot_set_last_error("llvm build in bounds gep failed.");
return false;
}
switch (global_type) {
case VALUE_TYPE_I32:
case VALUE_TYPE_EXTERNREF:
case VALUE_TYPE_FUNCREF:
ptr_type = comp_ctx->basic_types.int32_ptr_type;
break;
case VALUE_TYPE_I64:
ptr_type = comp_ctx->basic_types.int64_ptr_type;
break;
case VALUE_TYPE_F32:
ptr_type = comp_ctx->basic_types.float32_ptr_type;
break;
case VALUE_TYPE_F64:
ptr_type = comp_ctx->basic_types.float64_ptr_type;
break;
case VALUE_TYPE_V128:
ptr_type = comp_ctx->basic_types.v128_ptr_type;
break;
default:
bh_assert("unknown type");
break;
}
if (!(global_ptr = LLVMBuildBitCast(comp_ctx->builder, global_ptr, ptr_type,
"global_ptr"))) {
aot_set_last_error("llvm build bit cast failed.");
return false;
}
if (!is_set) {
if (!(global =
LLVMBuildLoad2(comp_ctx->builder, TO_LLVM_TYPE(global_type),
global_ptr, "global"))) {
aot_set_last_error("llvm build load failed.");
return false;
}
/* All globals' data is 4-byte aligned */
LLVMSetAlignment(global, 4);
PUSH(global, global_type);
}
else {
POP(global, global_type);
if (is_aux_stack && comp_ctx->enable_aux_stack_check) {
LLVMBasicBlockRef block_curr =
LLVMGetInsertBlock(comp_ctx->builder);
LLVMBasicBlockRef check_overflow_succ, check_underflow_succ;
LLVMValueRef cmp;
/* Add basic blocks */
if (!(check_overflow_succ = LLVMAppendBasicBlockInContext(
comp_ctx->context, func_ctx->func,
"check_overflow_succ"))) {
aot_set_last_error("llvm add basic block failed.");
return false;
}
LLVMMoveBasicBlockAfter(check_overflow_succ, block_curr);
if (!(check_underflow_succ = LLVMAppendBasicBlockInContext(
comp_ctx->context, func_ctx->func,
"check_underflow_succ"))) {
aot_set_last_error("llvm add basic block failed.");
return false;
}
LLVMMoveBasicBlockAfter(check_underflow_succ, check_overflow_succ);
/* Check aux stack overflow */
if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntULE, global,
func_ctx->aux_stack_bound, "cmp"))) {
aot_set_last_error("llvm build icmp failed.");
return false;
}
if (!aot_emit_exception(comp_ctx, func_ctx, EXCE_AUX_STACK_OVERFLOW,
true, cmp, check_overflow_succ)) {
return false;
}
/* Check aux stack underflow */
LLVMPositionBuilderAtEnd(comp_ctx->builder, check_overflow_succ);
if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGT, global,
func_ctx->aux_stack_bottom, "cmp"))) {
aot_set_last_error("llvm build icmp failed.");
return false;
}
if (!aot_emit_exception(comp_ctx, func_ctx,
EXCE_AUX_STACK_UNDERFLOW, true, cmp,
check_underflow_succ)) {
return false;
}
LLVMPositionBuilderAtEnd(comp_ctx->builder, check_underflow_succ);
}
if (!(res = LLVMBuildStore(comp_ctx->builder, global, global_ptr))) {
aot_set_last_error("llvm build store failed.");
return false;
}
/* All globals' data is 4-byte aligned */
LLVMSetAlignment(res, 4);
}
return true;
fail:
return false;
}
bool
aot_compile_op_get_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 global_idx)
{
return compile_global(comp_ctx, func_ctx, global_idx, false, false);
}
bool
aot_compile_op_set_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 global_idx, bool is_aux_stack)
{
return compile_global(comp_ctx, func_ctx, global_idx, true, is_aux_stack);
}