Import reference-types feature (#612)
Implement spec reference-types proposal for interpreter, AOT and JIT, update documents and add sample. And upgrade AOT_CURRENT_VERSION to 3 as AOT file format and AOT module instance layout are changed. Signed-off-by: Wenyong Huang <wenyong.huang@intel.com>
This commit is contained in:
@ -125,8 +125,18 @@ aot_create_table_init_data_list(const WASMModule *module)
|
||||
|
||||
data_list[i]->offset = module->table_segments[i].base_offset;
|
||||
data_list[i]->func_index_count = module->table_segments[i].function_count;
|
||||
memcpy(data_list[i]->func_indexes, module->table_segments[i].func_indexes,
|
||||
sizeof(uint32) * module->table_segments[i].function_count);
|
||||
data_list[i]->mode = module->table_segments[i].mode;
|
||||
data_list[i]->elem_type = module->table_segments[i].elem_type;
|
||||
/* runtime control it */
|
||||
data_list[i]->is_dropped = false;
|
||||
data_list[i]->table_index = module->table_segments[i].table_index;
|
||||
bh_memcpy_s(&data_list[i]->offset, sizeof(AOTInitExpr),
|
||||
&module->table_segments[i].base_offset, sizeof(AOTInitExpr));
|
||||
data_list[i]->func_index_count = module->table_segments[i].function_count;
|
||||
bh_memcpy_s(data_list[i]->func_indexes,
|
||||
sizeof(uint32) * module->table_segments[i].function_count,
|
||||
module->table_segments[i].func_indexes,
|
||||
sizeof(uint32) * module->table_segments[i].function_count);
|
||||
}
|
||||
|
||||
return data_list;
|
||||
@ -424,8 +434,6 @@ aot_create_comp_data(WASMModule *module)
|
||||
aot_create_mem_init_data_list(module)))
|
||||
goto fail;
|
||||
|
||||
/* TODO: create import tables */
|
||||
|
||||
/* Create tables */
|
||||
comp_data->table_count = module->import_table_count + module->table_count;
|
||||
|
||||
@ -447,6 +455,8 @@ aot_create_comp_data(WASMModule *module)
|
||||
module->import_tables[i].u.table.init_size;
|
||||
comp_data->tables[i].table_max_size =
|
||||
module->import_tables[i].u.table.max_size;
|
||||
comp_data->tables[i].possible_grow =
|
||||
module->import_tables[i].u.table.possible_grow;
|
||||
}
|
||||
else {
|
||||
j = i - module->import_table_count;
|
||||
@ -454,6 +464,7 @@ aot_create_comp_data(WASMModule *module)
|
||||
comp_data->tables[i].table_flags = module->tables[i].flags;
|
||||
comp_data->tables[i].table_init_size = module->tables[i].init_size;
|
||||
comp_data->tables[i].table_max_size = module->tables[i].max_size;
|
||||
comp_data->tables[i].possible_grow = module->tables[i].possible_grow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,6 +71,7 @@ typedef struct AOTImportTable {
|
||||
uint32 table_flags;
|
||||
uint32 table_init_size;
|
||||
uint32 table_max_size;
|
||||
bool possible_grow;
|
||||
} AOTImportTable;
|
||||
|
||||
/**
|
||||
@ -81,12 +82,19 @@ typedef struct AOTTable {
|
||||
uint32 table_flags;
|
||||
uint32 table_init_size;
|
||||
uint32 table_max_size;
|
||||
bool possible_grow;
|
||||
} AOTTable;
|
||||
|
||||
/**
|
||||
* A segment of table init data
|
||||
*/
|
||||
typedef struct AOTTableInitData {
|
||||
/* 0 to 7 */
|
||||
uint32 mode;
|
||||
/* funcref or externref, elemkind will be considered as funcref */
|
||||
uint32 elem_type;
|
||||
bool is_dropped;
|
||||
/* optional, only for active */
|
||||
uint32 table_index;
|
||||
/* Start address of init data */
|
||||
AOTInitExpr offset;
|
||||
@ -245,6 +253,18 @@ aot_set_last_error_v(const char *format, ...);
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
static inline uint32
|
||||
aot_get_tbl_data_slots(const AOTTable *tbl)
|
||||
{
|
||||
return tbl->possible_grow ? tbl->table_max_size : tbl->table_init_size;
|
||||
}
|
||||
|
||||
static inline uint32
|
||||
aot_get_imp_tbl_data_slots(const AOTImportTable *tbl)
|
||||
{
|
||||
return tbl->possible_grow ? tbl->table_max_size : tbl->table_init_size;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
#include "aot_emit_control.h"
|
||||
#include "aot_emit_function.h"
|
||||
#include "aot_emit_parametric.h"
|
||||
#include "aot_emit_table.h"
|
||||
#include "simd/simd_access_lanes.h"
|
||||
#include "simd/simd_bitmask_extracts.h"
|
||||
#include "simd/simd_bit_shifts.h"
|
||||
@ -176,7 +177,9 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|
||||
|| value_type == VALUE_TYPE_F32
|
||||
|| value_type == VALUE_TYPE_F64
|
||||
|| value_type == VALUE_TYPE_V128
|
||||
|| value_type == VALUE_TYPE_VOID) {
|
||||
|| value_type == VALUE_TYPE_VOID
|
||||
|| value_type == VALUE_TYPE_FUNCREF
|
||||
|| value_type == VALUE_TYPE_EXTERNREF) {
|
||||
param_count = 0;
|
||||
param_types = NULL;
|
||||
if (value_type == VALUE_TYPE_VOID) {
|
||||
@ -258,11 +261,27 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|
||||
break;
|
||||
|
||||
case WASM_OP_CALL_INDIRECT:
|
||||
{
|
||||
uint32 tbl_idx;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, type_idx);
|
||||
frame_ip++; /* skip 0x00 */
|
||||
if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx))
|
||||
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
if (comp_ctx->enable_ref_types) {
|
||||
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
frame_ip++;
|
||||
tbl_idx = 0;
|
||||
}
|
||||
|
||||
if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx,
|
||||
tbl_idx))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_TAIL_CALL != 0
|
||||
case WASM_OP_RETURN_CALL:
|
||||
@ -278,17 +297,33 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|
||||
break;
|
||||
|
||||
case WASM_OP_RETURN_CALL_INDIRECT:
|
||||
{
|
||||
uint32 tbl_idx;
|
||||
|
||||
if (!comp_ctx->enable_tail_call) {
|
||||
aot_set_last_error("unsupported opcode");
|
||||
return false;
|
||||
}
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, type_idx);
|
||||
frame_ip++; /* skip 0x00 */
|
||||
if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx))
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
if (comp_ctx->enable_ref_types) {
|
||||
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
frame_ip++;
|
||||
tbl_idx = 0;
|
||||
}
|
||||
|
||||
if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx,
|
||||
tbl_idx))
|
||||
return false;
|
||||
if (!aot_compile_op_return(comp_ctx, func_ctx, &frame_ip))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
#endif /* end of WASM_ENABLE_TAIL_CALL */
|
||||
|
||||
case WASM_OP_DROP:
|
||||
@ -311,6 +346,93 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|
||||
return false;
|
||||
break;
|
||||
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
case WASM_OP_SELECT_T:
|
||||
{
|
||||
uint32 vec_len;
|
||||
|
||||
if (!comp_ctx->enable_ref_types) {
|
||||
goto unsupport_ref_types;
|
||||
}
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, vec_len);
|
||||
bh_assert(vec_len == 1);
|
||||
vec_len = vec_len;
|
||||
|
||||
type_idx = *frame_ip++;
|
||||
if (!aot_compile_op_select(comp_ctx, func_ctx,
|
||||
(type_idx != VALUE_TYPE_I64)
|
||||
&& (type_idx != VALUE_TYPE_F64)))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case WASM_OP_TABLE_GET:
|
||||
{
|
||||
uint32 tbl_idx;
|
||||
|
||||
if (!comp_ctx->enable_ref_types) {
|
||||
goto unsupport_ref_types;
|
||||
}
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
|
||||
if (!aot_compile_op_table_get(comp_ctx, func_ctx, tbl_idx))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case WASM_OP_TABLE_SET:
|
||||
{
|
||||
uint32 tbl_idx;
|
||||
|
||||
if (!comp_ctx->enable_ref_types) {
|
||||
goto unsupport_ref_types;
|
||||
}
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
|
||||
if (!aot_compile_op_table_set(comp_ctx, func_ctx, tbl_idx))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case WASM_OP_REF_NULL:
|
||||
{
|
||||
uint32 type;
|
||||
|
||||
if (!comp_ctx->enable_ref_types) {
|
||||
goto unsupport_ref_types;
|
||||
}
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, type);
|
||||
|
||||
if (!aot_compile_op_ref_null(comp_ctx, func_ctx))
|
||||
return false;
|
||||
|
||||
(void)type;
|
||||
break;
|
||||
}
|
||||
case WASM_OP_REF_IS_NULL:
|
||||
{
|
||||
if (!comp_ctx->enable_ref_types) {
|
||||
goto unsupport_ref_types;
|
||||
}
|
||||
|
||||
if (!aot_compile_op_ref_is_null(comp_ctx, func_ctx))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case WASM_OP_REF_FUNC:
|
||||
{
|
||||
uint32 func_idx;
|
||||
|
||||
if (!comp_ctx->enable_ref_types) {
|
||||
goto unsupport_ref_types;
|
||||
}
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, func_idx);
|
||||
if (!aot_compile_op_ref_func(comp_ctx, func_ctx, func_idx))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case WASM_OP_GET_LOCAL:
|
||||
read_leb_uint32(frame_ip, frame_ip_end, local_idx);
|
||||
if (!aot_compile_op_get_local(comp_ctx, func_ctx, local_idx))
|
||||
@ -828,6 +950,15 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|
||||
read_leb_uint32(frame_ip, frame_ip_end, opcode1);
|
||||
opcode = (uint32)opcode1;
|
||||
|
||||
//TODO: --enable-bulk-memory ?
|
||||
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
if (WASM_OP_TABLE_INIT <= opcode && opcode <= WASM_OP_TABLE_FILL
|
||||
&& !comp_ctx->enable_ref_types) {
|
||||
goto unsupport_ref_types;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (opcode) {
|
||||
case WASM_OP_I32_TRUNC_SAT_S_F32:
|
||||
case WASM_OP_I32_TRUNC_SAT_U_F32:
|
||||
@ -886,11 +1017,74 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|
||||
break;
|
||||
}
|
||||
#endif /* WASM_ENABLE_BULK_MEMORY */
|
||||
default:
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
case WASM_OP_TABLE_INIT:
|
||||
{
|
||||
uint32 tbl_idx, tbl_seg_idx;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, tbl_seg_idx);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
|
||||
if (!aot_compile_op_table_init(comp_ctx, func_ctx, tbl_idx,
|
||||
tbl_seg_idx))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case WASM_OP_ELEM_DROP:
|
||||
{
|
||||
uint32 tbl_seg_idx;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, tbl_seg_idx);
|
||||
if (!aot_compile_op_elem_drop(comp_ctx, func_ctx, tbl_seg_idx))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case WASM_OP_TABLE_COPY:
|
||||
{
|
||||
uint32 src_tbl_idx, dst_tbl_idx;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, dst_tbl_idx);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, src_tbl_idx);
|
||||
if (!aot_compile_op_table_copy(comp_ctx, func_ctx, src_tbl_idx,
|
||||
dst_tbl_idx))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case WASM_OP_TABLE_GROW:
|
||||
{
|
||||
uint32 tbl_idx;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
|
||||
if (!aot_compile_op_table_grow(comp_ctx, func_ctx, tbl_idx))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case WASM_OP_TABLE_SIZE:
|
||||
{
|
||||
uint32 tbl_idx;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
|
||||
if (!aot_compile_op_table_size(comp_ctx, func_ctx, tbl_idx))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case WASM_OP_TABLE_FILL:
|
||||
{
|
||||
uint32 tbl_idx;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
|
||||
if (!aot_compile_op_table_fill(comp_ctx, func_ctx, tbl_idx))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
#endif /* WASM_ENABLE_REF_TYPES */
|
||||
default:
|
||||
aot_set_last_error("unsupported opcode");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
case WASM_OP_ATOMIC_PREFIX:
|
||||
{
|
||||
@ -1030,7 +1224,8 @@ build_atomic_rmw:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
aot_set_last_error("unsupported opcode");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1040,9 +1235,7 @@ build_atomic_rmw:
|
||||
case WASM_OP_SIMD_PREFIX:
|
||||
{
|
||||
if (!comp_ctx->enable_simd) {
|
||||
aot_set_last_error("SIMD instruction was found, "
|
||||
"try adding --enable-simd option?");
|
||||
return false;
|
||||
goto unsupport_simd;
|
||||
}
|
||||
|
||||
opcode = *frame_ip++;
|
||||
@ -1795,7 +1988,8 @@ build_atomic_rmw:
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
aot_set_last_error("unsupported opcode");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1803,29 +1997,43 @@ build_atomic_rmw:
|
||||
|
||||
default:
|
||||
aot_set_last_error("unsupported opcode");
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Move func_return block to the bottom */
|
||||
if (func_ctx->func_return_block) {
|
||||
LLVMBasicBlockRef last_block =
|
||||
LLVMGetLastBasicBlock(func_ctx->func);
|
||||
if (last_block != func_ctx->func_return_block)
|
||||
LLVMMoveBasicBlockAfter(func_ctx->func_return_block,
|
||||
last_block);
|
||||
LLVMBasicBlockRef last_block =
|
||||
LLVMGetLastBasicBlock(func_ctx->func);
|
||||
if (last_block != func_ctx->func_return_block)
|
||||
LLVMMoveBasicBlockAfter(func_ctx->func_return_block,
|
||||
last_block);
|
||||
}
|
||||
|
||||
/* Move got_exception block to the bottom */
|
||||
if (func_ctx->got_exception_block) {
|
||||
LLVMBasicBlockRef last_block =
|
||||
LLVMGetLastBasicBlock(func_ctx->func);
|
||||
if (last_block != func_ctx->got_exception_block)
|
||||
LLVMMoveBasicBlockAfter(func_ctx->got_exception_block,
|
||||
last_block);
|
||||
LLVMBasicBlockRef last_block =
|
||||
LLVMGetLastBasicBlock(func_ctx->func);
|
||||
if (last_block != func_ctx->got_exception_block)
|
||||
LLVMMoveBasicBlockAfter(func_ctx->got_exception_block,
|
||||
last_block);
|
||||
}
|
||||
return true;
|
||||
|
||||
#if WASM_ENABLE_SIMD != 0
|
||||
unsupport_simd:
|
||||
aot_set_last_error("SIMD instruction was found, "
|
||||
"try adding --enable-simd option?");
|
||||
return false;
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
unsupport_ref_types:
|
||||
aot_set_last_error("reference type instruction was found, "
|
||||
"try adding --enable-ref-types option?");
|
||||
return false;
|
||||
#endif
|
||||
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -102,6 +102,34 @@ typedef enum FloatArithmetic {
|
||||
FLOAT_MAX
|
||||
} FloatArithmetic;
|
||||
|
||||
static inline bool
|
||||
check_type_compatible(uint8 src_type, uint8 dst_type)
|
||||
{
|
||||
if (src_type == dst_type) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ext i1 to i32 */
|
||||
if (src_type == VALUE_TYPE_I1 && dst_type == VALUE_TYPE_I32) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* i32 <==> func.ref, i32 <==> extern.ref */
|
||||
if (src_type == VALUE_TYPE_I32
|
||||
&& (dst_type == VALUE_TYPE_EXTERNREF
|
||||
|| dst_type == VALUE_TYPE_FUNCREF)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dst_type == VALUE_TYPE_I32
|
||||
&& (src_type == VALUE_TYPE_FUNCREF
|
||||
|| src_type == VALUE_TYPE_EXTERNREF)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#define CHECK_STACK() do { \
|
||||
if (!func_ctx->block_stack.block_list_end) { \
|
||||
aot_set_last_error("WASM block stack underflow."); \
|
||||
@ -119,11 +147,8 @@ typedef enum FloatArithmetic {
|
||||
CHECK_STACK(); \
|
||||
aot_value = aot_value_stack_pop \
|
||||
(&func_ctx->block_stack.block_list_end->value_stack); \
|
||||
if ((value_type != VALUE_TYPE_I32 \
|
||||
&& aot_value->type != value_type) \
|
||||
|| (value_type == VALUE_TYPE_I32 \
|
||||
&& (aot_value->type != VALUE_TYPE_I32 \
|
||||
&& aot_value->type != VALUE_TYPE_I1))) { \
|
||||
if (!check_type_compatible(aot_value->type, \
|
||||
value_type)) { \
|
||||
aot_set_last_error("invalid WASM stack data type."); \
|
||||
wasm_runtime_free(aot_value); \
|
||||
goto fail; \
|
||||
@ -131,12 +156,23 @@ typedef enum FloatArithmetic {
|
||||
if (aot_value->type == value_type) \
|
||||
llvm_value = aot_value->value; \
|
||||
else { \
|
||||
bh_assert(aot_value->type == VALUE_TYPE_I1); \
|
||||
if (!(llvm_value = LLVMBuildZExt(comp_ctx->builder, \
|
||||
aot_value->value, I32_TYPE, "i1toi32"))) { \
|
||||
aot_set_last_error("invalid WASM stack data type.");\
|
||||
wasm_runtime_free(aot_value); \
|
||||
goto fail; \
|
||||
if (aot_value->type == VALUE_TYPE_I1) { \
|
||||
if (!(llvm_value = LLVMBuildZExt(comp_ctx->builder, \
|
||||
aot_value->value, I32_TYPE, "i1toi32"))) { \
|
||||
aot_set_last_error("invalid WASM stack " \
|
||||
"data type."); \
|
||||
wasm_runtime_free(aot_value); \
|
||||
goto fail; \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
bh_assert(aot_value->type == VALUE_TYPE_I32 \
|
||||
|| aot_value->type == VALUE_TYPE_FUNCREF \
|
||||
|| aot_value->type == VALUE_TYPE_EXTERNREF); \
|
||||
bh_assert(value_type == VALUE_TYPE_I32 \
|
||||
|| value_type == VALUE_TYPE_FUNCREF \
|
||||
|| value_type == VALUE_TYPE_EXTERNREF); \
|
||||
llvm_value = aot_value->value; \
|
||||
} \
|
||||
} \
|
||||
wasm_runtime_free(aot_value); \
|
||||
@ -147,6 +183,8 @@ typedef enum FloatArithmetic {
|
||||
#define POP_F32(v) POP(v, VALUE_TYPE_F32)
|
||||
#define POP_F64(v) POP(v, VALUE_TYPE_F64)
|
||||
#define POP_V128(v) POP(v, VALUE_TYPE_V128)
|
||||
#define POP_FUNCREF(v) POP(v, VALUE_TYPE_FUNCREF)
|
||||
#define POP_EXTERNREF(v) POP(v, VALUE_TYPE_EXTERNREF)
|
||||
|
||||
#define POP_COND(llvm_value) do { \
|
||||
AOTValue *aot_value; \
|
||||
@ -198,6 +236,8 @@ typedef enum FloatArithmetic {
|
||||
#define PUSH_F64(v) PUSH(v, VALUE_TYPE_F64)
|
||||
#define PUSH_V128(v) PUSH(v, VALUE_TYPE_V128)
|
||||
#define PUSH_COND(v) PUSH(v, VALUE_TYPE_I1)
|
||||
#define PUSH_FUNCREF(v) PUSH(v, VALUE_TYPE_FUNCREF)
|
||||
#define PUSH_EXTERNREF(v) PUSH(v, VALUE_TYPE_EXTERNREF)
|
||||
|
||||
#define TO_LLVM_TYPE(wasm_type) \
|
||||
wasm_type_to_llvm_type(&comp_ctx->basic_types, wasm_type)
|
||||
@ -217,6 +257,8 @@ typedef enum FloatArithmetic {
|
||||
#define INT64_PTR_TYPE comp_ctx->basic_types.int64_ptr_type
|
||||
#define F32_PTR_TYPE comp_ctx->basic_types.float32_ptr_type
|
||||
#define F64_PTR_TYPE comp_ctx->basic_types.float64_ptr_type
|
||||
#define FUNC_REF_TYPE comp_ctx->basic_types.funcref_type
|
||||
#define EXTERN_REF_TYPE comp_ctx->basic_types.externref_type
|
||||
|
||||
#define I32_CONST(v) LLVMConstInt(I32_TYPE, v, true)
|
||||
#define I64_CONST(v) LLVMConstInt(I64_TYPE, v, true)
|
||||
@ -263,6 +305,8 @@ typedef enum FloatArithmetic {
|
||||
#define V128_f32x4_ZERO (comp_ctx->llvm_consts.f32x4_vec_zero)
|
||||
#define V128_f64x2_ZERO (comp_ctx->llvm_consts.f64x2_vec_zero)
|
||||
|
||||
#define REF_NULL (comp_ctx->llvm_consts.i32_neg_one)
|
||||
|
||||
#define TO_V128_i8x16(v) LLVMBuildBitCast(comp_ctx->builder, v, \
|
||||
V128_i8x16_TYPE, "i8x16_val")
|
||||
#define TO_V128_i16x8(v) LLVMBuildBitCast(comp_ctx->builder, v, \
|
||||
@ -283,6 +327,36 @@ typedef enum FloatArithmetic {
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define GET_AOT_FUNCTION(name, argc) do { \
|
||||
if (!(func_type = LLVMFunctionType(ret_type, param_types, \
|
||||
argc, false))) { \
|
||||
aot_set_last_error("llvm add function type failed."); \
|
||||
return false; \
|
||||
} \
|
||||
if (comp_ctx->is_jit_mode) { \
|
||||
/* JIT mode, call the function directly */ \
|
||||
if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { \
|
||||
aot_set_last_error("llvm add pointer type failed."); \
|
||||
return false; \
|
||||
} \
|
||||
if (!(value = I64_CONST((uint64)(uintptr_t)name)) \
|
||||
|| !(func = LLVMConstIntToPtr(value, func_ptr_type))) { \
|
||||
aot_set_last_error("create LLVM value failed."); \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
char *func_name = #name; \
|
||||
/* AOT mode, delcare the function */ \
|
||||
if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name)) \
|
||||
&& !(func = LLVMAddFunction(comp_ctx->module, \
|
||||
func_name, func_type))) { \
|
||||
aot_set_last_error("llvm add function failed."); \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
bool
|
||||
aot_compile_wasm(AOTCompContext *comp_ctx);
|
||||
|
||||
|
||||
@ -183,9 +183,13 @@ get_mem_info_size(AOTCompData *comp_data)
|
||||
static uint32
|
||||
get_table_init_data_size(AOTTableInitData *table_init_data)
|
||||
{
|
||||
/* table_index + init expr type (4 bytes) + init expr value (8 bytes)
|
||||
+ func index count (4 bytes) + func indexes */
|
||||
return (uint32)(sizeof(uint32) + sizeof(uint32)
|
||||
/*
|
||||
* mode (4 bytes), elem_type (4 bytes), do not need is_dropped field
|
||||
*
|
||||
* table_index(4 bytes) + init expr type (4 bytes) + init expr value (8 bytes)
|
||||
* + func index count (4 bytes) + func indexes
|
||||
*/
|
||||
return (uint32)(sizeof(uint32) * 2 + sizeof(uint32) + sizeof(uint32)
|
||||
+ sizeof(uint64) + sizeof(uint32)
|
||||
+ sizeof(uint32) * table_init_data->func_index_count);
|
||||
}
|
||||
@ -194,9 +198,24 @@ static uint32
|
||||
get_table_init_data_list_size(AOTTableInitData **table_init_data_list,
|
||||
uint32 table_init_data_count)
|
||||
{
|
||||
/*
|
||||
* ------------------------------
|
||||
* | table_init_data_count
|
||||
* ------------------------------
|
||||
* | | U32 mode
|
||||
* | AOTTableInitData[N] | U32 elem_type
|
||||
* | | U32 table_index
|
||||
* | | U32 offset.init_expr_type
|
||||
* | | U64 offset.u.i64
|
||||
* | | U32 func_index_count
|
||||
* | | U32[func_index_count]
|
||||
* ------------------------------
|
||||
*/
|
||||
AOTTableInitData **table_init_data = table_init_data_list;
|
||||
uint32 size = 0, i;
|
||||
|
||||
size = (uint32)sizeof(uint32);
|
||||
|
||||
for (i = 0; i < table_init_data_count; i++, table_init_data++) {
|
||||
size = align_uint(size, 4);
|
||||
size += get_table_init_data_size(*table_init_data);
|
||||
@ -207,27 +226,66 @@ get_table_init_data_list_size(AOTTableInitData **table_init_data_list,
|
||||
static uint32
|
||||
get_import_table_size(AOTCompData *comp_data)
|
||||
{
|
||||
/* currently we only emit import_table_count = 0 */
|
||||
return sizeof(uint32);
|
||||
/*
|
||||
* ------------------------------
|
||||
* | import_table_count
|
||||
* ------------------------------
|
||||
* | | U32 table_init_size
|
||||
* | | ----------------------
|
||||
* | AOTImpotTable[N] | U32 table_init_size
|
||||
* | | ----------------------
|
||||
* | | U32 possible_grow (convenient than U8)
|
||||
* ------------------------------
|
||||
*/
|
||||
return (uint32)(sizeof(uint32)
|
||||
+ comp_data->import_table_count
|
||||
* (sizeof(uint32) * 3));
|
||||
}
|
||||
|
||||
static uint32
|
||||
get_table_size(AOTCompData *comp_data)
|
||||
{
|
||||
/* table_count + table_count * (elem_type + table_flags
|
||||
* + init_size + max_size) */
|
||||
/*
|
||||
* ------------------------------
|
||||
* | table_count
|
||||
* ------------------------------
|
||||
* | | U32 elem_type
|
||||
* | AOTTable[N] | U32 table_flags
|
||||
* | | U32 table_init_size
|
||||
* | | U32 table_max_size
|
||||
* | | U32 possible_grow (convenient than U8)
|
||||
* ------------------------------
|
||||
*/
|
||||
return (uint32)(sizeof(uint32)
|
||||
+ comp_data->table_count * sizeof(uint32) * 4);
|
||||
+ comp_data->table_count
|
||||
* (sizeof(uint32) * 5));
|
||||
}
|
||||
|
||||
static uint32
|
||||
get_table_info_size(AOTCompData *comp_data)
|
||||
{
|
||||
/* import_table size + table_size
|
||||
+ init data count + init data list */
|
||||
return get_import_table_size(comp_data)
|
||||
+ get_table_size(comp_data)
|
||||
+ (uint32)sizeof(uint32)
|
||||
/*
|
||||
* ------------------------------
|
||||
* | import_table_count
|
||||
* ------------------------------
|
||||
* |
|
||||
* | AOTImportTable[import_table_count]
|
||||
* |
|
||||
* ------------------------------
|
||||
* | table_count
|
||||
* ------------------------------
|
||||
* |
|
||||
* | AOTTable[table_count]
|
||||
* |
|
||||
* ------------------------------
|
||||
* | table_init_data_count
|
||||
* ------------------------------
|
||||
* |
|
||||
* | AOTTableInitData*[table_init_data_count]
|
||||
* |
|
||||
* ------------------------------
|
||||
*/
|
||||
return get_import_table_size(comp_data) + get_table_size(comp_data)
|
||||
+ get_table_init_data_list_size(comp_data->table_init_data_list,
|
||||
comp_data->table_init_data_count);
|
||||
}
|
||||
@ -1014,10 +1072,18 @@ aot_emit_table_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
|
||||
|
||||
*p_offset = offset = align_uint(offset, 4);
|
||||
|
||||
/* Emit import table count, only emit 0 currently.
|
||||
TODO: emit the actual import table count and
|
||||
the full import table info. */
|
||||
EMIT_U32(0);
|
||||
/* Emit import table count */
|
||||
EMIT_U32(comp_data->import_table_count);
|
||||
/* Emit table items */
|
||||
for (i = 0; i < comp_data->import_table_count; i++) {
|
||||
/* TODO:
|
||||
* EMIT_STR(comp_data->import_tables[i].module_name );
|
||||
* EMIT_STR(comp_data->import_tables[i].table_name);
|
||||
*/
|
||||
EMIT_U32(comp_data->import_tables[i].table_init_size);
|
||||
EMIT_U32(comp_data->import_tables[i].table_max_size);
|
||||
EMIT_U32(comp_data->import_tables[i].possible_grow & 0x000000FF);
|
||||
}
|
||||
|
||||
/* Emit table count */
|
||||
EMIT_U32(comp_data->table_count);
|
||||
@ -1027,6 +1093,7 @@ aot_emit_table_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
|
||||
EMIT_U32(comp_data->tables[i].table_flags);
|
||||
EMIT_U32(comp_data->tables[i].table_init_size);
|
||||
EMIT_U32(comp_data->tables[i].table_max_size);
|
||||
EMIT_U32(comp_data->tables[i].possible_grow & 0x000000FF);
|
||||
}
|
||||
|
||||
/* Emit table init data count */
|
||||
@ -1034,6 +1101,8 @@ aot_emit_table_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
|
||||
/* Emit table init data items */
|
||||
for (i = 0; i < comp_data->table_init_data_count; i++) {
|
||||
offset = align_uint(offset, 4);
|
||||
EMIT_U32(init_datas[i]->mode);
|
||||
EMIT_U32(init_datas[i]->elem_type);
|
||||
EMIT_U32(init_datas[i]->table_index);
|
||||
EMIT_U32(init_datas[i]->offset.init_expr_type);
|
||||
EMIT_U64(init_datas[i]->offset.u.i64);
|
||||
|
||||
@ -616,8 +616,10 @@ aot_compile_op_end(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
/* Handle block result values */
|
||||
CREATE_RESULT_VALUE_PHIS(block);
|
||||
for (i = 0; i < block->result_count; i++) {
|
||||
value = NULL;
|
||||
result_index = block->result_count - 1 - i;
|
||||
POP(value, block->result_types[result_index]);
|
||||
bh_assert(value);
|
||||
ADD_TO_RESULT_PHIS(block, value, result_index);
|
||||
}
|
||||
|
||||
|
||||
@ -6,38 +6,9 @@
|
||||
#include "aot_emit_function.h"
|
||||
#include "aot_emit_exception.h"
|
||||
#include "aot_emit_control.h"
|
||||
#include "aot_emit_table.h"
|
||||
#include "../aot/aot_runtime.h"
|
||||
|
||||
#define GET_AOT_FUNCTION(name, argc) do { \
|
||||
if (!(func_type = LLVMFunctionType(ret_type, param_types, \
|
||||
argc, false))) { \
|
||||
aot_set_last_error("llvm add function type failed."); \
|
||||
return false; \
|
||||
} \
|
||||
if (comp_ctx->is_jit_mode) { \
|
||||
/* JIT mode, call the function directly */ \
|
||||
if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { \
|
||||
aot_set_last_error("llvm add pointer type failed."); \
|
||||
return false; \
|
||||
} \
|
||||
if (!(value = I64_CONST((uint64)(uintptr_t)name)) \
|
||||
|| !(func = LLVMConstIntToPtr(value, func_ptr_type))) { \
|
||||
aot_set_last_error("create LLVM value failed."); \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
char *func_name = #name; \
|
||||
/* AOT mode, delcare the function */ \
|
||||
if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name)) \
|
||||
&& !(func = LLVMAddFunction(comp_ctx->module, \
|
||||
func_name, func_type))) { \
|
||||
aot_set_last_error("llvm add function failed."); \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ADD_BASIC_BLOCK(block, name) do { \
|
||||
if (!(block = LLVMAppendBasicBlockInContext(comp_ctx->context, \
|
||||
func_ctx->func, \
|
||||
@ -640,8 +611,8 @@ fail:
|
||||
|
||||
static bool
|
||||
call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
AOTFuncType *aot_func_type,
|
||||
LLVMValueRef func_type_idx, LLVMValueRef table_elem_idx,
|
||||
AOTFuncType *aot_func_type, LLVMValueRef func_type_idx,
|
||||
LLVMValueRef table_idx, LLVMValueRef table_elem_idx,
|
||||
LLVMTypeRef *param_types, LLVMValueRef *param_values,
|
||||
uint32 param_count, uint32 param_cell_num,
|
||||
uint32 result_count, uint8 *wasm_ret_types,
|
||||
@ -656,10 +627,11 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
|
||||
/* prepare function type of aot_call_indirect */
|
||||
func_param_types[0] = comp_ctx->exec_env_type; /* exec_env */
|
||||
func_param_types[1] = I32_TYPE; /* table_elem_idx */
|
||||
func_param_types[2] = I32_TYPE; /* argc */
|
||||
func_param_types[3] = INT32_PTR_TYPE; /* argv */
|
||||
if (!(func_type = LLVMFunctionType(INT8_TYPE, func_param_types, 4, false))) {
|
||||
func_param_types[1] = I32_TYPE; /* table_idx */
|
||||
func_param_types[2] = I32_TYPE; /* table_elem_idx */
|
||||
func_param_types[3] = I32_TYPE; /* argc */
|
||||
func_param_types[4] = INT32_PTR_TYPE; /* argv */
|
||||
if (!(func_type = LLVMFunctionType(INT8_TYPE, func_param_types, 5, false))) {
|
||||
aot_set_last_error("llvm add function type failed.");
|
||||
return false;
|
||||
}
|
||||
@ -722,18 +694,19 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
}
|
||||
|
||||
func_param_values[0] = func_ctx->exec_env;
|
||||
func_param_values[1] = table_elem_idx;
|
||||
func_param_values[2] = I32_CONST(param_cell_num);
|
||||
func_param_values[3] = func_ctx->argv_buf;
|
||||
func_param_values[1] = table_idx;
|
||||
func_param_values[2] = table_elem_idx;
|
||||
func_param_values[3] = I32_CONST(param_cell_num);
|
||||
func_param_values[4] = func_ctx->argv_buf;
|
||||
|
||||
if (!func_param_values[2]) {
|
||||
if (!func_param_values[3]) {
|
||||
aot_set_last_error("llvm create const failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* call aot_call_indirect() function */
|
||||
if (!(res = LLVMBuildCall(comp_ctx->builder, func,
|
||||
func_param_values, 4, "res"))) {
|
||||
func_param_values, 5, "res"))) {
|
||||
aot_set_last_error("llvm build call failed.");
|
||||
return false;
|
||||
}
|
||||
@ -771,10 +744,10 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
|
||||
bool
|
||||
aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 type_idx)
|
||||
uint32 type_idx, uint32 tbl_idx)
|
||||
{
|
||||
AOTFuncType *func_type;
|
||||
LLVMValueRef elem_idx, table_elem, func_idx;
|
||||
LLVMValueRef tbl_idx_value, elem_idx, table_elem, func_idx;
|
||||
LLVMValueRef ftype_idx_ptr, ftype_idx, ftype_idx_const;
|
||||
LLVMValueRef cmp_elem_idx, cmp_func_idx, cmp_ftype_idx;
|
||||
LLVMValueRef func, func_ptr, table_size_const;
|
||||
@ -787,8 +760,9 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
LLVMBasicBlockRef check_elem_idx_succ, check_ftype_idx_succ;
|
||||
LLVMBasicBlockRef check_func_idx_succ, block_return, block_curr;
|
||||
LLVMBasicBlockRef block_call_import, block_call_non_import;
|
||||
LLVMValueRef offset;
|
||||
uint32 total_param_count, func_param_count, func_result_count;
|
||||
uint32 table_init_size = 0, ext_cell_num, param_cell_num, i, j;
|
||||
uint32 ext_cell_num, param_cell_num, i, j;
|
||||
uint8 wasm_ret_type, *wasm_ret_types;
|
||||
uint64 total_size;
|
||||
char buf[32];
|
||||
@ -818,20 +792,31 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
|
||||
POP_I32(elem_idx);
|
||||
|
||||
if (comp_ctx->comp_data->import_table_count > 0) {
|
||||
table_init_size = comp_ctx->comp_data->import_tables[0]
|
||||
.table_init_size;
|
||||
}
|
||||
else if (comp_ctx->comp_data->table_count > 0) {
|
||||
table_init_size = comp_ctx->comp_data->tables[0]
|
||||
.table_init_size;
|
||||
}
|
||||
else {
|
||||
aot_set_last_error("table index out of range");
|
||||
/* get the cur size of the table instance */
|
||||
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
|
||||
+ offsetof(AOTTableInstance, cur_size)))) {
|
||||
HANDLE_FAILURE("LLVMConstInt");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(table_size_const =
|
||||
LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst, &offset, 1,
|
||||
"cur_size_i8p"))) {
|
||||
HANDLE_FAILURE("LLVMBuildGEP");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(table_size_const =
|
||||
LLVMBuildBitCast(comp_ctx->builder, table_size_const,
|
||||
INT32_PTR_TYPE, "cur_siuze_i32p"))) {
|
||||
HANDLE_FAILURE("LLVMBuildBitCast");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(table_size_const = LLVMBuildLoad(comp_ctx->builder, table_size_const, "cur_size"))) {
|
||||
HANDLE_FAILURE("LLVMBuildLoad");
|
||||
goto fail;
|
||||
}
|
||||
table_size_const = I32_CONST(table_init_size);
|
||||
CHECK_LLVM_CONST(table_size_const);
|
||||
|
||||
/* Check if (uint32)elem index >= table size */
|
||||
if (!(cmp_elem_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE,
|
||||
@ -857,14 +842,32 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
true, cmp_elem_idx, check_elem_idx_succ)))
|
||||
goto fail;
|
||||
|
||||
/* Load function index */
|
||||
if (!(table_elem = LLVMBuildInBoundsGEP(comp_ctx->builder,
|
||||
func_ctx->table_base,
|
||||
&elem_idx, 1, "table_elem"))) {
|
||||
/* load data as i32* */
|
||||
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
|
||||
+ offsetof(AOTTableInstance, data)))) {
|
||||
HANDLE_FAILURE("LLVMConstInt");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(table_elem = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst,
|
||||
&offset, 1, "table_elem_i8p"))) {
|
||||
aot_set_last_error("llvm build add failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(table_elem = LLVMBuildBitCast(comp_ctx->builder, table_elem,
|
||||
INT32_PTR_TYPE, "table_elem_i32p"))) {
|
||||
HANDLE_FAILURE("LLVMBuildBitCast");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Load function index */
|
||||
if (!(table_elem = LLVMBuildGEP(comp_ctx->builder, table_elem, &elem_idx,
|
||||
1, "table_elem"))) {
|
||||
HANDLE_FAILURE("LLVMBuildNUWAdd");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(func_idx = LLVMBuildLoad(comp_ctx->builder,
|
||||
table_elem, "func_idx"))) {
|
||||
aot_set_last_error("llvm build load failed.");
|
||||
@ -1118,8 +1121,15 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
param_cell_num = func_type->param_cell_num;
|
||||
wasm_ret_types = func_type->types + func_type->param_count;
|
||||
|
||||
tbl_idx_value = I32_CONST(tbl_idx);
|
||||
if (!tbl_idx_value) {
|
||||
aot_set_last_error("llvm create const failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!call_aot_call_indirect_func(comp_ctx, func_ctx,
|
||||
func_type, ftype_idx, elem_idx,
|
||||
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,
|
||||
@ -1240,3 +1250,56 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_ref_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
{
|
||||
PUSH_I32(REF_NULL);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_ref_is_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
{
|
||||
LLVMValueRef lhs, res;
|
||||
|
||||
POP_I32(lhs);
|
||||
|
||||
if (!(res = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ, lhs, REF_NULL,
|
||||
"cmp_w_null"))) {
|
||||
HANDLE_FAILURE("LLVMBuildICmp");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(res = LLVMBuildZExt(comp_ctx->builder, res, I32_TYPE, "r_i"))) {
|
||||
HANDLE_FAILURE("LLVMBuildZExt");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
PUSH_I32(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_ref_func(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 func_idx)
|
||||
{
|
||||
LLVMValueRef ref_idx;
|
||||
|
||||
if (!(ref_idx = I32_CONST(func_idx))) {
|
||||
HANDLE_FAILURE("LLVMConstInt");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
PUSH_I32(ref_idx);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -17,9 +17,21 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 func_idx, bool tail_call);
|
||||
|
||||
bool
|
||||
aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 type_idx);
|
||||
aot_compile_op_call_indirect(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 type_idx,
|
||||
uint32 tbl_idx);
|
||||
|
||||
bool
|
||||
aot_compile_op_ref_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
|
||||
bool
|
||||
aot_compile_op_ref_is_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
|
||||
bool
|
||||
aot_compile_op_ref_func(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 func_idx);
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
@ -657,7 +657,7 @@ aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
|
||||
POP_I32(delta);
|
||||
|
||||
/* Function type of wasm_runtime_enlarge_memory() */
|
||||
/* Function type of aot_enlarge_memory() */
|
||||
param_types[0] = INT8_PTR_TYPE;
|
||||
param_types[1] = I32_TYPE;
|
||||
ret_type = INT8_TYPE;
|
||||
@ -673,14 +673,14 @@ aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
aot_set_last_error("llvm add pointer type failed.");
|
||||
return false;
|
||||
}
|
||||
if (!(value = I64_CONST((uint64)(uintptr_t)wasm_runtime_enlarge_memory))
|
||||
if (!(value = I64_CONST((uint64)(uintptr_t)aot_enlarge_memory))
|
||||
|| !(func = LLVMConstIntToPtr(value, func_ptr_type))) {
|
||||
aot_set_last_error("create LLVM value failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
char *func_name = "wasm_runtime_enlarge_memory";
|
||||
char *func_name = "aot_enlarge_memory";
|
||||
/* AOT mode, delcare the function */
|
||||
if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name))
|
||||
&& !(func = LLVMAddFunction(comp_ctx->module,
|
||||
@ -690,7 +690,7 @@ aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
}
|
||||
}
|
||||
|
||||
/* Call function wasm_runtime_enlarge_memory() */
|
||||
/* Call function aot_enlarge_memory() */
|
||||
param_values[0] = func_ctx->aot_inst;
|
||||
param_values[1] = delta;
|
||||
if (!(ret_value = LLVMBuildCall(comp_ctx->builder, func,
|
||||
@ -715,35 +715,6 @@ fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
#define GET_AOT_FUNCTION(name, argc) do { \
|
||||
if (!(func_type = LLVMFunctionType(ret_type, param_types, \
|
||||
argc, false))) { \
|
||||
aot_set_last_error("llvm add function type failed."); \
|
||||
return false; \
|
||||
} \
|
||||
if (comp_ctx->is_jit_mode) { \
|
||||
/* JIT mode, call the function directly */ \
|
||||
if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { \
|
||||
aot_set_last_error("llvm add pointer type failed."); \
|
||||
return false; \
|
||||
} \
|
||||
if (!(value = I64_CONST((uint64)(uintptr_t)name)) \
|
||||
|| !(func = LLVMConstIntToPtr(value, func_ptr_type))) { \
|
||||
aot_set_last_error("create LLVM value failed."); \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
char *func_name = #name; \
|
||||
/* AOT mode, delcare the function */ \
|
||||
if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name)) \
|
||||
&& !(func = LLVMAddFunction(comp_ctx->module, \
|
||||
func_name, func_type))) { \
|
||||
aot_set_last_error("llvm add function failed."); \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
|
||||
|
||||
@ -45,11 +45,18 @@ pop_value_from_wasm_stack(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
|
||||
wasm_runtime_free(aot_value);
|
||||
|
||||
if ((is_32
|
||||
&& (type != VALUE_TYPE_I32 && type != VALUE_TYPE_F32
|
||||
&& type != VALUE_TYPE_V128))
|
||||
|| (!is_32
|
||||
&& (type != VALUE_TYPE_I64 && type != VALUE_TYPE_F64))) {
|
||||
/* is_32: i32, f32, ref.func, ref.extern, v128 */
|
||||
if (is_32
|
||||
&& !(type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32
|
||||
|| type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF
|
||||
|| type == VALUE_TYPE_V128)) {
|
||||
aot_set_last_error("invalid WASM stack data type.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* !is_32: i64, f64 */
|
||||
if (!is_32
|
||||
&& !(type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64)) {
|
||||
aot_set_last_error("invalid WASM stack data type.");
|
||||
return false;
|
||||
}
|
||||
|
||||
487
core/iwasm/compilation/aot_emit_table.c
Normal file
487
core/iwasm/compilation/aot_emit_table.c
Normal file
@ -0,0 +1,487 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "aot_emit_table.h"
|
||||
#include "aot_emit_exception.h"
|
||||
#include "../aot/aot_runtime.h"
|
||||
|
||||
|
||||
uint64
|
||||
get_tbl_inst_offset(const AOTCompContext *comp_ctx,
|
||||
const AOTFuncContext *func_ctx,
|
||||
uint32 tbl_idx)
|
||||
{
|
||||
uint64 offset = 0, i = 0;
|
||||
AOTImportTable *imp_tbls = comp_ctx->comp_data->import_tables;
|
||||
AOTTable *tbls = comp_ctx->comp_data->tables;
|
||||
|
||||
/* from the head of AOTModuleInstance */
|
||||
offset =
|
||||
offsetof(AOTModuleInstance, global_table_data.bytes)
|
||||
+ (uint64)comp_ctx->comp_data->memory_count * sizeof(AOTMemoryInstance)
|
||||
+ comp_ctx->comp_data->global_data_size;
|
||||
|
||||
while (i < tbl_idx && i < comp_ctx->comp_data->import_table_count) {
|
||||
offset += offsetof(AOTTableInstance, data);
|
||||
offset += sizeof(uint32) * aot_get_imp_tbl_data_slots(imp_tbls + i);
|
||||
++i;
|
||||
}
|
||||
|
||||
if (i == tbl_idx) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
tbl_idx -= comp_ctx->comp_data->import_table_count;
|
||||
i -= comp_ctx->comp_data->import_table_count;
|
||||
while (i < tbl_idx && i < comp_ctx->comp_data->table_count) {
|
||||
offset += offsetof(AOTTableInstance, data);
|
||||
offset += sizeof(uint32) * aot_get_tbl_data_slots(tbls + i);
|
||||
++i;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
|
||||
LLVMValueRef
|
||||
aot_compile_get_tbl_inst(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 tbl_idx)
|
||||
{
|
||||
LLVMValueRef offset, tbl_inst;
|
||||
|
||||
if (!(offset =
|
||||
I64_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)))) {
|
||||
HANDLE_FAILURE("LLVMConstInt");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(tbl_inst = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst,
|
||||
&offset, 1, "tbl_inst"))) {
|
||||
HANDLE_FAILURE("LLVMBuildGEP");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return tbl_inst;
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_elem_drop(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 tbl_seg_idx)
|
||||
{
|
||||
LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type;
|
||||
LLVMValueRef param_values[2], ret_value, func, value;
|
||||
|
||||
/* void aot_drop_table_seg(AOTModuleInstance *, uint32 ) */
|
||||
param_types[0] = INT8_PTR_TYPE;
|
||||
param_types[1] = I32_TYPE;
|
||||
ret_type = VOID_TYPE;
|
||||
|
||||
GET_AOT_FUNCTION(aot_drop_table_seg, 2);
|
||||
|
||||
param_values[0] = func_ctx->aot_inst;
|
||||
if (!(param_values[1] = I32_CONST(tbl_seg_idx))) {
|
||||
HANDLE_FAILURE("LLVMConstInt");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* "" means return void */
|
||||
if (!(ret_value =
|
||||
LLVMBuildCall(comp_ctx->builder, func, param_values, 2, ""))) {
|
||||
HANDLE_FAILURE("LLVMBuildCall");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
aot_check_table_access(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 tbl_idx,
|
||||
LLVMValueRef elem_idx)
|
||||
{
|
||||
LLVMValueRef offset, tbl_sz, cmp_elem_idx;
|
||||
LLVMBasicBlockRef check_elem_idx_succ;
|
||||
|
||||
/* get the cur size of the table instance */
|
||||
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
|
||||
+ offsetof(AOTTableInstance, cur_size)))) {
|
||||
HANDLE_FAILURE("LLVMConstInt");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(tbl_sz = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst, &offset,
|
||||
1, "cur_size_i8p"))) {
|
||||
HANDLE_FAILURE("LLVMBuildGEP");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(tbl_sz = LLVMBuildBitCast(comp_ctx->builder, tbl_sz, INT32_PTR_TYPE,
|
||||
"cur_siuze_i32p"))) {
|
||||
HANDLE_FAILURE("LLVMBuildBitCast");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(tbl_sz = LLVMBuildLoad(comp_ctx->builder, tbl_sz, "cur_size"))) {
|
||||
HANDLE_FAILURE("LLVMBuildLoad");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check if (uint32)elem index >= table size */
|
||||
if (!(cmp_elem_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, elem_idx,
|
||||
tbl_sz, "cmp_elem_idx"))) {
|
||||
aot_set_last_error("llvm build icmp failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Throw exception if elem index >= table size */
|
||||
if (!(check_elem_idx_succ = LLVMAppendBasicBlockInContext(
|
||||
comp_ctx->context, func_ctx->func, "check_elem_idx_succ"))) {
|
||||
aot_set_last_error("llvm add basic block failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
LLVMMoveBasicBlockAfter(check_elem_idx_succ,
|
||||
LLVMGetInsertBlock(comp_ctx->builder));
|
||||
|
||||
if (!(aot_emit_exception(comp_ctx, func_ctx,
|
||||
EXCE_OUT_OF_BOUNDS_TABLE_ACCESS, true,
|
||||
cmp_elem_idx, check_elem_idx_succ)))
|
||||
goto fail;
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_table_get(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 tbl_idx)
|
||||
{
|
||||
LLVMValueRef elem_idx, offset, table_elem, func_idx;
|
||||
|
||||
POP_I32(elem_idx);
|
||||
|
||||
if (!aot_check_table_access(comp_ctx, func_ctx, tbl_idx, elem_idx)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* load data as i32* */
|
||||
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
|
||||
+ offsetof(AOTTableInstance, data)))) {
|
||||
HANDLE_FAILURE("LLVMConstInt");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(table_elem = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst,
|
||||
&offset, 1, "table_elem_i8p"))) {
|
||||
aot_set_last_error("llvm build add failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(table_elem = LLVMBuildBitCast(comp_ctx->builder, table_elem,
|
||||
INT32_PTR_TYPE, "table_elem_i32p"))) {
|
||||
HANDLE_FAILURE("LLVMBuildBitCast");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Load function index */
|
||||
if (!(table_elem = LLVMBuildGEP(comp_ctx->builder, table_elem, &elem_idx,
|
||||
1, "table_elem"))) {
|
||||
HANDLE_FAILURE("LLVMBuildNUWAdd");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(func_idx =
|
||||
LLVMBuildLoad(comp_ctx->builder, table_elem, "func_idx"))) {
|
||||
HANDLE_FAILURE("LLVMBuildLoad");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
PUSH_I32(func_idx);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_table_set(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 tbl_idx)
|
||||
{
|
||||
LLVMValueRef val, elem_idx, offset, table_elem;
|
||||
|
||||
POP_I32(val);
|
||||
POP_I32(elem_idx);
|
||||
|
||||
if (!aot_check_table_access(comp_ctx, func_ctx, tbl_idx, elem_idx)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* load data as i32* */
|
||||
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
|
||||
+ offsetof(AOTTableInstance, data)))) {
|
||||
HANDLE_FAILURE("LLVMConstInt");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(table_elem = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst,
|
||||
&offset, 1, "table_elem_i8p"))) {
|
||||
HANDLE_FAILURE("LLVMBuildGEP");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(table_elem = LLVMBuildBitCast(comp_ctx->builder, table_elem,
|
||||
INT32_PTR_TYPE, "table_elem_i32p"))) {
|
||||
HANDLE_FAILURE("LLVMBuildBitCast");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Load function index */
|
||||
if (!(table_elem = LLVMBuildGEP(comp_ctx->builder, table_elem, &elem_idx,
|
||||
1, "table_elem"))) {
|
||||
HANDLE_FAILURE("LLVMBuildGEP");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(LLVMBuildStore(comp_ctx->builder, val, table_elem))) {
|
||||
HANDLE_FAILURE("LLVMBuildStore");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_table_init(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 tbl_idx,
|
||||
uint32 tbl_seg_idx)
|
||||
|
||||
{
|
||||
LLVMValueRef func, param_values[6], value;
|
||||
LLVMTypeRef param_types[6], ret_type, func_type, func_ptr_type;
|
||||
|
||||
param_types[0] = INT8_PTR_TYPE;
|
||||
param_types[1] = I32_TYPE;
|
||||
param_types[2] = I32_TYPE;
|
||||
param_types[3] = I32_TYPE;
|
||||
param_types[4] = I32_TYPE;
|
||||
param_types[5] = I32_TYPE;
|
||||
ret_type = VOID_TYPE;
|
||||
|
||||
GET_AOT_FUNCTION(aot_table_init, 6);
|
||||
|
||||
param_values[0] = func_ctx->aot_inst;
|
||||
|
||||
if (!(param_values[1] = I32_CONST(tbl_idx))) {
|
||||
HANDLE_FAILURE("LLVMConstInt");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(param_values[2] = I32_CONST(tbl_seg_idx))) {
|
||||
HANDLE_FAILURE("LLVMConstInt");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* n */
|
||||
POP_I32(param_values[3]);
|
||||
/* s */
|
||||
POP_I32(param_values[4]);
|
||||
/* d */
|
||||
POP_I32(param_values[5]);
|
||||
|
||||
/* "" means return void */
|
||||
if (!(LLVMBuildCall(comp_ctx->builder, func, param_values, 6, ""))) {
|
||||
HANDLE_FAILURE("LLVMBuildCall");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_table_copy(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 src_tbl_idx,
|
||||
uint32 dst_tbl_idx)
|
||||
{
|
||||
LLVMTypeRef param_types[6], ret_type, func_type, func_ptr_type;
|
||||
LLVMValueRef func, param_values[6], value;
|
||||
|
||||
param_types[0] = INT8_PTR_TYPE;
|
||||
param_types[1] = I32_TYPE;
|
||||
param_types[2] = I32_TYPE;
|
||||
param_types[3] = I32_TYPE;
|
||||
param_types[4] = I32_TYPE;
|
||||
param_types[5] = I32_TYPE;
|
||||
ret_type = VOID_TYPE;
|
||||
|
||||
GET_AOT_FUNCTION(aot_table_copy, 6);
|
||||
|
||||
param_values[0] = func_ctx->aot_inst;
|
||||
|
||||
if (!(param_values[1] = I32_CONST(src_tbl_idx))) {
|
||||
HANDLE_FAILURE("LLVMConstInt");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(param_values[2] = I32_CONST(dst_tbl_idx))) {
|
||||
HANDLE_FAILURE("LLVMConstInt");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* n */
|
||||
POP_I32(param_values[3]);
|
||||
/* s */
|
||||
POP_I32(param_values[4]);
|
||||
/* d */
|
||||
POP_I32(param_values[5]);
|
||||
|
||||
/* "" means return void */
|
||||
if (!(LLVMBuildCall(comp_ctx->builder, func, param_values, 6, ""))) {
|
||||
HANDLE_FAILURE("LLVMBuildCall");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_table_size(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 tbl_idx)
|
||||
{
|
||||
LLVMValueRef offset, tbl_sz;
|
||||
|
||||
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
|
||||
+ offsetof(AOTTableInstance, cur_size)))) {
|
||||
HANDLE_FAILURE("LLVMConstInt");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(tbl_sz = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst, &offset,
|
||||
1, "tbl_sz_ptr_i8"))) {
|
||||
HANDLE_FAILURE("LLVMBuildGEP");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(tbl_sz = LLVMBuildBitCast(comp_ctx->builder, tbl_sz, INT32_PTR_TYPE,
|
||||
"tbl_sz_ptr"))) {
|
||||
HANDLE_FAILURE("LLVMBuildBitCast");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(tbl_sz = LLVMBuildLoad(comp_ctx->builder, tbl_sz, "tbl_sz"))) {
|
||||
HANDLE_FAILURE("LLVMBuildLoad");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
PUSH_I32(tbl_sz);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_table_grow(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 tbl_idx)
|
||||
{
|
||||
LLVMTypeRef param_types[4], ret_type, func_type, func_ptr_type;
|
||||
LLVMValueRef func, param_values[4], ret, value;
|
||||
|
||||
param_types[0] = INT8_PTR_TYPE;
|
||||
param_types[1] = I32_TYPE;
|
||||
param_types[2] = I32_TYPE;
|
||||
param_types[3] = I32_TYPE;
|
||||
ret_type = I32_TYPE;
|
||||
|
||||
GET_AOT_FUNCTION(aot_table_grow, 4);
|
||||
|
||||
param_values[0] = func_ctx->aot_inst;
|
||||
|
||||
if (!(param_values[1] = I32_CONST(tbl_idx))) {
|
||||
HANDLE_FAILURE("LLVMConstInt");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* n */
|
||||
POP_I32(param_values[2]);
|
||||
/* v */
|
||||
POP_I32(param_values[3]);
|
||||
|
||||
if (!(ret = LLVMBuildCall(comp_ctx->builder, func, param_values, 4,
|
||||
"table_grow"))) {
|
||||
HANDLE_FAILURE("LLVMBuildCall");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
PUSH_I32(ret);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_table_fill(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 tbl_idx)
|
||||
{
|
||||
LLVMTypeRef param_types[5], ret_type, func_type, func_ptr_type;
|
||||
LLVMValueRef func, param_values[5], value;
|
||||
|
||||
param_types[0] = INT8_PTR_TYPE;
|
||||
param_types[1] = I32_TYPE;
|
||||
param_types[2] = I32_TYPE;
|
||||
param_types[3] = I32_TYPE;
|
||||
param_types[4] = I32_TYPE;
|
||||
ret_type = VOID_TYPE;
|
||||
|
||||
GET_AOT_FUNCTION(aot_table_fill, 5);
|
||||
|
||||
param_values[0] = func_ctx->aot_inst;
|
||||
|
||||
if (!(param_values[1] = I32_CONST(tbl_idx))) {
|
||||
HANDLE_FAILURE("LLVMConstInt");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* n */
|
||||
POP_I32(param_values[2]);
|
||||
/* v */
|
||||
POP_I32(param_values[3]);
|
||||
/* i */
|
||||
POP_I32(param_values[4]);
|
||||
|
||||
/* "" means return void */
|
||||
if (!(LLVMBuildCall(comp_ctx->builder, func, param_values, 5, ""))) {
|
||||
HANDLE_FAILURE("LLVMBuildCall");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* WASM_ENABLE_REF_TYPES != 0 */
|
||||
71
core/iwasm/compilation/aot_emit_table.h
Normal file
71
core/iwasm/compilation/aot_emit_table.h
Normal file
@ -0,0 +1,71 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _AOT_EMIT_TABLE_H_
|
||||
#define _AOT_EMIT_TABLE_H_
|
||||
|
||||
#include "aot_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool
|
||||
aot_compile_op_elem_drop(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 tbl_seg_idx);
|
||||
|
||||
bool
|
||||
aot_compile_op_table_get(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 tbl_idx);
|
||||
|
||||
bool
|
||||
aot_compile_op_table_set(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 tbl_idx);
|
||||
|
||||
bool
|
||||
aot_compile_op_table_init(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 tbl_idx,
|
||||
uint32 tbl_seg_idx);
|
||||
|
||||
bool
|
||||
aot_compile_op_table_copy(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 src_tbl_idx,
|
||||
uint32 dst_tbl_idx);
|
||||
|
||||
bool
|
||||
aot_compile_op_table_size(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 tbl_idx);
|
||||
|
||||
bool
|
||||
aot_compile_op_table_grow(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 tbl_idx);
|
||||
|
||||
bool
|
||||
aot_compile_op_table_fill(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 tbl_idx);
|
||||
|
||||
uint64
|
||||
get_tbl_inst_offset(const AOTCompContext *comp_ctx,
|
||||
const AOTFuncContext *func_ctx,
|
||||
uint32 tbl_idx);
|
||||
|
||||
LLVMValueRef
|
||||
aot_compile_get_tbl_inst(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint32 tbl_idx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
#endif
|
||||
@ -143,6 +143,8 @@ compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
|
||||
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:
|
||||
@ -158,7 +160,7 @@ compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
ptr_type = comp_ctx->basic_types.v128_ptr_type;
|
||||
break;
|
||||
default:
|
||||
bh_assert(0);
|
||||
bh_assert("unknown type");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -14,6 +14,8 @@ wasm_type_to_llvm_type(AOTLLVMTypes *llvm_types, uint8 wasm_type)
|
||||
{
|
||||
switch (wasm_type) {
|
||||
case VALUE_TYPE_I32:
|
||||
case VALUE_TYPE_FUNCREF:
|
||||
case VALUE_TYPE_EXTERNREF:
|
||||
return llvm_types->int32_type;
|
||||
case VALUE_TYPE_I64:
|
||||
return llvm_types->int64_type;
|
||||
@ -21,12 +23,12 @@ wasm_type_to_llvm_type(AOTLLVMTypes *llvm_types, uint8 wasm_type)
|
||||
return llvm_types->float32_type;
|
||||
case VALUE_TYPE_F64:
|
||||
return llvm_types->float64_type;
|
||||
#if WASM_ENABLE_SIMD != 0
|
||||
case VALUE_TYPE_V128:
|
||||
return llvm_types->i64x2_vec_type;
|
||||
#endif
|
||||
case VALUE_TYPE_VOID:
|
||||
return llvm_types->void_type;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -491,34 +493,6 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
create_table_base(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
{
|
||||
AOTCompData *comp_data = comp_ctx->comp_data;
|
||||
uint64 module_inst_mem_inst_size =
|
||||
(uint64)comp_data->memory_count * sizeof(AOTMemoryInstance);
|
||||
LLVMValueRef offset;
|
||||
|
||||
offset = I32_CONST(offsetof(AOTModuleInstance, global_table_data.bytes)
|
||||
+ module_inst_mem_inst_size
|
||||
+ comp_ctx->comp_data->global_data_size);
|
||||
func_ctx->table_base = LLVMBuildInBoundsGEP(comp_ctx->builder,
|
||||
func_ctx->aot_inst,
|
||||
&offset, 1,
|
||||
"table_base_tmp");
|
||||
if (!func_ctx->table_base) {
|
||||
aot_set_last_error("llvm build in bounds gep failed.");
|
||||
return false;
|
||||
}
|
||||
func_ctx->table_base = LLVMBuildBitCast(comp_ctx->builder, func_ctx->table_base,
|
||||
INT32_PTR_TYPE, "table_base");
|
||||
if (!func_ctx->table_base) {
|
||||
aot_set_last_error("llvm build bit cast failed.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
create_cur_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
{
|
||||
@ -810,11 +784,13 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx,
|
||||
case VALUE_TYPE_F64:
|
||||
local_value = F64_ZERO;
|
||||
break;
|
||||
#if WASM_ENABLE_SIMD != 0
|
||||
case VALUE_TYPE_V128:
|
||||
local_value = V128_ZERO;
|
||||
break;
|
||||
#endif
|
||||
case VALUE_TYPE_FUNCREF:
|
||||
case VALUE_TYPE_EXTERNREF:
|
||||
local_value = REF_NULL;
|
||||
break;
|
||||
default:
|
||||
bh_assert(0);
|
||||
break;
|
||||
@ -853,10 +829,6 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx,
|
||||
if (!create_memory_info(comp_ctx, func_ctx, int8_ptr_type, func_index))
|
||||
goto fail;
|
||||
|
||||
/* Load table base */
|
||||
if (!create_table_base(comp_ctx, func_ctx))
|
||||
goto fail;
|
||||
|
||||
/* Load current exception */
|
||||
if (!create_cur_exception(comp_ctx, func_ctx))
|
||||
goto fail;
|
||||
@ -943,6 +915,12 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context)
|
||||
basic_types->meta_data_type = LLVMMetadataTypeInContext(context);
|
||||
|
||||
basic_types->int8_ptr_type = LLVMPointerType(basic_types->int8_type, 0);
|
||||
|
||||
if (basic_types->int8_ptr_type) {
|
||||
basic_types->int8_pptr_type =
|
||||
LLVMPointerType(basic_types->int8_ptr_type, 0);
|
||||
}
|
||||
|
||||
basic_types->int16_ptr_type = LLVMPointerType(basic_types->int16_type, 0);
|
||||
basic_types->int32_ptr_type = LLVMPointerType(basic_types->int32_type, 0);
|
||||
basic_types->int64_ptr_type = LLVMPointerType(basic_types->int64_type, 0);
|
||||
@ -959,7 +937,11 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context)
|
||||
basic_types->v128_type = basic_types->i64x2_vec_type;
|
||||
basic_types->v128_ptr_type = LLVMPointerType(basic_types->v128_type, 0);
|
||||
|
||||
basic_types->funcref_type = LLVMInt32TypeInContext(context);
|
||||
basic_types->externref_type = LLVMInt32TypeInContext(context);
|
||||
|
||||
return (basic_types->int8_ptr_type
|
||||
&& basic_types->int8_pptr_type
|
||||
&& basic_types->int16_ptr_type
|
||||
&& basic_types->int32_ptr_type
|
||||
&& basic_types->int64_ptr_type
|
||||
@ -971,7 +953,9 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context)
|
||||
&& basic_types->i64x2_vec_type
|
||||
&& basic_types->f32x4_vec_type
|
||||
&& basic_types->f64x2_vec_type
|
||||
&& basic_types->meta_data_type) ? true : false;
|
||||
&& basic_types->meta_data_type
|
||||
&& basic_types->funcref_type
|
||||
&& basic_types->externref_type) ? true : false;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -1014,6 +998,7 @@ aot_create_llvm_consts(AOTLLVMConsts *consts, AOTCompContext *comp_ctx)
|
||||
consts->i32_32 = I32_CONST(32);
|
||||
consts->i64_63 = I64_CONST(63);
|
||||
consts->i64_64 = I64_CONST(64);
|
||||
consts->ref_null = I32_CONST(NULL_REF);
|
||||
|
||||
return (consts->i8_zero
|
||||
&& consts->i32_zero
|
||||
@ -1041,7 +1026,8 @@ aot_create_llvm_consts(AOTLLVMConsts *consts, AOTCompContext *comp_ctx)
|
||||
&& consts->i32_31
|
||||
&& consts->i32_32
|
||||
&& consts->i64_63
|
||||
&& consts->i64_64) ? true : false;
|
||||
&& consts->i64_64
|
||||
&& consts->ref_null) ? true : false;
|
||||
}
|
||||
|
||||
typedef struct ArchItem {
|
||||
@ -1245,6 +1231,9 @@ aot_create_comp_context(AOTCompData *comp_data,
|
||||
if (option->enable_tail_call)
|
||||
comp_ctx->enable_tail_call = true;
|
||||
|
||||
if (option->enable_ref_types)
|
||||
comp_ctx->enable_ref_types = true;
|
||||
|
||||
if (option->enable_aux_stack_frame)
|
||||
comp_ctx->enable_aux_stack_frame = true;
|
||||
|
||||
@ -1585,10 +1574,7 @@ aot_create_comp_context(AOTCompData *comp_data,
|
||||
}
|
||||
|
||||
/* set exec_env data type to int8** */
|
||||
if (!(comp_ctx->exec_env_type = LLVMPointerType(INT8_PTR_TYPE, 0))) {
|
||||
aot_set_last_error("llvm get pointer type failed.");
|
||||
goto fail;
|
||||
}
|
||||
comp_ctx->exec_env_type = comp_ctx->basic_types.int8_pptr_type;
|
||||
|
||||
/* set aot_inst data type to int8* */
|
||||
comp_ctx->aot_inst_type = INT8_PTR_TYPE;
|
||||
@ -1846,11 +1832,13 @@ aot_build_zero_function_ret(AOTCompContext *comp_ctx,
|
||||
case VALUE_TYPE_F64:
|
||||
ret = LLVMBuildRet(comp_ctx->builder, F64_ZERO);
|
||||
break;
|
||||
#if WASM_ENABLE_SIMD != 0
|
||||
case VALUE_TYPE_V128:
|
||||
ret = LLVMBuildRet(comp_ctx->builder, V128_ZERO);
|
||||
break;
|
||||
#endif
|
||||
case VALUE_TYPE_FUNCREF:
|
||||
case VALUE_TYPE_EXTERNREF:
|
||||
ret = LLVMBuildRet(comp_ctx->builder, REF_NULL);
|
||||
break;
|
||||
default:
|
||||
bh_assert(0);
|
||||
}
|
||||
|
||||
@ -119,7 +119,6 @@ typedef struct AOTFuncContext {
|
||||
|
||||
LLVMValueRef exec_env;
|
||||
LLVMValueRef aot_inst;
|
||||
LLVMValueRef table_base;
|
||||
LLVMValueRef argv_buf;
|
||||
LLVMValueRef native_stack_bound;
|
||||
LLVMValueRef aux_stack_bound;
|
||||
@ -152,6 +151,7 @@ typedef struct AOTLLVMTypes {
|
||||
LLVMTypeRef void_type;
|
||||
|
||||
LLVMTypeRef int8_ptr_type;
|
||||
LLVMTypeRef int8_pptr_type;
|
||||
LLVMTypeRef int16_ptr_type;
|
||||
LLVMTypeRef int32_ptr_type;
|
||||
LLVMTypeRef int64_ptr_type;
|
||||
@ -168,6 +168,9 @@ typedef struct AOTLLVMTypes {
|
||||
LLVMTypeRef f64x2_vec_type;
|
||||
|
||||
LLVMTypeRef meta_data_type;
|
||||
|
||||
LLVMTypeRef funcref_type;
|
||||
LLVMTypeRef externref_type;
|
||||
} AOTLLVMTypes;
|
||||
|
||||
typedef struct AOTLLVMConsts {
|
||||
@ -199,6 +202,7 @@ typedef struct AOTLLVMConsts {
|
||||
LLVMValueRef i32_32;
|
||||
LLVMValueRef i64_63;
|
||||
LLVMValueRef i64_64;
|
||||
LLVMValueRef ref_null;
|
||||
} AOTLLVMConsts;
|
||||
|
||||
/**
|
||||
@ -241,6 +245,9 @@ typedef struct AOTCompContext {
|
||||
/* Tail Call */
|
||||
bool enable_tail_call;
|
||||
|
||||
/* Reference Types */
|
||||
bool enable_ref_types;
|
||||
|
||||
/* Whether optimize the JITed code */
|
||||
bool optimize;
|
||||
|
||||
@ -283,6 +290,7 @@ typedef struct AOTCompOption{
|
||||
bool enable_thread_mgr;
|
||||
bool enable_tail_call;
|
||||
bool enable_simd;
|
||||
bool enable_ref_types;
|
||||
bool enable_aux_stack_check;
|
||||
bool enable_aux_stack_frame;
|
||||
bool is_sgx_platform;
|
||||
|
||||
Reference in New Issue
Block a user