Enable AoT and wamr-sdk, and change arguments of call wasm API (#157)
* Implement memory profiler, optimize memory usage, modify code indent * Implement memory.grow and limit heap space base offset to 1G; modify iwasm build type to Release and 64 bit by default * Add a new extension library: connection * Fix bug of reading magic number and version in big endian platform * Re-org platform APIs: move most platform APIs from iwasm to shared-lib * Enhance wasm loader to fix some security issues * Fix issue about illegal load of EXC_RETURN into PC on stm32 board * Updates that let a restricted version of the interpreter run in SGX * Enable native/app address validation and conversion for wasm app * Remove wasm_application_exectue_* APIs from wasm_export.h which makes confused * Refine binary size and fix several minor issues Optimize interpreter LOAD/STORE opcodes to decrease the binary size Fix issues when using iwasm library: _bh_log undefined, bh_memory.h not found Remove unused _stdin/_stdout/_stderr global variables resolve in libc wrapper Add macros of global heap size, stack size, heap size for Zephyr main.c Clear compile warning of wasm_application.c * Add more strict security checks for libc wrapper API's * Use one libc wrapper copy for sgx and other platforms; remove bh_printf macro for other platform header files * Enhance security of libc strcpy/sprintf wrapper function * Fix issue of call native for x86_64/arm/mips, add module inst parameter for native wrapper functions * Remove get_module_inst() and fix issue of call native * Refine wgl lib: remove module_inst parameter from widget functions; move function index check to runtime instantiate * Refine interpreter call native process, refine memory boudary check * Fix issues of invokeNative function of arm/mips/general version * Add a switch to build simple sample without gui support * Add BUILD_TARGET setting in makefile to replace cpu compiler flags in source code * Re-org shared lib header files, remove unused info; fix compile issues of vxworks * Add build target general * Remove unused files * Update license header * test push * Restore file * Sync up with internal/feature * Sync up with internal/feature * Rename build_wamr_app to build_wasm_app * Fix small issues of README * Enhance malformed wasm file checking Fix issue of print hex int and implement utf8 string check Fix wasi file read/write right issue Fix minor issue of build wasm app doc * Sync up with internal/feature * Sync up with internal/feature: fix interpreter arm issue, fix read leb issue * Sync up with internal/feature * Fix bug of config.h and rename wasi config.h to ssp_config.h * Sync up with internal/feature * Import wamr aot * update document * update document * Update document, disable WASI in 32bit * update document * remove files * update document * Update document * update document * update document * update samples * Sync up with internal repo
This commit is contained in:
510
core/iwasm/compilation/aot.c
Normal file
510
core/iwasm/compilation/aot.c
Normal file
@ -0,0 +1,510 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "aot.h"
|
||||
#include "bh_memory.h"
|
||||
|
||||
|
||||
static char aot_error[128];
|
||||
|
||||
char*
|
||||
aot_get_last_error()
|
||||
{
|
||||
return aot_error[0] == '\0' ? "" : aot_error;
|
||||
}
|
||||
|
||||
void
|
||||
aot_set_last_error(const char *error)
|
||||
{
|
||||
if (error)
|
||||
snprintf(aot_error, sizeof(aot_error), "Error: %s", error);
|
||||
else
|
||||
aot_error[0] = '\0';
|
||||
}
|
||||
|
||||
static void
|
||||
aot_destroy_mem_init_data_list(AOTMemInitData **data_list, uint32 count)
|
||||
{
|
||||
uint32 i;
|
||||
for (i = 0; i < count; i++)
|
||||
if (data_list[i])
|
||||
wasm_free(data_list[i]);
|
||||
wasm_free(data_list);
|
||||
}
|
||||
|
||||
static AOTMemInitData **
|
||||
aot_create_mem_init_data_list(const WASMModule *module)
|
||||
{
|
||||
AOTMemInitData **data_list;
|
||||
uint64 size;
|
||||
uint32 i;
|
||||
|
||||
/* Allocate memory */
|
||||
size = sizeof(AOTMemInitData *) * (uint64)module->data_seg_count;
|
||||
if (size >= UINT32_MAX
|
||||
|| !(data_list = wasm_malloc((uint32)size))) {
|
||||
aot_set_last_error("allocate memory failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(data_list, 0, size);
|
||||
|
||||
/* Create each memory data segment */
|
||||
for (i = 0; i < module->data_seg_count; i++) {
|
||||
size = offsetof(AOTMemInitData, bytes) +
|
||||
(uint64)module->data_segments[i]->data_length;
|
||||
if (size >= UINT32_MAX
|
||||
|| !(data_list[i] = wasm_malloc((uint32)size))) {
|
||||
aot_set_last_error("allocate memory failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
data_list[i]->offset = module->data_segments[i]->base_offset;
|
||||
data_list[i]->byte_count = module->data_segments[i]->data_length;
|
||||
memcpy(data_list[i]->bytes, module->data_segments[i]->data,
|
||||
module->data_segments[i]->data_length);
|
||||
}
|
||||
|
||||
return data_list;
|
||||
|
||||
fail:
|
||||
aot_destroy_mem_init_data_list(data_list, module->data_seg_count);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
aot_destroy_table_init_data_list(AOTTableInitData **data_list, uint32 count)
|
||||
{
|
||||
uint32 i;
|
||||
for (i = 0; i < count; i++)
|
||||
if (data_list[i])
|
||||
wasm_free(data_list[i]);
|
||||
wasm_free(data_list);
|
||||
}
|
||||
|
||||
static AOTTableInitData **
|
||||
aot_create_table_init_data_list(const WASMModule *module)
|
||||
{
|
||||
AOTTableInitData **data_list;
|
||||
uint64 size;
|
||||
uint32 i;
|
||||
|
||||
/* Allocate memory */
|
||||
size = sizeof(AOTTableInitData *) * (uint64)module->table_seg_count;
|
||||
if (size >= UINT32_MAX
|
||||
|| !(data_list = wasm_malloc((uint32)size))) {
|
||||
aot_set_last_error("allocate memory failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(data_list, 0, size);
|
||||
|
||||
/* Create each table data segment */
|
||||
for (i = 0; i < module->table_seg_count; i++) {
|
||||
size = offsetof(AOTTableInitData, func_indexes) +
|
||||
sizeof(uint32) * (uint64)module->table_segments[i].function_count;
|
||||
if (size >= UINT32_MAX
|
||||
|| !(data_list[i] = wasm_malloc((uint32)size))) {
|
||||
aot_set_last_error("allocate memory failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return data_list;
|
||||
|
||||
fail:
|
||||
aot_destroy_table_init_data_list(data_list, module->table_seg_count);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static AOTImportGlobal *
|
||||
aot_create_import_globals(const WASMModule *module,
|
||||
uint32 *p_import_global_data_size)
|
||||
{
|
||||
AOTImportGlobal *import_globals;
|
||||
uint64 size;
|
||||
uint32 i, data_offset = 0;
|
||||
|
||||
/* Allocate memory */
|
||||
size = sizeof(AOTImportGlobal) * (uint64)module->import_global_count;
|
||||
if (size >= UINT32_MAX
|
||||
|| !(import_globals = wasm_malloc((uint32)size))) {
|
||||
aot_set_last_error("allocate memory failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(import_globals, 0, (uint32)size);
|
||||
|
||||
/* Create each import global */
|
||||
for (i = 0; i < module->import_global_count; i++) {
|
||||
WASMGlobalImport *import_global = &module->import_globals[i].u.global;
|
||||
import_globals[i].module_name = import_global->module_name;
|
||||
import_globals[i].global_name = import_global->field_name;
|
||||
import_globals[i].type = import_global->type;
|
||||
import_globals[i].is_mutable = import_global->is_mutable;
|
||||
import_globals[i].global_data_linked = import_global->global_data_linked;
|
||||
import_globals[i].size = wasm_value_type_size(import_global->type);
|
||||
/* Calculate data offset */
|
||||
import_globals[i].data_offset = data_offset;
|
||||
data_offset += wasm_value_type_size(import_global->type);
|
||||
}
|
||||
|
||||
*p_import_global_data_size = data_offset;
|
||||
return import_globals;
|
||||
}
|
||||
|
||||
static AOTGlobal *
|
||||
aot_create_globals(const WASMModule *module,
|
||||
uint32 global_data_start_offset,
|
||||
uint32 *p_global_data_size)
|
||||
{
|
||||
AOTGlobal *globals;
|
||||
uint64 size;
|
||||
uint32 i, data_offset = global_data_start_offset;
|
||||
|
||||
/* Allocate memory */
|
||||
size = sizeof(AOTGlobal) * (uint64)module->global_count;
|
||||
if (size >= UINT32_MAX
|
||||
|| !(globals = wasm_malloc((uint32)size))) {
|
||||
aot_set_last_error("allocate memory failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(globals, 0, (uint32)size);
|
||||
|
||||
/* Create each global */
|
||||
for (i = 0; i < module->global_count; i++) {
|
||||
WASMGlobal *global = &module->globals[i];
|
||||
globals[i].type = global->type;
|
||||
globals[i].is_mutable = global->is_mutable;
|
||||
globals[i].size = wasm_value_type_size(global->type);
|
||||
memcpy(&globals[i].init_expr, &global->init_expr,
|
||||
sizeof(global->init_expr));
|
||||
/* Calculate data offset */
|
||||
globals[i].data_offset = data_offset;
|
||||
data_offset += wasm_value_type_size(global->type);
|
||||
}
|
||||
|
||||
*p_global_data_size = data_offset - global_data_start_offset;
|
||||
return globals;
|
||||
}
|
||||
|
||||
static void
|
||||
aot_destroy_func_types(AOTFuncType **func_types, uint32 count)
|
||||
{
|
||||
uint32 i;
|
||||
for (i = 0; i < count; i++)
|
||||
if (func_types[i])
|
||||
wasm_free(func_types[i]);
|
||||
wasm_free(func_types);
|
||||
}
|
||||
|
||||
static AOTFuncType **
|
||||
aot_create_func_types(const WASMModule *module)
|
||||
{
|
||||
AOTFuncType **func_types;
|
||||
uint64 size;
|
||||
uint32 i;
|
||||
|
||||
/* Allocate memory */
|
||||
size = sizeof(AOTFuncType*) * (uint64)module->type_count;
|
||||
if (size >= UINT32_MAX
|
||||
|| !(func_types = wasm_malloc((uint32)size))) {
|
||||
aot_set_last_error("allocate memory failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(func_types, 0, size);
|
||||
|
||||
/* Create each function type */
|
||||
for (i = 0; i < module->type_count; i++) {
|
||||
size = offsetof(AOTFuncType, types) +
|
||||
(uint64)module->types[i]->param_count +
|
||||
(uint64)module->types[i]->result_count;
|
||||
if (size >= UINT32_MAX
|
||||
|| !(func_types[i] = wasm_malloc((uint32)size))) {
|
||||
aot_set_last_error("allocate memory failed.");
|
||||
goto fail;
|
||||
}
|
||||
memcpy(func_types[i], module->types[i], size);
|
||||
}
|
||||
|
||||
return func_types;
|
||||
|
||||
fail:
|
||||
aot_destroy_func_types(func_types, module->type_count);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static AOTImportFunc *
|
||||
aot_create_import_funcs(const WASMModule *module)
|
||||
{
|
||||
AOTImportFunc *import_funcs;
|
||||
uint64 size;
|
||||
uint32 i, j;
|
||||
|
||||
/* Allocate memory */
|
||||
size = sizeof(AOTImportFunc) * (uint64)module->import_function_count;
|
||||
if (size >= UINT32_MAX
|
||||
|| !(import_funcs = wasm_malloc((uint32)size))) {
|
||||
aot_set_last_error("allocate memory failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create each import function */
|
||||
for (i = 0; i < module->import_function_count; i++) {
|
||||
WASMFunctionImport *import_func = &module->import_functions[i].u.function;
|
||||
import_funcs[i].module_name = import_func->module_name;
|
||||
import_funcs[i].func_name = import_func->field_name;
|
||||
import_funcs[i].func_ptr_linked = import_func->func_ptr_linked;
|
||||
import_funcs[i].func_type = import_func->func_type;
|
||||
/* Resolve function type index */
|
||||
for (j = 0; j < module->type_count; j++)
|
||||
if (import_func->func_type == module->types[j]) {
|
||||
import_funcs[i].func_type_index = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return import_funcs;
|
||||
}
|
||||
|
||||
static void
|
||||
aot_destroy_funcs(AOTFunc **funcs, uint32 count)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
if (funcs[i])
|
||||
wasm_free(funcs[i]);
|
||||
wasm_free(funcs);
|
||||
}
|
||||
|
||||
static AOTFunc **
|
||||
aot_create_funcs(const WASMModule *module)
|
||||
{
|
||||
AOTFunc **funcs;
|
||||
uint64 size;
|
||||
uint32 i, j;
|
||||
|
||||
/* Allocate memory */
|
||||
size = sizeof(AOTFunc*) * (uint64)module->function_count;
|
||||
if (size >= UINT32_MAX
|
||||
|| !(funcs = wasm_malloc((uint32)size))) {
|
||||
aot_set_last_error("allocate memory failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(funcs, 0, size);
|
||||
|
||||
/* Create each function */
|
||||
for (i = 0; i < module->function_count; i++) {
|
||||
WASMFunction *func = module->functions[i];
|
||||
size = sizeof (AOTFunc);
|
||||
if (!(funcs[i] = wasm_malloc((uint32)size))) {
|
||||
aot_set_last_error("allocate memory failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
funcs[i]->func_type = func->func_type;
|
||||
|
||||
/* Resolve function type index */
|
||||
for (j = 0; j < module->type_count; j++)
|
||||
if (func->func_type == module->types[j]) {
|
||||
funcs[i]->func_type_index = j;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Resolve local variable info and code info */
|
||||
funcs[i]->local_count = func->local_count;
|
||||
funcs[i]->local_types = func->local_types;
|
||||
funcs[i]->code = func->code;
|
||||
funcs[i]->code_size = func->code_size;
|
||||
}
|
||||
|
||||
return funcs;
|
||||
|
||||
fail:
|
||||
aot_destroy_funcs(funcs, module->function_count);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static AOTExportFunc *
|
||||
aot_create_export_funcs(const WASMModule *module,
|
||||
uint32 export_func_count)
|
||||
{
|
||||
AOTExportFunc *export_funcs;
|
||||
uint64 size;
|
||||
uint32 i, j = 0;
|
||||
|
||||
/* Allocate memory */
|
||||
size = sizeof(AOTExportFunc) * (uint64)export_func_count;
|
||||
if (size >= UINT32_MAX
|
||||
|| !(export_funcs = wasm_malloc((uint32)size))) {
|
||||
aot_set_last_error("allocate memory failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create each export function */
|
||||
for (i = 0; i < module->export_count; i++) {
|
||||
if (module->exports[i].kind == EXPORT_KIND_FUNC) {
|
||||
export_funcs[j].func_name = module->exports[i].name;
|
||||
export_funcs[j].func_index = module->exports[i].index;
|
||||
export_funcs[j].func_type =
|
||||
module->functions[module->exports[i].index
|
||||
- module->import_function_count]->func_type;
|
||||
/* Function pointer to be linked in JIT mode */
|
||||
export_funcs[j].func_ptr = NULL;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
return export_funcs;
|
||||
}
|
||||
|
||||
AOTCompData*
|
||||
aot_create_comp_data(WASMModule *module)
|
||||
{
|
||||
AOTCompData *comp_data;
|
||||
uint32 import_global_data_size = 0, global_data_size = 0, i;
|
||||
|
||||
/* Allocate memory */
|
||||
if (!(comp_data = wasm_malloc(sizeof(AOTCompData)))) {
|
||||
aot_set_last_error("create compile data failed.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(comp_data, 0, sizeof(AOTCompData));
|
||||
|
||||
/* Set memory page count */
|
||||
if (module->import_memory_count) {
|
||||
comp_data->mem_init_page_count =
|
||||
module->import_memories[0].u.memory.init_page_count;
|
||||
comp_data->mem_max_page_count =
|
||||
module->import_memories[0].u.memory.max_page_count;
|
||||
}
|
||||
else if (module->memory_count) {
|
||||
comp_data->mem_init_page_count =
|
||||
module->memories[0].init_page_count;
|
||||
comp_data->mem_max_page_count =
|
||||
module->memories[0].max_page_count;
|
||||
}
|
||||
|
||||
/* Create memory data segments */
|
||||
comp_data->mem_init_data_count = module->data_seg_count;
|
||||
if (comp_data->mem_init_data_count > 0
|
||||
&& !(comp_data->mem_init_data_list =
|
||||
aot_create_mem_init_data_list(module)))
|
||||
goto fail;
|
||||
|
||||
/* Set table size */
|
||||
if (module->import_table_count)
|
||||
comp_data->table_size = module->import_tables[0].u.table.init_size;
|
||||
else if (module->table_count)
|
||||
comp_data->table_size = module->tables[0].init_size;
|
||||
|
||||
/* Create table data segments */
|
||||
comp_data->table_init_data_count = module->table_seg_count;
|
||||
if (comp_data->table_init_data_count > 0
|
||||
&& !(comp_data->table_init_data_list =
|
||||
aot_create_table_init_data_list(module)))
|
||||
goto fail;
|
||||
|
||||
/* Create import globals */
|
||||
comp_data->import_global_count = module->import_global_count;
|
||||
if (comp_data->import_global_count > 0
|
||||
&& !(comp_data->import_globals =
|
||||
aot_create_import_globals(module, &import_global_data_size)))
|
||||
goto fail;
|
||||
|
||||
/* Create globals */
|
||||
comp_data->global_count = module->global_count;
|
||||
if (comp_data->global_count
|
||||
&& !(comp_data->globals = aot_create_globals
|
||||
(module, import_global_data_size, &global_data_size)))
|
||||
goto fail;
|
||||
|
||||
comp_data->global_data_size = import_global_data_size +
|
||||
global_data_size;
|
||||
|
||||
/* Create function types */
|
||||
comp_data->func_type_count = module->type_count;
|
||||
if (comp_data->func_type_count
|
||||
&& !(comp_data->func_types = aot_create_func_types(module)))
|
||||
goto fail;
|
||||
|
||||
/* Create import functions */
|
||||
comp_data->import_func_count = module->import_function_count;
|
||||
if (comp_data->import_func_count
|
||||
&& !(comp_data->import_funcs = aot_create_import_funcs(module)))
|
||||
goto fail;
|
||||
|
||||
/* Create functions */
|
||||
comp_data->func_count = module->function_count;
|
||||
if (comp_data->func_count
|
||||
&& !(comp_data->funcs = aot_create_funcs(module)))
|
||||
goto fail;
|
||||
|
||||
/* Create export functions */
|
||||
for (i = 0; i < module->export_count; i++)
|
||||
if (module->exports[i].kind == EXPORT_KIND_FUNC)
|
||||
comp_data->export_func_count++;
|
||||
|
||||
if (comp_data->export_func_count
|
||||
&& !(comp_data->export_funcs = aot_create_export_funcs
|
||||
(module, comp_data->export_func_count)))
|
||||
goto fail;
|
||||
|
||||
comp_data->start_func_index = module->start_function;
|
||||
comp_data->wasm_module = module;
|
||||
|
||||
return comp_data;
|
||||
|
||||
fail:
|
||||
|
||||
aot_destroy_comp_data(comp_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
aot_destroy_comp_data(AOTCompData *comp_data)
|
||||
{
|
||||
if (!comp_data)
|
||||
return;
|
||||
|
||||
if (comp_data->mem_init_data_list)
|
||||
aot_destroy_mem_init_data_list(comp_data->mem_init_data_list,
|
||||
comp_data->mem_init_data_count);
|
||||
|
||||
if (comp_data->table_init_data_list)
|
||||
aot_destroy_table_init_data_list(comp_data->table_init_data_list,
|
||||
comp_data->table_init_data_count);
|
||||
|
||||
if (comp_data->import_globals)
|
||||
wasm_free(comp_data->import_globals);
|
||||
|
||||
if (comp_data->globals)
|
||||
wasm_free(comp_data->globals);
|
||||
|
||||
if (comp_data->func_types)
|
||||
aot_destroy_func_types(comp_data->func_types,
|
||||
comp_data->func_type_count);
|
||||
|
||||
if (comp_data->import_funcs)
|
||||
wasm_free(comp_data->import_funcs);
|
||||
|
||||
if (comp_data->funcs)
|
||||
aot_destroy_funcs(comp_data->funcs, comp_data->func_count);
|
||||
|
||||
if (comp_data->export_funcs)
|
||||
wasm_free(comp_data->export_funcs);
|
||||
|
||||
wasm_free(comp_data);
|
||||
}
|
||||
|
||||
165
core/iwasm/compilation/aot.h
Normal file
165
core/iwasm/compilation/aot.h
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _AOT_H_
|
||||
#define _AOT_H_
|
||||
|
||||
#include "bh_platform.h"
|
||||
#include "bh_assert.h"
|
||||
#include "../common/wasm_runtime_common.h"
|
||||
#include "../interpreter/wasm.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define AOT_FUNC_PREFIX "aot_func#"
|
||||
|
||||
typedef InitializerExpression AOTInitExpr;
|
||||
typedef WASMType AOTFuncType;
|
||||
|
||||
/**
|
||||
* A segment of memory init data
|
||||
*/
|
||||
typedef struct AOTMemInitData {
|
||||
/* Start address of init data */
|
||||
AOTInitExpr offset;
|
||||
/* Byte count */
|
||||
uint32 byte_count;
|
||||
/* Byte array */
|
||||
uint8 bytes[1];
|
||||
} AOTMemInitData;
|
||||
|
||||
/**
|
||||
* A segment of table init data
|
||||
*/
|
||||
typedef struct AOTTableInitData {
|
||||
/* Start address of init data */
|
||||
AOTInitExpr offset;
|
||||
/* Function index count */
|
||||
uint32 func_index_count;
|
||||
/* Function index array */
|
||||
uint32 func_indexes[1];
|
||||
} AOTTableInitData;
|
||||
|
||||
/**
|
||||
* Import global variable
|
||||
*/
|
||||
typedef struct AOTImportGlobal {
|
||||
char *module_name;
|
||||
char *global_name;
|
||||
/* VALUE_TYPE_I32/I64/F32/F64 */
|
||||
uint8 type;
|
||||
bool is_mutable;
|
||||
uint32 size;
|
||||
/* The data offset of current global in global data */
|
||||
uint32 data_offset;
|
||||
/* global data after linked */
|
||||
WASMValue global_data_linked;
|
||||
} AOTImportGlobal;
|
||||
|
||||
/**
|
||||
* Global variable
|
||||
*/
|
||||
typedef struct AOTGlobal {
|
||||
/* VALUE_TYPE_I32/I64/F32/F64 */
|
||||
uint8 type;
|
||||
bool is_mutable;
|
||||
uint32 size;
|
||||
/* The data offset of current global in global data */
|
||||
uint32 data_offset;
|
||||
AOTInitExpr init_expr;
|
||||
} AOTGlobal;
|
||||
|
||||
/**
|
||||
* Import function
|
||||
*/
|
||||
typedef struct AOTImportFunc {
|
||||
char *module_name;
|
||||
char *func_name;
|
||||
AOTFuncType *func_type;
|
||||
uint32 func_type_index;
|
||||
/* function pointer after linked */
|
||||
void *func_ptr_linked;
|
||||
} AOTImportFunc;
|
||||
|
||||
/**
|
||||
* Function
|
||||
*/
|
||||
typedef struct AOTFunc {
|
||||
AOTFuncType *func_type;
|
||||
uint32 func_type_index;
|
||||
uint32 local_count;
|
||||
uint8 *local_types;
|
||||
uint32 code_size;
|
||||
uint8 *code;
|
||||
} AOTFunc;
|
||||
|
||||
/**
|
||||
* Export function
|
||||
*/
|
||||
typedef struct AOTExportFunc {
|
||||
char *func_name;
|
||||
AOTFuncType *func_type;
|
||||
/* function pointer linked */
|
||||
void *func_ptr;
|
||||
uint32 func_index;
|
||||
} AOTExportFunc;
|
||||
|
||||
typedef struct AOTCompData {
|
||||
/* Memory and memory init data info */
|
||||
uint32 mem_init_page_count;
|
||||
uint32 mem_max_page_count;
|
||||
uint32 mem_init_data_count;
|
||||
AOTMemInitData **mem_init_data_list;
|
||||
|
||||
/* Table and table init data info */
|
||||
uint32 table_size;
|
||||
AOTTableInitData **table_init_data_list;
|
||||
uint32 table_init_data_count;
|
||||
|
||||
AOTImportGlobal *import_globals;
|
||||
uint32 import_global_count;
|
||||
|
||||
AOTGlobal *globals;
|
||||
uint32 global_count;
|
||||
|
||||
AOTFuncType **func_types;
|
||||
uint32 func_type_count;
|
||||
|
||||
AOTImportFunc *import_funcs;
|
||||
uint32 import_func_count;
|
||||
|
||||
AOTFunc **funcs;
|
||||
uint32 func_count;
|
||||
|
||||
AOTExportFunc *export_funcs;
|
||||
uint32 export_func_count;
|
||||
|
||||
uint32 start_func_index;
|
||||
uint32 addr_data_size;
|
||||
uint32 global_data_size;
|
||||
|
||||
WASMModule *wasm_module;
|
||||
} AOTCompData;
|
||||
|
||||
AOTCompData*
|
||||
aot_create_comp_data(WASMModule *module);
|
||||
|
||||
void
|
||||
aot_destroy_comp_data(AOTCompData *comp_data);
|
||||
|
||||
char*
|
||||
aot_get_last_error();
|
||||
|
||||
void
|
||||
aot_set_last_error(const char *error);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _AOT_H_ */
|
||||
|
||||
804
core/iwasm/compilation/aot_compiler.c
Normal file
804
core/iwasm/compilation/aot_compiler.c
Normal file
@ -0,0 +1,804 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "aot_compiler.h"
|
||||
#include "aot_emit_compare.h"
|
||||
#include "aot_emit_conversion.h"
|
||||
#include "aot_emit_memory.h"
|
||||
#include "aot_emit_variable.h"
|
||||
#include "aot_emit_const.h"
|
||||
#include "aot_emit_exception.h"
|
||||
#include "aot_emit_numberic.h"
|
||||
#include "aot_emit_control.h"
|
||||
#include "aot_emit_function.h"
|
||||
#include "aot_emit_parametric.h"
|
||||
#include "bh_memory.h"
|
||||
#include "../aot/aot_runtime.h"
|
||||
#include "../interpreter/wasm_opcode.h"
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#define CHECK_BUF(buf, buf_end, length) do { \
|
||||
if (buf + length > buf_end) { \
|
||||
aot_set_last_error("read leb failed: unexpected end."); \
|
||||
return false; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static bool
|
||||
read_leb(const uint8 *buf, const uint8 *buf_end,
|
||||
uint32 *p_offset, uint32 maxbits,
|
||||
bool sign, uint64 *p_result)
|
||||
{
|
||||
uint64 result = 0;
|
||||
uint32 shift = 0;
|
||||
uint32 bcnt = 0;
|
||||
uint64 byte;
|
||||
|
||||
while (true) {
|
||||
CHECK_BUF(buf, buf_end, 1);
|
||||
byte = buf[*p_offset];
|
||||
*p_offset += 1;
|
||||
result |= ((byte & 0x7f) << shift);
|
||||
shift += 7;
|
||||
if ((byte & 0x80) == 0) {
|
||||
break;
|
||||
}
|
||||
bcnt += 1;
|
||||
}
|
||||
if (bcnt > (((maxbits + 8) >> 3) - (maxbits + 8))) {
|
||||
aot_set_last_error("read leb failed: unsigned leb overflow.");
|
||||
return false;
|
||||
}
|
||||
if (sign && (shift < maxbits) && (byte & 0x40)) {
|
||||
/* Sign extend */
|
||||
result |= (uint64)(- (((uint64)1) << shift));
|
||||
}
|
||||
*p_result = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
#define read_leb_uint32(p, p_end, res) do { \
|
||||
uint32 off = 0; \
|
||||
uint64 res64; \
|
||||
if (!read_leb(p, p_end, &off, 32, false, &res64)) \
|
||||
return false; \
|
||||
p += off; \
|
||||
res = (uint32)res64; \
|
||||
} while (0)
|
||||
|
||||
#define read_leb_int32(p, p_end, res) do { \
|
||||
uint32 off = 0; \
|
||||
uint64 res64; \
|
||||
if (!read_leb(p, p_end, &off, 32, true, &res64)) \
|
||||
return false; \
|
||||
p += off; \
|
||||
res = (int32)res64; \
|
||||
} while (0)
|
||||
|
||||
#define read_leb_int64(p, p_end, res) do { \
|
||||
uint32 off = 0; \
|
||||
uint64 res64; \
|
||||
if (!read_leb(p, p_end, &off, 64, true, &res64)) \
|
||||
return false; \
|
||||
p += off; \
|
||||
res = (int64)res64; \
|
||||
} while (0)
|
||||
|
||||
static bool
|
||||
aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|
||||
{
|
||||
AOTFuncContext *func_ctx = comp_ctx->func_ctxes[func_index];
|
||||
uint8 *frame_ip = func_ctx->aot_func->code, opcode, *p_f32, *p_f64;
|
||||
uint8 *frame_ip_end = frame_ip + func_ctx->aot_func->code_size;
|
||||
uint32 block_ret_type, br_depth, *br_depths, br_count;
|
||||
uint32 func_idx, type_idx, mem_idx, local_idx, global_idx, i;
|
||||
uint32 bytes = 4, align, offset;
|
||||
bool sign = true;
|
||||
int32 i32_const;
|
||||
int64 i64_const;
|
||||
float32 f32_const;
|
||||
float64 f64_const;
|
||||
|
||||
/* Start to translate the opcodes */
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder,
|
||||
func_ctx->block_stack.block_list_head
|
||||
->llvm_entry_block);
|
||||
while (frame_ip < frame_ip_end) {
|
||||
opcode = *frame_ip++;
|
||||
switch (opcode) {
|
||||
case WASM_OP_UNREACHABLE:
|
||||
if (!aot_compile_op_unreachable(comp_ctx, func_ctx, &frame_ip))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_NOP:
|
||||
break;
|
||||
|
||||
case WASM_OP_BLOCK:
|
||||
case WASM_OP_LOOP:
|
||||
case WASM_OP_IF:
|
||||
read_leb_uint32(frame_ip, frame_ip_end, block_ret_type);
|
||||
if (!aot_compile_op_block(comp_ctx, func_ctx,
|
||||
&frame_ip, frame_ip_end,
|
||||
(uint32)(BLOCK_TYPE_BLOCK + opcode - WASM_OP_BLOCK),
|
||||
block_ret_type))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_ELSE:
|
||||
if (!aot_compile_op_else(comp_ctx, func_ctx, &frame_ip))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_END:
|
||||
if (!aot_compile_op_end(comp_ctx, func_ctx, &frame_ip))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_BR:
|
||||
read_leb_uint32(frame_ip, frame_ip_end, br_depth);
|
||||
if (!aot_compile_op_br(comp_ctx, func_ctx, br_depth, &frame_ip))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_BR_IF:
|
||||
read_leb_uint32(frame_ip, frame_ip_end, br_depth);
|
||||
if (!aot_compile_op_br_if(comp_ctx, func_ctx, br_depth, &frame_ip))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_BR_TABLE:
|
||||
read_leb_uint32(frame_ip, frame_ip_end, br_count);
|
||||
if (!(br_depths = wasm_malloc((uint32)sizeof(uint32) * (br_count + 1)))) {
|
||||
aot_set_last_error("allocate memory failed.");
|
||||
goto fail;
|
||||
}
|
||||
for (i = 0; i <= br_count; i++)
|
||||
read_leb_uint32(frame_ip, frame_ip_end, br_depths[i]);
|
||||
|
||||
if (!aot_compile_op_br_table(comp_ctx, func_ctx,
|
||||
br_depths, br_count, &frame_ip)) {
|
||||
wasm_free(br_depths);
|
||||
return false;
|
||||
}
|
||||
|
||||
wasm_free(br_depths);
|
||||
break;
|
||||
|
||||
case WASM_OP_RETURN:
|
||||
if (!aot_compile_op_return(comp_ctx, func_ctx, &frame_ip))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_CALL:
|
||||
read_leb_uint32(frame_ip, frame_ip_end, func_idx);
|
||||
if (!aot_compile_op_call(comp_ctx, func_ctx, func_idx, &frame_ip))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_CALL_INDIRECT:
|
||||
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))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_DROP_32:
|
||||
if (!aot_compile_op_drop(comp_ctx, func_ctx, true))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_DROP_64:
|
||||
if (!aot_compile_op_drop(comp_ctx, func_ctx, false))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_SELECT_32:
|
||||
if (!aot_compile_op_select(comp_ctx, func_ctx, true))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_SELECT_64:
|
||||
if (!aot_compile_op_select(comp_ctx, func_ctx, false))
|
||||
return false;
|
||||
break;
|
||||
|
||||
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))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_SET_LOCAL:
|
||||
read_leb_uint32(frame_ip, frame_ip_end, local_idx);
|
||||
if (!aot_compile_op_set_local(comp_ctx, func_ctx, local_idx))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_TEE_LOCAL:
|
||||
read_leb_uint32(frame_ip, frame_ip_end, local_idx);
|
||||
if (!aot_compile_op_tee_local(comp_ctx, func_ctx, local_idx))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_GET_GLOBAL:
|
||||
read_leb_uint32(frame_ip, frame_ip_end, global_idx);
|
||||
if (!aot_compile_op_get_global(comp_ctx, func_ctx, global_idx))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_SET_GLOBAL:
|
||||
read_leb_uint32(frame_ip, frame_ip_end, global_idx);
|
||||
if (!aot_compile_op_set_global(comp_ctx, func_ctx, global_idx))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I32_LOAD:
|
||||
bytes = 4;
|
||||
sign = true;
|
||||
goto op_i32_load;
|
||||
case WASM_OP_I32_LOAD8_S:
|
||||
case WASM_OP_I32_LOAD8_U:
|
||||
bytes = 1;
|
||||
sign = (opcode == WASM_OP_I32_LOAD8_S) ? true : false;
|
||||
goto op_i32_load;
|
||||
case WASM_OP_I32_LOAD16_S:
|
||||
case WASM_OP_I32_LOAD16_U:
|
||||
bytes = 2;
|
||||
sign = (opcode == WASM_OP_I32_LOAD16_S) ? true : false;
|
||||
op_i32_load:
|
||||
read_leb_uint32(frame_ip, frame_ip_end, align);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, offset);
|
||||
if (!aot_compile_op_i32_load(comp_ctx, func_ctx, align, offset,
|
||||
bytes, sign))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I64_LOAD:
|
||||
bytes = 8;
|
||||
sign = true;
|
||||
goto op_i64_load;
|
||||
case WASM_OP_I64_LOAD8_S:
|
||||
case WASM_OP_I64_LOAD8_U:
|
||||
bytes = 1;
|
||||
sign = (opcode == WASM_OP_I64_LOAD8_S) ? true : false;
|
||||
goto op_i64_load;
|
||||
case WASM_OP_I64_LOAD16_S:
|
||||
case WASM_OP_I64_LOAD16_U:
|
||||
bytes = 2;
|
||||
sign = (opcode == WASM_OP_I64_LOAD16_S) ? true : false;
|
||||
goto op_i64_load;
|
||||
case WASM_OP_I64_LOAD32_S:
|
||||
case WASM_OP_I64_LOAD32_U:
|
||||
bytes = 4;
|
||||
sign = (opcode == WASM_OP_I64_LOAD32_S) ? true : false;
|
||||
op_i64_load:
|
||||
read_leb_uint32(frame_ip, frame_ip_end, align);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, offset);
|
||||
if (!aot_compile_op_i64_load(comp_ctx, func_ctx, align, offset,
|
||||
bytes, sign))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F32_LOAD:
|
||||
read_leb_uint32(frame_ip, frame_ip_end, align);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, offset);
|
||||
if (!aot_compile_op_f32_load(comp_ctx, func_ctx, align, offset))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F64_LOAD:
|
||||
read_leb_uint32(frame_ip, frame_ip_end, align);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, offset);
|
||||
if (!aot_compile_op_f64_load(comp_ctx, func_ctx, align, offset))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I32_STORE:
|
||||
bytes = 4;
|
||||
goto op_i32_store;
|
||||
case WASM_OP_I32_STORE8:
|
||||
bytes = 1;
|
||||
goto op_i32_store;
|
||||
case WASM_OP_I32_STORE16:
|
||||
bytes = 2;
|
||||
op_i32_store:
|
||||
read_leb_uint32(frame_ip, frame_ip_end, align);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, offset);
|
||||
if (!aot_compile_op_i32_store(comp_ctx, func_ctx, align, offset, bytes))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I64_STORE:
|
||||
bytes = 8;
|
||||
goto op_i64_store;
|
||||
case WASM_OP_I64_STORE8:
|
||||
bytes = 1;
|
||||
goto op_i64_store;
|
||||
case WASM_OP_I64_STORE16:
|
||||
bytes = 2;
|
||||
goto op_i64_store;
|
||||
case WASM_OP_I64_STORE32:
|
||||
bytes = 4;
|
||||
op_i64_store:
|
||||
read_leb_uint32(frame_ip, frame_ip_end, align);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, offset);
|
||||
if (!aot_compile_op_i64_store(comp_ctx, func_ctx, align, offset, bytes))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F32_STORE:
|
||||
read_leb_uint32(frame_ip, frame_ip_end, align);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, offset);
|
||||
if (!aot_compile_op_f32_store(comp_ctx, func_ctx, align, offset))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F64_STORE:
|
||||
read_leb_uint32(frame_ip, frame_ip_end, align);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, offset);
|
||||
if (!aot_compile_op_f64_store(comp_ctx, func_ctx, align, offset))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_MEMORY_SIZE:
|
||||
read_leb_uint32(frame_ip, frame_ip_end, mem_idx);
|
||||
if (!aot_compile_op_memory_size(comp_ctx, func_ctx))
|
||||
return false;
|
||||
(void)mem_idx;
|
||||
break;
|
||||
|
||||
case WASM_OP_MEMORY_GROW:
|
||||
read_leb_uint32(frame_ip, frame_ip_end, mem_idx);
|
||||
if (!aot_compile_op_memory_grow(comp_ctx, func_ctx))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I32_CONST:
|
||||
read_leb_int32(frame_ip, frame_ip_end, i32_const);
|
||||
if (!aot_compile_op_i32_const(comp_ctx, func_ctx, i32_const))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I64_CONST:
|
||||
read_leb_int64(frame_ip, frame_ip_end, i64_const);
|
||||
if (!aot_compile_op_i64_const(comp_ctx, func_ctx, i64_const))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F32_CONST:
|
||||
p_f32 = (uint8*)&f32_const;
|
||||
for (i = 0; i < sizeof(float32); i++)
|
||||
*p_f32++ = *frame_ip++;
|
||||
if (!aot_compile_op_f32_const(comp_ctx, func_ctx, f32_const))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F64_CONST:
|
||||
p_f64 = (uint8*)&f64_const;
|
||||
for (i = 0; i < sizeof(float64); i++)
|
||||
*p_f64++ = *frame_ip++;
|
||||
if (!aot_compile_op_f64_const(comp_ctx, func_ctx, f64_const))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I32_EQZ:
|
||||
case WASM_OP_I32_EQ:
|
||||
case WASM_OP_I32_NE:
|
||||
case WASM_OP_I32_LT_S:
|
||||
case WASM_OP_I32_LT_U:
|
||||
case WASM_OP_I32_GT_S:
|
||||
case WASM_OP_I32_GT_U:
|
||||
case WASM_OP_I32_LE_S:
|
||||
case WASM_OP_I32_LE_U:
|
||||
case WASM_OP_I32_GE_S:
|
||||
case WASM_OP_I32_GE_U:
|
||||
if (!aot_compile_op_i32_compare(comp_ctx, func_ctx,
|
||||
INT_EQZ + opcode - WASM_OP_I32_EQZ))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I64_EQZ:
|
||||
case WASM_OP_I64_EQ:
|
||||
case WASM_OP_I64_NE:
|
||||
case WASM_OP_I64_LT_S:
|
||||
case WASM_OP_I64_LT_U:
|
||||
case WASM_OP_I64_GT_S:
|
||||
case WASM_OP_I64_GT_U:
|
||||
case WASM_OP_I64_LE_S:
|
||||
case WASM_OP_I64_LE_U:
|
||||
case WASM_OP_I64_GE_S:
|
||||
case WASM_OP_I64_GE_U:
|
||||
if (!aot_compile_op_i64_compare(comp_ctx, func_ctx,
|
||||
INT_EQZ + opcode - WASM_OP_I64_EQZ))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F32_EQ:
|
||||
case WASM_OP_F32_NE:
|
||||
case WASM_OP_F32_LT:
|
||||
case WASM_OP_F32_GT:
|
||||
case WASM_OP_F32_LE:
|
||||
case WASM_OP_F32_GE:
|
||||
if (!aot_compile_op_f32_compare(comp_ctx, func_ctx,
|
||||
FLOAT_EQ + opcode - WASM_OP_F32_EQ))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F64_EQ:
|
||||
case WASM_OP_F64_NE:
|
||||
case WASM_OP_F64_LT:
|
||||
case WASM_OP_F64_GT:
|
||||
case WASM_OP_F64_LE:
|
||||
case WASM_OP_F64_GE:
|
||||
if (!aot_compile_op_f64_compare(comp_ctx, func_ctx,
|
||||
FLOAT_EQ + opcode - WASM_OP_F64_EQ))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I32_CLZ:
|
||||
if (!aot_compile_op_i32_clz(comp_ctx, func_ctx))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I32_CTZ:
|
||||
if (!aot_compile_op_i32_ctz(comp_ctx, func_ctx))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I32_POPCNT:
|
||||
if (!aot_compile_op_i32_popcnt(comp_ctx, func_ctx))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I32_ADD:
|
||||
case WASM_OP_I32_SUB:
|
||||
case WASM_OP_I32_MUL:
|
||||
case WASM_OP_I32_DIV_S:
|
||||
case WASM_OP_I32_DIV_U:
|
||||
case WASM_OP_I32_REM_S:
|
||||
case WASM_OP_I32_REM_U:
|
||||
if (!aot_compile_op_i32_arithmetic(comp_ctx, func_ctx,
|
||||
INT_ADD + opcode - WASM_OP_I32_ADD,
|
||||
&frame_ip))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I32_AND:
|
||||
case WASM_OP_I32_OR:
|
||||
case WASM_OP_I32_XOR:
|
||||
if (!aot_compile_op_i32_bitwise(comp_ctx, func_ctx,
|
||||
INT_SHL + opcode - WASM_OP_I32_AND))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I32_SHL:
|
||||
case WASM_OP_I32_SHR_S:
|
||||
case WASM_OP_I32_SHR_U:
|
||||
case WASM_OP_I32_ROTL:
|
||||
case WASM_OP_I32_ROTR:
|
||||
if (!aot_compile_op_i32_shift(comp_ctx, func_ctx,
|
||||
INT_SHL + opcode - WASM_OP_I32_SHL))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I64_CLZ:
|
||||
if (!aot_compile_op_i64_clz(comp_ctx, func_ctx))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I64_CTZ:
|
||||
if (!aot_compile_op_i64_ctz(comp_ctx, func_ctx))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I64_POPCNT:
|
||||
if (!aot_compile_op_i64_popcnt(comp_ctx, func_ctx))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I64_ADD:
|
||||
case WASM_OP_I64_SUB:
|
||||
case WASM_OP_I64_MUL:
|
||||
case WASM_OP_I64_DIV_S:
|
||||
case WASM_OP_I64_DIV_U:
|
||||
case WASM_OP_I64_REM_S:
|
||||
case WASM_OP_I64_REM_U:
|
||||
if (!aot_compile_op_i64_arithmetic(comp_ctx, func_ctx,
|
||||
INT_ADD + opcode - WASM_OP_I64_ADD,
|
||||
&frame_ip))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I64_AND:
|
||||
case WASM_OP_I64_OR:
|
||||
case WASM_OP_I64_XOR:
|
||||
if (!aot_compile_op_i64_bitwise(comp_ctx, func_ctx,
|
||||
INT_SHL + opcode - WASM_OP_I64_AND))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I64_SHL:
|
||||
case WASM_OP_I64_SHR_S:
|
||||
case WASM_OP_I64_SHR_U:
|
||||
case WASM_OP_I64_ROTL:
|
||||
case WASM_OP_I64_ROTR:
|
||||
if (!aot_compile_op_i64_shift(comp_ctx, func_ctx,
|
||||
INT_SHL + opcode - WASM_OP_I64_SHL))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F32_ABS:
|
||||
case WASM_OP_F32_NEG:
|
||||
case WASM_OP_F32_CEIL:
|
||||
case WASM_OP_F32_FLOOR:
|
||||
case WASM_OP_F32_TRUNC:
|
||||
case WASM_OP_F32_NEAREST:
|
||||
case WASM_OP_F32_SQRT:
|
||||
if (!aot_compile_op_f32_math(comp_ctx, func_ctx,
|
||||
FLOAT_ABS + opcode - WASM_OP_F32_ABS))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F32_ADD:
|
||||
case WASM_OP_F32_SUB:
|
||||
case WASM_OP_F32_MUL:
|
||||
case WASM_OP_F32_DIV:
|
||||
case WASM_OP_F32_MIN:
|
||||
case WASM_OP_F32_MAX:
|
||||
if (!aot_compile_op_f32_arithmetic(comp_ctx, func_ctx,
|
||||
FLOAT_ADD + opcode - WASM_OP_F32_ADD))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F32_COPYSIGN:
|
||||
if (!aot_compile_op_f32_copysign(comp_ctx, func_ctx))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F64_ABS:
|
||||
case WASM_OP_F64_NEG:
|
||||
case WASM_OP_F64_CEIL:
|
||||
case WASM_OP_F64_FLOOR:
|
||||
case WASM_OP_F64_TRUNC:
|
||||
case WASM_OP_F64_NEAREST:
|
||||
case WASM_OP_F64_SQRT:
|
||||
if (!aot_compile_op_f64_math(comp_ctx, func_ctx,
|
||||
FLOAT_ABS + opcode - WASM_OP_F64_ABS))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F64_ADD:
|
||||
case WASM_OP_F64_SUB:
|
||||
case WASM_OP_F64_MUL:
|
||||
case WASM_OP_F64_DIV:
|
||||
case WASM_OP_F64_MIN:
|
||||
case WASM_OP_F64_MAX:
|
||||
if (!aot_compile_op_f64_arithmetic(comp_ctx, func_ctx,
|
||||
FLOAT_ADD + opcode - WASM_OP_F64_ADD))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F64_COPYSIGN:
|
||||
if (!aot_compile_op_f64_copysign(comp_ctx, func_ctx))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I32_WRAP_I64:
|
||||
if (!aot_compile_op_i32_wrap_i64(comp_ctx, func_ctx))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I32_TRUNC_S_F32:
|
||||
case WASM_OP_I32_TRUNC_U_F32:
|
||||
sign = (opcode == WASM_OP_I32_TRUNC_S_F32) ? true : false;
|
||||
if (!aot_compile_op_i32_trunc_f32(comp_ctx, func_ctx, sign))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I32_TRUNC_S_F64:
|
||||
case WASM_OP_I32_TRUNC_U_F64:
|
||||
sign = (opcode == WASM_OP_I32_TRUNC_S_F64) ? true : false;
|
||||
if (!aot_compile_op_i32_trunc_f64(comp_ctx, func_ctx, sign))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I64_EXTEND_S_I32:
|
||||
case WASM_OP_I64_EXTEND_U_I32:
|
||||
sign = (opcode == WASM_OP_I64_EXTEND_S_I32) ? true : false;
|
||||
if (!aot_compile_op_i64_extend_i32(comp_ctx, func_ctx, sign))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I64_TRUNC_S_F32:
|
||||
case WASM_OP_I64_TRUNC_U_F32:
|
||||
sign = (opcode == WASM_OP_I64_TRUNC_S_F32) ? true : false;
|
||||
if (!aot_compile_op_i64_trunc_f32(comp_ctx, func_ctx, sign))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I64_TRUNC_S_F64:
|
||||
case WASM_OP_I64_TRUNC_U_F64:
|
||||
sign = (opcode == WASM_OP_I64_TRUNC_S_F64) ? true : false;
|
||||
if (!aot_compile_op_i64_trunc_f64(comp_ctx, func_ctx, sign))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F32_CONVERT_S_I32:
|
||||
case WASM_OP_F32_CONVERT_U_I32:
|
||||
sign = (opcode == WASM_OP_F32_CONVERT_S_I32) ? true : false;
|
||||
if (!aot_compile_op_f32_convert_i32(comp_ctx, func_ctx, sign))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F32_CONVERT_S_I64:
|
||||
case WASM_OP_F32_CONVERT_U_I64:
|
||||
sign = (opcode == WASM_OP_F32_CONVERT_S_I64) ? true : false;
|
||||
if (!aot_compile_op_f32_convert_i64(comp_ctx, func_ctx, sign))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F32_DEMOTE_F64:
|
||||
if (!aot_compile_op_f32_demote_f64(comp_ctx, func_ctx))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F64_CONVERT_S_I32:
|
||||
case WASM_OP_F64_CONVERT_U_I32:
|
||||
sign = (opcode == WASM_OP_F64_CONVERT_S_I32) ? true : false;
|
||||
if (!aot_compile_op_f64_convert_i32(comp_ctx, func_ctx, sign))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F64_CONVERT_S_I64:
|
||||
case WASM_OP_F64_CONVERT_U_I64:
|
||||
sign = (opcode == WASM_OP_F64_CONVERT_S_I64) ? true : false;
|
||||
if (!aot_compile_op_f64_convert_i64(comp_ctx, func_ctx, sign))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F64_PROMOTE_F32:
|
||||
if (!aot_compile_op_f64_promote_f32(comp_ctx, func_ctx))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I32_REINTERPRET_F32:
|
||||
if (!aot_compile_op_i32_reinterpret_f32(comp_ctx, func_ctx))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I64_REINTERPRET_F64:
|
||||
if (!aot_compile_op_i64_reinterpret_f64(comp_ctx, func_ctx))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F32_REINTERPRET_I32:
|
||||
if (!aot_compile_op_f32_reinterpret_i32(comp_ctx, func_ctx))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_F64_REINTERPRET_I64:
|
||||
if (!aot_compile_op_f64_reinterpret_i64(comp_ctx, func_ctx))
|
||||
return false;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Move all other exception blocks before got_exception block */
|
||||
for (i = 0; i < EXCE_NUM; i++) {
|
||||
if (func_ctx->exception_blocks[i])
|
||||
LLVMMoveBasicBlockBefore(func_ctx->exception_blocks[i],
|
||||
func_ctx->got_exception_block);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_wasm(AOTCompContext *comp_ctx)
|
||||
{
|
||||
char *msg = NULL;
|
||||
bool ret;
|
||||
uint32 i;
|
||||
|
||||
for (i = 0; i < comp_ctx->func_ctx_count; i++)
|
||||
if (!aot_compile_func(comp_ctx, i)) {
|
||||
#if 0
|
||||
LLVMDumpModule(comp_ctx->module);
|
||||
char *err;
|
||||
LLVMTargetMachineEmitToFile(comp_ctx->target_machine, comp_ctx->module,
|
||||
"./test.o", LLVMObjectFile, &err);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
LLVMDumpModule(comp_ctx->module);
|
||||
/* Clear error no, LLVMDumpModule may set errno */
|
||||
errno = 0;
|
||||
#endif
|
||||
|
||||
ret = LLVMVerifyModule(comp_ctx->module, LLVMPrintMessageAction, &msg);
|
||||
if (!ret && msg) {
|
||||
if (msg[0] != '\0') {
|
||||
aot_set_last_error(msg);
|
||||
LLVMDisposeMessage(msg);
|
||||
return false;
|
||||
}
|
||||
LLVMDisposeMessage(msg);
|
||||
}
|
||||
|
||||
if (comp_ctx->optimize) {
|
||||
LLVMInitializeFunctionPassManager(comp_ctx->pass_mgr);
|
||||
for (i = 0; i < comp_ctx->func_ctx_count; i++)
|
||||
LLVMRunFunctionPassManager(comp_ctx->pass_mgr,
|
||||
comp_ctx->func_ctxes[i]->func);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_emit_llvm_file(AOTCompContext *comp_ctx, const char *file_name)
|
||||
{
|
||||
char *err = NULL;
|
||||
|
||||
if (LLVMPrintModuleToFile(comp_ctx->module, file_name, &err) != 0) {
|
||||
if (err) {
|
||||
LLVMDisposeMessage(err);
|
||||
err = NULL;
|
||||
}
|
||||
aot_set_last_error("emit llvm ir to file failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_emit_object_file(AOTCompContext *comp_ctx, char *file_name)
|
||||
{
|
||||
char *err = NULL;
|
||||
|
||||
if (LLVMTargetMachineEmitToFile(comp_ctx->target_machine,
|
||||
comp_ctx->module,
|
||||
file_name,
|
||||
LLVMObjectFile,
|
||||
&err) != 0) {
|
||||
if (err) {
|
||||
LLVMDisposeMessage(err);
|
||||
err = NULL;
|
||||
}
|
||||
aot_set_last_error("emit elf to memory buffer failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
248
core/iwasm/compilation/aot_compiler.h
Normal file
248
core/iwasm/compilation/aot_compiler.h
Normal file
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _AOT_COMPILER_H_
|
||||
#define _AOT_COMPILER_H_
|
||||
|
||||
#include "aot.h"
|
||||
#include "aot_llvm.h"
|
||||
#include "bh_memory.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum IntCond {
|
||||
INT_EQZ = 0,
|
||||
INT_EQ,
|
||||
INT_NE,
|
||||
INT_LT_S,
|
||||
INT_LT_U,
|
||||
INT_GT_S,
|
||||
INT_GT_U,
|
||||
INT_LE_S,
|
||||
INT_LE_U,
|
||||
INT_GE_S,
|
||||
INT_GE_U
|
||||
} IntCond;
|
||||
|
||||
typedef enum FloatCond {
|
||||
FLOAT_EQ = 0,
|
||||
FLOAT_NE,
|
||||
FLOAT_LT,
|
||||
FLOAT_GT,
|
||||
FLOAT_LE,
|
||||
FLOAT_GE
|
||||
} FloatCond;
|
||||
|
||||
typedef enum IntArithmetic {
|
||||
INT_ADD = 0,
|
||||
INT_SUB,
|
||||
INT_MUL,
|
||||
INT_DIV_S,
|
||||
INT_DIV_U,
|
||||
INT_REM_S,
|
||||
INT_REM_U
|
||||
} IntArithmetic;
|
||||
|
||||
typedef enum IntBitwise {
|
||||
INT_AND = 0,
|
||||
INT_OR,
|
||||
INT_XOR,
|
||||
} IntBitwise;
|
||||
|
||||
typedef enum IntShift {
|
||||
INT_SHL = 0,
|
||||
INT_SHR_S,
|
||||
INT_SHR_U,
|
||||
INT_ROTL,
|
||||
INT_ROTR
|
||||
} IntShift;
|
||||
|
||||
typedef enum FloatMath {
|
||||
FLOAT_ABS = 0,
|
||||
FLOAT_NEG,
|
||||
FLOAT_CEIL,
|
||||
FLOAT_FLOOR,
|
||||
FLOAT_TRUNC,
|
||||
FLOAT_NEAREST,
|
||||
FLOAT_SQRT
|
||||
} FloatMath;
|
||||
|
||||
typedef enum FloatArithmetic {
|
||||
FLOAT_ADD = 0,
|
||||
FLOAT_SUB,
|
||||
FLOAT_MUL,
|
||||
FLOAT_DIV,
|
||||
FLOAT_MIN,
|
||||
FLOAT_MAX
|
||||
} FloatArithmetic;
|
||||
|
||||
#define CHECK_STACK() do { \
|
||||
if (!func_ctx->block_stack.block_list_end) { \
|
||||
aot_set_last_error("WASM block stack underflow."); \
|
||||
goto fail; \
|
||||
} \
|
||||
if (!func_ctx->block_stack.block_list_end-> \
|
||||
value_stack.value_list_end) { \
|
||||
aot_set_last_error("WASM data stack underflow."); \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define POP(llvm_value, value_type) do { \
|
||||
AOTValue *aot_value; \
|
||||
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))) { \
|
||||
aot_set_last_error("invalid WASM stack data type."); \
|
||||
wasm_free(aot_value); \
|
||||
goto fail; \
|
||||
} \
|
||||
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_free(aot_value); \
|
||||
goto fail; \
|
||||
} \
|
||||
} \
|
||||
wasm_free(aot_value); \
|
||||
} while (0)
|
||||
|
||||
#define POP_I32(v) POP(v, VALUE_TYPE_I32)
|
||||
#define POP_I64(v) POP(v, VALUE_TYPE_I64)
|
||||
#define POP_F32(v) POP(v, VALUE_TYPE_F32)
|
||||
#define POP_F64(v) POP(v, VALUE_TYPE_F64)
|
||||
|
||||
#define POP_COND(llvm_value) do { \
|
||||
AOTValue *aot_value; \
|
||||
CHECK_STACK(); \
|
||||
aot_value = aot_value_stack_pop \
|
||||
(&func_ctx->block_stack.block_list_end->value_stack); \
|
||||
if (aot_value->type != VALUE_TYPE_I1 \
|
||||
&& aot_value->type != VALUE_TYPE_I32) { \
|
||||
aot_set_last_error("invalid WASM stack data type."); \
|
||||
wasm_free(aot_value); \
|
||||
goto fail; \
|
||||
} \
|
||||
if (aot_value->type == VALUE_TYPE_I1) \
|
||||
llvm_value = aot_value->value; \
|
||||
else { \
|
||||
if (!(llvm_value = LLVMBuildICmp(comp_ctx->builder, \
|
||||
LLVMIntNE, aot_value->value, I32_ZERO, \
|
||||
"i1_cond"))){ \
|
||||
aot_set_last_error("llvm build trunc failed."); \
|
||||
wasm_free(aot_value); \
|
||||
goto fail; \
|
||||
} \
|
||||
} \
|
||||
wasm_free(aot_value); \
|
||||
} while (0)
|
||||
|
||||
#define PUSH(llvm_value, value_type) do { \
|
||||
AOTValue *aot_value; \
|
||||
if (!func_ctx->block_stack.block_list_end) { \
|
||||
aot_set_last_error("WASM block stack underflow."); \
|
||||
goto fail; \
|
||||
} \
|
||||
aot_value = wasm_malloc(sizeof(AOTValue)); \
|
||||
memset(aot_value, 0, sizeof(AOTValue)); \
|
||||
if (!aot_value) { \
|
||||
aot_set_last_error("allocate memory failed."); \
|
||||
goto fail; \
|
||||
} \
|
||||
aot_value->type = value_type; \
|
||||
aot_value->value = llvm_value; \
|
||||
aot_value_stack_push \
|
||||
(&func_ctx->block_stack.block_list_end->value_stack,\
|
||||
aot_value); \
|
||||
} while (0)
|
||||
|
||||
#define PUSH_I32(v) PUSH(v, VALUE_TYPE_I32)
|
||||
#define PUSH_I64(v) PUSH(v, VALUE_TYPE_I64)
|
||||
#define PUSH_F32(v) PUSH(v, VALUE_TYPE_F32)
|
||||
#define PUSH_F64(v) PUSH(v, VALUE_TYPE_F64)
|
||||
#define PUSH_COND(v) PUSH(v, VALUE_TYPE_I1)
|
||||
|
||||
#define TO_LLVM_TYPE(wasm_type) \
|
||||
wasm_type_to_llvm_type(&comp_ctx->basic_types, wasm_type)
|
||||
|
||||
#define I32_TYPE comp_ctx->basic_types.int32_type
|
||||
#define I64_TYPE comp_ctx->basic_types.int64_type
|
||||
#define F32_TYPE comp_ctx->basic_types.float32_type
|
||||
#define F64_TYPE comp_ctx->basic_types.float64_type
|
||||
#define VOID_TYPE comp_ctx->basic_types.void_type
|
||||
#define INT1_TYPE comp_ctx->basic_types.int1_type
|
||||
#define INT8_TYPE comp_ctx->basic_types.int8_type
|
||||
#define INT16_TYPE comp_ctx->basic_types.int16_type
|
||||
#define MD_TYPE comp_ctx->basic_types.meta_data_type
|
||||
#define INT8_PTR_TYPE comp_ctx->basic_types.int8_ptr_type
|
||||
#define INT16_PTR_TYPE comp_ctx->basic_types.int16_ptr_type
|
||||
#define INT32_PTR_TYPE comp_ctx->basic_types.int32_ptr_type
|
||||
#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 VOID_PTR_TYPE comp_ctx->basic_types.void_ptr_type
|
||||
|
||||
#define I32_CONST(v) LLVMConstInt(I32_TYPE, v, true)
|
||||
#define I64_CONST(v) LLVMConstInt(I64_TYPE, v, true)
|
||||
#define F32_CONST(v) LLVMConstReal(F32_TYPE, v)
|
||||
#define F64_CONST(v) LLVMConstReal(F64_TYPE, v)
|
||||
#define I8_CONST(v) LLVMConstInt(INT8_TYPE, v, true)
|
||||
|
||||
#define I8_ZERO (comp_ctx->llvm_consts.i8_zero)
|
||||
#define I32_ZERO (comp_ctx->llvm_consts.i32_zero)
|
||||
#define I64_ZERO (comp_ctx->llvm_consts.i64_zero)
|
||||
#define F32_ZERO (comp_ctx->llvm_consts.f32_zero)
|
||||
#define F64_ZERO (comp_ctx->llvm_consts.f64_zero)
|
||||
#define I32_ONE (comp_ctx->llvm_consts.i32_one)
|
||||
#define I32_TWO (comp_ctx->llvm_consts.i32_two)
|
||||
#define I32_FOUR (comp_ctx->llvm_consts.i32_four)
|
||||
#define I32_EIGHT (comp_ctx->llvm_consts.i32_eight)
|
||||
#define I32_NEG_ONE (comp_ctx->llvm_consts.i32_neg_one)
|
||||
#define I64_NEG_ONE (comp_ctx->llvm_consts.i64_neg_one)
|
||||
#define I32_MIN (comp_ctx->llvm_consts.i32_min)
|
||||
#define I64_MIN (comp_ctx->llvm_consts.i64_min)
|
||||
#define I32_31 (comp_ctx->llvm_consts.i32_31)
|
||||
#define I32_32 (comp_ctx->llvm_consts.i32_32)
|
||||
#define I64_63 (comp_ctx->llvm_consts.i64_63)
|
||||
#define I64_64 (comp_ctx->llvm_consts.i64_64)
|
||||
|
||||
#define CHECK_LLVM_CONST(v) do { \
|
||||
if (!v) { \
|
||||
aot_set_last_error("create llvm const failed."); \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
bool
|
||||
aot_compile_wasm(AOTCompContext *comp_ctx);
|
||||
|
||||
bool
|
||||
aot_emit_llvm_file(AOTCompContext *comp_ctx, const char *file_name);
|
||||
|
||||
bool
|
||||
aot_emit_aot_file(AOTCompContext *comp_ctx,
|
||||
AOTCompData *comp_data,
|
||||
const char *file_name);
|
||||
|
||||
bool
|
||||
aot_emit_object_file(AOTCompContext *comp_ctx, char *file_name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _AOT_COMPILER_H_ */
|
||||
|
||||
1934
core/iwasm/compilation/aot_emit_aot_file.c
Normal file
1934
core/iwasm/compilation/aot_emit_aot_file.c
Normal file
File diff suppressed because it is too large
Load Diff
196
core/iwasm/compilation/aot_emit_compare.c
Normal file
196
core/iwasm/compilation/aot_emit_compare.c
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "aot_emit_compare.h"
|
||||
|
||||
static bool
|
||||
int_cond_to_llvm_op(IntCond cond, LLVMIntPredicate *op)
|
||||
{
|
||||
if (cond < INT_EQZ || cond > INT_GE_U)
|
||||
return false;
|
||||
|
||||
switch (cond) {
|
||||
case INT_EQZ:
|
||||
case INT_EQ:
|
||||
*op = LLVMIntEQ;
|
||||
break;
|
||||
case INT_NE:
|
||||
*op = LLVMIntNE;
|
||||
break;
|
||||
case INT_LT_S:
|
||||
*op = LLVMIntSLT;
|
||||
break;
|
||||
case INT_LT_U:
|
||||
*op = LLVMIntULT;
|
||||
break;
|
||||
case INT_GT_S:
|
||||
*op = LLVMIntSGT;
|
||||
break;
|
||||
case INT_GT_U:
|
||||
*op = LLVMIntUGT;
|
||||
break;
|
||||
case INT_LE_S:
|
||||
*op = LLVMIntSLE;
|
||||
break;
|
||||
case INT_LE_U:
|
||||
*op = LLVMIntULE;
|
||||
break;
|
||||
case INT_GE_S:
|
||||
*op = LLVMIntSGE;
|
||||
break;
|
||||
case INT_GE_U:
|
||||
*op = LLVMIntUGE;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
float_cond_to_llvm_op(FloatCond cond, LLVMRealPredicate *op)
|
||||
{
|
||||
if (cond < FLOAT_EQ || cond > FLOAT_GE)
|
||||
return false;
|
||||
|
||||
switch (cond) {
|
||||
case FLOAT_EQ:
|
||||
*op = LLVMRealOEQ;
|
||||
break;
|
||||
case FLOAT_NE:
|
||||
*op = LLVMRealUNE;
|
||||
break;
|
||||
case FLOAT_LT:
|
||||
*op = LLVMRealOLT;
|
||||
break;
|
||||
case FLOAT_GT:
|
||||
*op = LLVMRealOGT;
|
||||
break;
|
||||
case FLOAT_LE:
|
||||
*op = LLVMRealOLE;
|
||||
break;
|
||||
case FLOAT_GE:
|
||||
*op = LLVMRealOGE;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_compare(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
IntCond cond)
|
||||
{
|
||||
LLVMIntPredicate op;
|
||||
LLVMValueRef lhs, rhs, res;
|
||||
|
||||
if (!int_cond_to_llvm_op(cond, &op)) {
|
||||
aot_set_last_error("invalid WASM condition opcode");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cond == INT_EQZ)
|
||||
rhs = I32_ZERO;
|
||||
else
|
||||
POP_I32(rhs);
|
||||
|
||||
POP_I32(lhs);
|
||||
|
||||
if (!(res = LLVMBuildICmp(comp_ctx->builder, op, lhs, rhs, "i32_cmp"))) {
|
||||
aot_set_last_error("llvm build compare failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PUSH_COND(res);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_compare(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
IntCond cond)
|
||||
{
|
||||
LLVMIntPredicate op;
|
||||
LLVMValueRef lhs, rhs, res;
|
||||
|
||||
if (!int_cond_to_llvm_op(cond, &op)) {
|
||||
aot_set_last_error("invalid WASM condition opcode");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cond == INT_EQZ)
|
||||
rhs = I64_CONST(0);
|
||||
else
|
||||
POP_I64(rhs);
|
||||
|
||||
POP_I64(lhs);
|
||||
|
||||
if (!(res = LLVMBuildICmp(comp_ctx->builder, op, lhs, rhs, "i64_cmp"))) {
|
||||
aot_set_last_error("llvm build compare failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PUSH_COND(res);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_f32_compare(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
FloatCond cond)
|
||||
{
|
||||
LLVMRealPredicate op;
|
||||
LLVMValueRef lhs, rhs, res;
|
||||
|
||||
if (!float_cond_to_llvm_op(cond, &op)) {
|
||||
aot_set_last_error("invalid WASM condition opcode");
|
||||
return false;
|
||||
}
|
||||
|
||||
POP_F32(rhs);
|
||||
POP_F32(lhs);
|
||||
|
||||
if (!(res = LLVMBuildFCmp(comp_ctx->builder, op, lhs, rhs, "f32_cmp"))) {
|
||||
aot_set_last_error("llvm build compare failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PUSH_COND(res);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_f64_compare(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
FloatCond cond)
|
||||
{
|
||||
LLVMRealPredicate op;
|
||||
LLVMValueRef lhs, rhs, res;
|
||||
|
||||
if (!float_cond_to_llvm_op(cond, &op)) {
|
||||
aot_set_last_error("invalid WASM condition opcode");
|
||||
return false;
|
||||
}
|
||||
|
||||
POP_F64(rhs);
|
||||
POP_F64(lhs);
|
||||
|
||||
if (!(res = LLVMBuildFCmp(comp_ctx->builder, op, lhs, rhs, "f64_cmp"))) {
|
||||
aot_set_last_error("llvm build compare failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PUSH_COND(res);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
37
core/iwasm/compilation/aot_emit_compare.h
Normal file
37
core/iwasm/compilation/aot_emit_compare.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _AOT_EMIT_COMPARE_H_
|
||||
#define _AOT_EMIT_COMPARE_H_
|
||||
|
||||
#include "aot_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_compare(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
IntCond cond);
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_compare(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
IntCond cond);
|
||||
|
||||
bool
|
||||
aot_compile_op_f32_compare(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
FloatCond cond);
|
||||
|
||||
bool
|
||||
aot_compile_op_f64_compare(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
FloatCond cond);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _AOT_EMIT_COMPARE_H_ */
|
||||
|
||||
115
core/iwasm/compilation/aot_emit_const.c
Normal file
115
core/iwasm/compilation/aot_emit_const.c
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "aot_emit_const.h"
|
||||
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_const(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
int32 i32_const)
|
||||
{
|
||||
LLVMValueRef value = I32_CONST((uint32)i32_const);
|
||||
CHECK_LLVM_CONST(value);
|
||||
PUSH_I32(value);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_const(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
int64 i64_const)
|
||||
{
|
||||
LLVMValueRef value = I64_CONST((uint64)i64_const);
|
||||
CHECK_LLVM_CONST(value);
|
||||
PUSH_I64(value);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_f32_const(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
float32 f32_const)
|
||||
{
|
||||
LLVMValueRef alloca, value;
|
||||
|
||||
if (!isnan(f32_const)) {
|
||||
value = F32_CONST(f32_const);
|
||||
CHECK_LLVM_CONST(value);
|
||||
PUSH_F32(value);
|
||||
}
|
||||
else {
|
||||
int32 i32_const;
|
||||
memcpy(&i32_const, &f32_const, sizeof(int32));
|
||||
if (!(alloca = LLVMBuildAlloca(comp_ctx->builder,
|
||||
INT32_PTR_TYPE, "i32_ptr"))) {
|
||||
aot_set_last_error("llvm build alloca failed.");
|
||||
return false;
|
||||
}
|
||||
if (!LLVMBuildStore(comp_ctx->builder,
|
||||
I32_CONST((uint32)i32_const), alloca)) {
|
||||
aot_set_last_error("llvm build store failed.");
|
||||
return false;
|
||||
}
|
||||
if (!(alloca = LLVMBuildBitCast(comp_ctx->builder,
|
||||
alloca, F32_PTR_TYPE, "f32_ptr"))) {
|
||||
aot_set_last_error("llvm build bitcast failed.");
|
||||
return false;
|
||||
}
|
||||
if (!(value = LLVMBuildLoad(comp_ctx->builder, alloca, ""))) {
|
||||
aot_set_last_error("llvm build load failed.");
|
||||
return false;
|
||||
}
|
||||
PUSH_F32(value);
|
||||
}
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_f64_const(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
float64 f64_const)
|
||||
{
|
||||
LLVMValueRef alloca, value;
|
||||
|
||||
if (!isnan(f64_const)) {
|
||||
value = F64_CONST(f64_const);
|
||||
CHECK_LLVM_CONST(value);
|
||||
PUSH_F64(value);
|
||||
}
|
||||
else {
|
||||
int64 i64_const;
|
||||
memcpy(&i64_const, &f64_const, sizeof(int64));
|
||||
if (!(alloca = LLVMBuildAlloca(comp_ctx->builder,
|
||||
I64_TYPE, "i64_ptr"))) {
|
||||
aot_set_last_error("llvm build alloca failed.");
|
||||
return false;
|
||||
}
|
||||
value = I64_CONST((uint64)i64_const);
|
||||
CHECK_LLVM_CONST(value);
|
||||
if (!LLVMBuildStore(comp_ctx->builder, value, alloca)) {
|
||||
aot_set_last_error("llvm build store failed.");
|
||||
return false;
|
||||
}
|
||||
if (!(alloca = LLVMBuildBitCast(comp_ctx->builder,
|
||||
alloca, F64_PTR_TYPE, "f64_ptr"))) {
|
||||
aot_set_last_error("llvm build bitcast failed.");
|
||||
return false;
|
||||
}
|
||||
if (!(value = LLVMBuildLoad(comp_ctx->builder, alloca, ""))) {
|
||||
aot_set_last_error("llvm build load failed.");
|
||||
return false;
|
||||
}
|
||||
PUSH_F64(value);
|
||||
}
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
36
core/iwasm/compilation/aot_emit_const.h
Normal file
36
core/iwasm/compilation/aot_emit_const.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _AOT_EMIT_CONST_H_
|
||||
#define _AOT_EMIT_CONST_H_
|
||||
|
||||
#include "aot_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_const(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
int32 i32_const);
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_const(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
int64 i64_const);
|
||||
|
||||
bool
|
||||
aot_compile_op_f32_const(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
float32 f32_const);
|
||||
|
||||
bool
|
||||
aot_compile_op_f64_const(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
float64 f64_const);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _AOT_EMIT_CONST_H_ */
|
||||
|
||||
672
core/iwasm/compilation/aot_emit_control.c
Normal file
672
core/iwasm/compilation/aot_emit_control.c
Normal file
@ -0,0 +1,672 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "aot_emit_control.h"
|
||||
#include "aot_emit_exception.h"
|
||||
#include "../aot/aot_runtime.h"
|
||||
#include "../interpreter/wasm_loader.h"
|
||||
#include "bh_memory.h"
|
||||
|
||||
static char *block_name_prefix[] = { "block", "loop", "if" };
|
||||
static char *block_name_suffix[] = { "begin", "else", "end" };
|
||||
|
||||
enum {
|
||||
LABEL_BEGIN = 0,
|
||||
LABEL_ELSE,
|
||||
LABEL_END
|
||||
};
|
||||
|
||||
static void
|
||||
format_block_name(char *name, uint32 name_size,
|
||||
uint32 block_index, uint32 block_type,
|
||||
uint32 label_type)
|
||||
{
|
||||
if (block_type != BLOCK_TYPE_FUNCTION)
|
||||
snprintf(name, name_size, "%s%d%s%s",
|
||||
block_name_prefix[block_type], block_index,
|
||||
"_", block_name_suffix[label_type]);
|
||||
else
|
||||
snprintf(name, name_size, "%s", "func_end");
|
||||
}
|
||||
|
||||
#define CREATE_BLOCK(new_llvm_block, name) do { \
|
||||
if (!(new_llvm_block = \
|
||||
LLVMAppendBasicBlockInContext(comp_ctx->context, \
|
||||
func_ctx->func, \
|
||||
name))) { \
|
||||
aot_set_last_error("add LLVM basic block failed.");\
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CURR_BLOCK() LLVMGetInsertBlock(comp_ctx->builder)
|
||||
|
||||
#define MOVE_BLOCK_AFTER(llvm_block, llvm_block_after) \
|
||||
LLVMMoveBasicBlockAfter(llvm_block, llvm_block_after)
|
||||
|
||||
#define MOVE_BLOCK_AFTER_CURR(llvm_block) \
|
||||
LLVMMoveBasicBlockAfter(llvm_block, CURR_BLOCK())
|
||||
|
||||
#define MOVE_BLOCK_BEFORE(llvm_block, llvm_block_before) \
|
||||
LLVMMoveBasicBlockBefore(llvm_block, llvm_block_before)
|
||||
|
||||
#define BUILD_BR(llvm_block) do { \
|
||||
if (!LLVMBuildBr(comp_ctx->builder, llvm_block)) { \
|
||||
aot_set_last_error("llvm build br failed."); \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BUILD_COND_BR(value_if, block_then, block_else) do {\
|
||||
if (!LLVMBuildCondBr(comp_ctx->builder, value_if, \
|
||||
block_then, block_else)) { \
|
||||
aot_set_last_error("llvm build cond br failed."); \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SET_BUILDER_POS(llvm_block) \
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, llvm_block)
|
||||
|
||||
#define CREATE_RETURN_VALUE_PHI(block) do { \
|
||||
if (block->return_type != VALUE_TYPE_VOID \
|
||||
&& !block->return_value_phi) { \
|
||||
LLVMBasicBlockRef block_curr = CURR_BLOCK(); \
|
||||
SET_BUILDER_POS(block->llvm_end_block); \
|
||||
if (!(block->return_value_phi = \
|
||||
LLVMBuildPhi(comp_ctx->builder, \
|
||||
TO_LLVM_TYPE(block->return_type),\
|
||||
"phi"))) { \
|
||||
aot_set_last_error("llvm build phi failed."); \
|
||||
goto fail; \
|
||||
} \
|
||||
SET_BUILDER_POS(block_curr); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ADD_TO_RETURN_PHI(block, value) do { \
|
||||
LLVMBasicBlockRef block_curr = CURR_BLOCK(); \
|
||||
LLVMAddIncoming(block->return_value_phi, \
|
||||
&value, &block_curr, 1); \
|
||||
} while (0)
|
||||
|
||||
|
||||
static LLVMBasicBlockRef
|
||||
find_next_llvm_end_block(AOTBlock *block)
|
||||
{
|
||||
block = block->prev;
|
||||
while (block && !block->llvm_end_block)
|
||||
block = block->prev;
|
||||
return block ? block->llvm_end_block : NULL;
|
||||
}
|
||||
|
||||
static AOTBlock*
|
||||
get_target_block(AOTFuncContext *func_ctx, uint32 br_depth)
|
||||
{
|
||||
uint32 i = br_depth;
|
||||
AOTBlock *block = func_ctx->block_stack.block_list_end;
|
||||
|
||||
while (i-- > 0 && block) {
|
||||
block = block->prev;
|
||||
}
|
||||
|
||||
if (!block) {
|
||||
aot_set_last_error("WASM block stack underflow.");
|
||||
return NULL;
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_next_reachable_block(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint8 **p_frame_ip)
|
||||
{
|
||||
AOTBlock *block = func_ctx->block_stack.block_list_end;
|
||||
AOTBlock *block_prev;
|
||||
uint8 *frame_ip;
|
||||
|
||||
if (block->block_type == BLOCK_TYPE_IF
|
||||
&& block->llvm_else_block
|
||||
&& !block->skip_wasm_code_else
|
||||
&& *p_frame_ip <= block->wasm_code_else) {
|
||||
/* Clear value stack and start to translate else branch */
|
||||
aot_value_stack_destroy(&block->value_stack);
|
||||
SET_BUILDER_POS(block->llvm_else_block);
|
||||
*p_frame_ip = block->wasm_code_else + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
while (block && !block->is_reachable) {
|
||||
block_prev = block->prev;
|
||||
block = aot_block_stack_pop(&func_ctx->block_stack);
|
||||
|
||||
if (block->block_type == BLOCK_TYPE_IF
|
||||
&& block->llvm_end_block) {
|
||||
LLVMDeleteBasicBlock(block->llvm_end_block);
|
||||
block->llvm_end_block = NULL;
|
||||
}
|
||||
|
||||
frame_ip = block->wasm_code_end;
|
||||
aot_block_destroy(block);
|
||||
block = block_prev;
|
||||
}
|
||||
|
||||
if (!block) {
|
||||
*p_frame_ip = frame_ip + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
*p_frame_ip = block->wasm_code_end + 1;
|
||||
SET_BUILDER_POS(block->llvm_end_block);
|
||||
|
||||
/* Pop block, push its return value, and destroy the block */
|
||||
block = aot_block_stack_pop(&func_ctx->block_stack);
|
||||
if (block->return_type != VALUE_TYPE_VOID) {
|
||||
bh_assert(block->return_value_phi);
|
||||
if (block->block_type != BLOCK_TYPE_FUNCTION)
|
||||
PUSH(block->return_value_phi, block->return_type);
|
||||
else
|
||||
LLVMBuildRet(comp_ctx->builder, block->return_value_phi);
|
||||
}
|
||||
else if (block->block_type == BLOCK_TYPE_FUNCTION) {
|
||||
LLVMBuildRetVoid(comp_ctx->builder);
|
||||
}
|
||||
aot_block_destroy(block);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint8 **p_frame_ip, uint8 *frame_ip_end,
|
||||
uint32 block_type, uint32 block_ret_type)
|
||||
{
|
||||
AOTBlock *block;
|
||||
uint8 *else_addr, *end_addr;
|
||||
LLVMValueRef value;
|
||||
char name[32];
|
||||
|
||||
/* Check block stack */
|
||||
if (!func_ctx->block_stack.block_list_end) {
|
||||
aot_set_last_error("WASM block stack underflow.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get block info */
|
||||
if (!(wasm_loader_find_block_addr(comp_ctx->comp_data->wasm_module,
|
||||
*p_frame_ip, frame_ip_end, (uint8)block_type,
|
||||
&else_addr, &end_addr, NULL, 0))) {
|
||||
aot_set_last_error("find block end addr failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Allocate memory */
|
||||
if (!(block = wasm_malloc(sizeof(AOTBlock)))) {
|
||||
aot_set_last_error("allocate memory failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Init aot block data */
|
||||
memset(block, 0, sizeof(AOTBlock));
|
||||
block->block_type = block_type;
|
||||
block->return_type = (uint8)block_ret_type;
|
||||
block->wasm_code_else = else_addr;
|
||||
block->wasm_code_end = end_addr;
|
||||
block->block_index = func_ctx->block_stack.block_index[block_type];
|
||||
func_ctx->block_stack.block_index[block_type]++;
|
||||
|
||||
if (block_type == BLOCK_TYPE_BLOCK
|
||||
|| block_type == BLOCK_TYPE_LOOP) {
|
||||
/* Create block */
|
||||
format_block_name(name, sizeof(name),
|
||||
block->block_index, block_type, LABEL_BEGIN);
|
||||
CREATE_BLOCK(block->llvm_entry_block, name);
|
||||
MOVE_BLOCK_AFTER_CURR(block->llvm_entry_block);
|
||||
/* Jump to the entry block */
|
||||
BUILD_BR(block->llvm_entry_block);
|
||||
/* Start to translate the block */
|
||||
SET_BUILDER_POS(block->llvm_entry_block);
|
||||
aot_block_stack_push(&func_ctx->block_stack, block);
|
||||
}
|
||||
else if (block_type == BLOCK_TYPE_IF) {
|
||||
POP_COND(value);
|
||||
if (!LLVMIsConstant(value)) {
|
||||
/* Compare value is not constant, create condition br IR */
|
||||
/* Create entry block */
|
||||
format_block_name(name, sizeof(name),
|
||||
block->block_index, block_type, LABEL_BEGIN);
|
||||
CREATE_BLOCK(block->llvm_entry_block, name);
|
||||
MOVE_BLOCK_AFTER_CURR(block->llvm_entry_block);
|
||||
|
||||
/* Create end block */
|
||||
format_block_name(name, sizeof(name),
|
||||
block->block_index, block_type, LABEL_END);
|
||||
CREATE_BLOCK(block->llvm_end_block, name);
|
||||
MOVE_BLOCK_AFTER(block->llvm_end_block, block->llvm_entry_block);
|
||||
|
||||
if (else_addr) {
|
||||
/* Create else block */
|
||||
format_block_name(name, sizeof(name),
|
||||
block->block_index, block_type, LABEL_ELSE);
|
||||
CREATE_BLOCK(block->llvm_else_block, name);
|
||||
MOVE_BLOCK_AFTER(block->llvm_else_block, block->llvm_entry_block);
|
||||
/* Create condition br IR */
|
||||
BUILD_COND_BR(value, block->llvm_entry_block,
|
||||
block->llvm_else_block);
|
||||
}
|
||||
else {
|
||||
/* Create condition br IR */
|
||||
BUILD_COND_BR(value, block->llvm_entry_block,
|
||||
block->llvm_end_block);
|
||||
block->is_reachable = true;
|
||||
}
|
||||
/* Start to translate if branch of BLOCK if */
|
||||
SET_BUILDER_POS(block->llvm_entry_block);
|
||||
aot_block_stack_push(&func_ctx->block_stack, block);
|
||||
}
|
||||
else {
|
||||
if ((int32)LLVMConstIntGetZExtValue(value) != 0) {
|
||||
/* Compare value is not 0, condtion is true, else branch of
|
||||
BLOCK if cannot be reached */
|
||||
block->skip_wasm_code_else = true;
|
||||
/* Create entry block */
|
||||
format_block_name(name, sizeof(name),
|
||||
block->block_index, block_type, LABEL_BEGIN);
|
||||
CREATE_BLOCK(block->llvm_entry_block, name);
|
||||
MOVE_BLOCK_AFTER_CURR(block->llvm_entry_block);
|
||||
/* Jump to the entry block */
|
||||
BUILD_BR(block->llvm_entry_block);
|
||||
/* Start to translate the if branch */
|
||||
SET_BUILDER_POS(block->llvm_entry_block);
|
||||
aot_block_stack_push(&func_ctx->block_stack, block);
|
||||
}
|
||||
else {
|
||||
/* Compare value is not 0, condtion is false, if branch of
|
||||
BLOCK if cannot be reached */
|
||||
if (else_addr) {
|
||||
/* Create else block */
|
||||
format_block_name(name, sizeof(name),
|
||||
block->block_index, block_type, LABEL_ELSE);
|
||||
CREATE_BLOCK(block->llvm_else_block, name);
|
||||
MOVE_BLOCK_AFTER_CURR(block->llvm_else_block);
|
||||
/* Jump to the else block */
|
||||
BUILD_BR(block->llvm_else_block);
|
||||
/* Start to translate the else branch */
|
||||
SET_BUILDER_POS(block->llvm_else_block);
|
||||
*p_frame_ip = else_addr + 1;
|
||||
aot_block_stack_push(&func_ctx->block_stack, block);
|
||||
}
|
||||
else {
|
||||
if (block->return_type != VALUE_TYPE_VOID) {
|
||||
aot_set_last_error("WASM value stack underflow.");
|
||||
goto fail;
|
||||
}
|
||||
/* skip the block */
|
||||
wasm_free(block);
|
||||
*p_frame_ip = end_addr + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
aot_set_last_error("Invalid block type.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return true;
|
||||
fail:
|
||||
wasm_free(block);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_else(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint8 **p_frame_ip)
|
||||
{
|
||||
AOTBlock *block = func_ctx->block_stack.block_list_end;
|
||||
LLVMValueRef value;
|
||||
char name[32];
|
||||
|
||||
/* Check block */
|
||||
if (!block) {
|
||||
aot_set_last_error("WASM block stack underflow.");
|
||||
return false;
|
||||
}
|
||||
if (block->block_type != BLOCK_TYPE_IF
|
||||
|| (!block->skip_wasm_code_else
|
||||
&& !block->llvm_else_block)) {
|
||||
aot_set_last_error("Invalid WASM block type.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Create end block if needed */
|
||||
if (!block->llvm_end_block) {
|
||||
format_block_name(name, sizeof(name),
|
||||
block->block_index, block->block_type, LABEL_END);
|
||||
CREATE_BLOCK(block->llvm_end_block, name);
|
||||
if (block->llvm_else_block)
|
||||
MOVE_BLOCK_AFTER(block->llvm_end_block, block->llvm_else_block);
|
||||
else
|
||||
MOVE_BLOCK_AFTER_CURR(block->llvm_end_block);
|
||||
}
|
||||
|
||||
block->is_reachable = true;
|
||||
|
||||
/* Comes from the if branch of BLOCK if */
|
||||
if (block->return_type != VALUE_TYPE_VOID) {
|
||||
POP(value, block->return_type);
|
||||
CREATE_RETURN_VALUE_PHI(block);
|
||||
ADD_TO_RETURN_PHI(block, value);
|
||||
}
|
||||
|
||||
/* Jump to end block */
|
||||
BUILD_BR(block->llvm_end_block);
|
||||
|
||||
if (!block->skip_wasm_code_else
|
||||
&& block->llvm_else_block) {
|
||||
/* Clear value stack and start to translate else branch */
|
||||
aot_value_stack_destroy(&block->value_stack);
|
||||
SET_BUILDER_POS(block->llvm_else_block);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* No else branch or no need to translate else branch */
|
||||
block->is_reachable = true;
|
||||
return handle_next_reachable_block(comp_ctx, func_ctx, p_frame_ip);
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_end(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint8 **p_frame_ip)
|
||||
{
|
||||
AOTBlock *block;
|
||||
LLVMValueRef value;
|
||||
LLVMBasicBlockRef next_llvm_end_block;
|
||||
char name[32];
|
||||
|
||||
/* Check block stack */
|
||||
if (!(block = func_ctx->block_stack.block_list_end)) {
|
||||
aot_set_last_error("WASM block stack underflow.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Create the end block */
|
||||
if (!block->llvm_end_block) {
|
||||
format_block_name(name, sizeof(name),
|
||||
block->block_index, block->block_type, LABEL_END);
|
||||
CREATE_BLOCK(block->llvm_end_block, name);
|
||||
if ((next_llvm_end_block = find_next_llvm_end_block(block)))
|
||||
MOVE_BLOCK_BEFORE(block->llvm_end_block, next_llvm_end_block);
|
||||
}
|
||||
|
||||
/* Handle block return value */
|
||||
if (block->return_type != VALUE_TYPE_VOID) {
|
||||
POP(value, block->return_type);
|
||||
CREATE_RETURN_VALUE_PHI(block);
|
||||
ADD_TO_RETURN_PHI(block, value);
|
||||
}
|
||||
|
||||
/* Jump to the end block */
|
||||
BUILD_BR(block->llvm_end_block);
|
||||
|
||||
block->is_reachable = true;
|
||||
return handle_next_reachable_block(comp_ctx, func_ctx, p_frame_ip);
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_br(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 br_depth, uint8 **p_frame_ip)
|
||||
{
|
||||
AOTBlock *block_dst;
|
||||
LLVMValueRef value_ret;
|
||||
LLVMBasicBlockRef next_llvm_end_block;
|
||||
char name[32];
|
||||
|
||||
if (!(block_dst = get_target_block(func_ctx, br_depth))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (block_dst->block_type == BLOCK_TYPE_LOOP) {
|
||||
/* Dest block is Loop block */
|
||||
BUILD_BR(block_dst->llvm_entry_block);
|
||||
}
|
||||
else {
|
||||
/* Dest block is Block/If/Function block */
|
||||
/* Create the end block */
|
||||
if (!block_dst->llvm_end_block) {
|
||||
format_block_name(name, sizeof(name),
|
||||
block_dst->block_index, block_dst->block_type,
|
||||
LABEL_END);
|
||||
CREATE_BLOCK(block_dst->llvm_end_block, name);
|
||||
if ((next_llvm_end_block = find_next_llvm_end_block(block_dst)))
|
||||
MOVE_BLOCK_BEFORE(block_dst->llvm_end_block,
|
||||
next_llvm_end_block);
|
||||
}
|
||||
|
||||
block_dst->is_reachable = true;
|
||||
|
||||
/* Handle return value */
|
||||
if (block_dst->return_type != VALUE_TYPE_VOID) {
|
||||
POP(value_ret, block_dst->return_type);
|
||||
CREATE_RETURN_VALUE_PHI(block_dst);
|
||||
ADD_TO_RETURN_PHI(block_dst, value_ret);
|
||||
}
|
||||
|
||||
/* Jump to the end block */
|
||||
BUILD_BR(block_dst->llvm_end_block);
|
||||
}
|
||||
|
||||
return handle_next_reachable_block(comp_ctx, func_ctx, p_frame_ip);
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_br_if(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 br_depth, uint8 **p_frame_ip)
|
||||
{
|
||||
AOTBlock *block_dst;
|
||||
LLVMValueRef value_cmp, value_ret;
|
||||
LLVMBasicBlockRef llvm_else_block, next_llvm_end_block;
|
||||
char name[32];
|
||||
|
||||
POP_COND(value_cmp);
|
||||
if (!LLVMIsConstant(value_cmp)) {
|
||||
/* Compare value is not constant, create condition br IR */
|
||||
if (!(block_dst = get_target_block(func_ctx, br_depth))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Create llvm else block */
|
||||
CREATE_BLOCK(llvm_else_block, "br_if_else");
|
||||
MOVE_BLOCK_AFTER_CURR(llvm_else_block);
|
||||
|
||||
if (block_dst->block_type == BLOCK_TYPE_LOOP) {
|
||||
/* Dest block is Loop block */
|
||||
BUILD_COND_BR(value_cmp, block_dst->llvm_entry_block,
|
||||
llvm_else_block);
|
||||
|
||||
/* Move builder to else block */
|
||||
SET_BUILDER_POS(llvm_else_block);
|
||||
}
|
||||
else {
|
||||
/* Dest block is Block/If/Function block */
|
||||
/* Create the end block */
|
||||
if (!block_dst->llvm_end_block) {
|
||||
format_block_name(name, sizeof(name),
|
||||
block_dst->block_index, block_dst->block_type,
|
||||
LABEL_END);
|
||||
CREATE_BLOCK(block_dst->llvm_end_block, name);
|
||||
if ((next_llvm_end_block = find_next_llvm_end_block(block_dst)))
|
||||
MOVE_BLOCK_BEFORE(block_dst->llvm_end_block,
|
||||
next_llvm_end_block);
|
||||
}
|
||||
|
||||
/* Set reachable flag and create condtion br IR */
|
||||
block_dst->is_reachable = true;
|
||||
|
||||
/* Handle return value */
|
||||
if (block_dst->return_type != VALUE_TYPE_VOID) {
|
||||
POP(value_ret, block_dst->return_type);
|
||||
CREATE_RETURN_VALUE_PHI(block_dst);
|
||||
ADD_TO_RETURN_PHI(block_dst, value_ret);
|
||||
PUSH(value_ret, block_dst->return_type);
|
||||
}
|
||||
|
||||
/* Condition jump to end block */
|
||||
BUILD_COND_BR(value_cmp, block_dst->llvm_end_block,
|
||||
llvm_else_block);
|
||||
|
||||
/* Move builder to else block */
|
||||
SET_BUILDER_POS(llvm_else_block);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((int32)LLVMConstIntGetZExtValue(value_cmp) != 0) {
|
||||
/* Compare value is not 0, condtion is true, same as op_br */
|
||||
return aot_compile_op_br(comp_ctx, func_ctx, br_depth, p_frame_ip);
|
||||
}
|
||||
else {
|
||||
/* Compare value is not 0, condtion is false, skip br_if */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_br_table(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 *br_depths, uint32 br_count,
|
||||
uint8 **p_frame_ip)
|
||||
{
|
||||
uint32 i;
|
||||
LLVMValueRef value_switch, value_cmp, value_case, value_ret = NULL;
|
||||
LLVMBasicBlockRef default_llvm_block = NULL, target_llvm_block;
|
||||
LLVMBasicBlockRef next_llvm_end_block;
|
||||
AOTBlock *target_block;
|
||||
uint32 br_depth, depth_idx;
|
||||
char name[32];
|
||||
|
||||
POP_I32(value_cmp);
|
||||
if (!LLVMIsConstant(value_cmp)) {
|
||||
/* Compare value is not constant, create switch IR */
|
||||
for (i = 0; i <= br_count; i++) {
|
||||
target_block = get_target_block(func_ctx, br_depths[i]);
|
||||
if (!target_block)
|
||||
return false;
|
||||
|
||||
if (target_block->block_type != BLOCK_TYPE_LOOP) {
|
||||
/* Dest block is Block/If/Function block */
|
||||
/* Create the end block */
|
||||
if (!target_block->llvm_end_block) {
|
||||
format_block_name(name, sizeof(name),
|
||||
target_block->block_index,
|
||||
target_block->block_type,
|
||||
LABEL_END);
|
||||
CREATE_BLOCK(target_block->llvm_end_block, name);
|
||||
if ((next_llvm_end_block =
|
||||
find_next_llvm_end_block(target_block)))
|
||||
MOVE_BLOCK_BEFORE(target_block->llvm_end_block,
|
||||
next_llvm_end_block);
|
||||
}
|
||||
/* Handle return value */
|
||||
if (target_block->return_type != VALUE_TYPE_VOID) {
|
||||
POP(value_ret, target_block->return_type);
|
||||
CREATE_RETURN_VALUE_PHI(target_block);
|
||||
ADD_TO_RETURN_PHI(target_block, value_ret);
|
||||
PUSH(value_ret, target_block->return_type);
|
||||
}
|
||||
target_block->is_reachable = true;
|
||||
if (i == br_count)
|
||||
default_llvm_block = target_block->llvm_end_block;
|
||||
}
|
||||
else {
|
||||
if (i == br_count)
|
||||
default_llvm_block = target_block->llvm_entry_block;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create switch IR */
|
||||
if (!(value_switch = LLVMBuildSwitch(comp_ctx->builder, value_cmp,
|
||||
default_llvm_block, br_count))) {
|
||||
aot_set_last_error("llvm build switch failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Add each case for switch IR */
|
||||
for (i = 0; i < br_count; i++) {
|
||||
value_case = I32_CONST(i);
|
||||
CHECK_LLVM_CONST(value_case);
|
||||
target_block = get_target_block(func_ctx, br_depths[i]);
|
||||
if (!target_block)
|
||||
return false;
|
||||
target_llvm_block = target_block->block_type != BLOCK_TYPE_LOOP
|
||||
? target_block->llvm_end_block
|
||||
: target_block->llvm_entry_block;
|
||||
LLVMAddCase(value_switch, value_case, target_llvm_block);
|
||||
}
|
||||
|
||||
return handle_next_reachable_block(comp_ctx, func_ctx, p_frame_ip);
|
||||
}
|
||||
else {
|
||||
/* Compare value is constant, create br IR */
|
||||
depth_idx = (uint32)LLVMConstIntGetZExtValue(value_cmp);
|
||||
br_depth = br_depths[br_count];
|
||||
if (depth_idx < br_count) {
|
||||
br_depth = br_depths[depth_idx];
|
||||
}
|
||||
return aot_compile_op_br(comp_ctx, func_ctx, br_depth, p_frame_ip);
|
||||
}
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_return(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint8 **p_frame_ip)
|
||||
{
|
||||
AOTBlock *block_func = func_ctx->block_stack.block_list_head;
|
||||
LLVMValueRef value;
|
||||
|
||||
bh_assert(block_func);
|
||||
if (block_func->return_type != VALUE_TYPE_VOID) {
|
||||
POP(value, block_func->return_type);
|
||||
LLVMBuildRet(comp_ctx->builder, value);
|
||||
}
|
||||
else
|
||||
LLVMBuildRetVoid(comp_ctx->builder);
|
||||
|
||||
return handle_next_reachable_block(comp_ctx, func_ctx, p_frame_ip);
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_unreachable(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint8 **p_frame_ip)
|
||||
{
|
||||
if (!aot_emit_exception(comp_ctx, func_ctx, EXCE_UNREACHABLE,
|
||||
false, NULL, NULL))
|
||||
return false;
|
||||
|
||||
return handle_next_reachable_block(comp_ctx, func_ctx, p_frame_ip);
|
||||
}
|
||||
|
||||
bool
|
||||
aot_handle_next_reachable_block(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint8 **p_frame_ip)
|
||||
{
|
||||
return handle_next_reachable_block(comp_ctx, func_ctx, p_frame_ip);
|
||||
}
|
||||
60
core/iwasm/compilation/aot_emit_control.h
Normal file
60
core/iwasm/compilation/aot_emit_control.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _AOT_EMIT_CONTROL_H_
|
||||
#define _AOT_EMIT_CONTROL_H_
|
||||
|
||||
#include "aot_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool
|
||||
aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint8 **p_frame_ip, uint8 *frame_ip_end,
|
||||
uint32 block_type, uint32 block_ret_type);
|
||||
|
||||
bool
|
||||
aot_compile_op_else(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint8 **p_frame_ip);
|
||||
|
||||
bool
|
||||
aot_compile_op_end(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint8 **p_frame_ip);
|
||||
|
||||
bool
|
||||
aot_compile_op_br(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 br_depth, uint8 **p_frame_ip);
|
||||
|
||||
bool
|
||||
aot_compile_op_br_if(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 br_depth, uint8 **p_frame_ip);
|
||||
|
||||
bool
|
||||
aot_compile_op_br_table(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 *br_depths, uint32 br_count,
|
||||
uint8 **p_frame_ip);
|
||||
|
||||
bool
|
||||
aot_compile_op_return(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint8 **p_frame_ip);
|
||||
|
||||
bool
|
||||
aot_compile_op_unreachable(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint8 **p_frame_ip);
|
||||
|
||||
bool
|
||||
aot_handle_next_reachable_block(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
uint8 **p_frame_ip);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _AOT_EMIT_CONTROL_H_ */
|
||||
|
||||
432
core/iwasm/compilation/aot_emit_conversion.c
Normal file
432
core/iwasm/compilation/aot_emit_conversion.c
Normal file
@ -0,0 +1,432 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "aot_emit_conversion.h"
|
||||
#include "aot_emit_exception.h"
|
||||
#include "aot_emit_numberic.h"
|
||||
#include "../aot/aot_runtime.h"
|
||||
|
||||
static bool
|
||||
trunc_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
LLVMValueRef operand, LLVMTypeRef dest_type,
|
||||
LLVMValueRef min_value, LLVMValueRef max_value,
|
||||
char *name, bool sign)
|
||||
{
|
||||
LLVMBasicBlockRef check_nan_succ, check_overflow_succ;
|
||||
LLVMValueRef is_less, is_greater, res;
|
||||
|
||||
if (!(res = LLVMBuildFCmp(comp_ctx->builder, LLVMRealUNO,
|
||||
operand, operand, "fcmp_is_nan"))) {
|
||||
aot_set_last_error("llvm build fcmp failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(check_nan_succ =
|
||||
LLVMAppendBasicBlockInContext(comp_ctx->context,
|
||||
func_ctx->func,
|
||||
"check_nan_succ"))) {
|
||||
aot_set_last_error("llvm add basic block failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
LLVMMoveBasicBlockAfter(check_nan_succ,
|
||||
LLVMGetInsertBlock(comp_ctx->builder));
|
||||
|
||||
if (!(aot_emit_exception(comp_ctx, func_ctx, EXCE_INVALID_CONVERSION_TO_INTEGER,
|
||||
true, res, check_nan_succ)))
|
||||
goto fail;
|
||||
|
||||
if (!(is_less = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOLE, operand,
|
||||
min_value, "fcmp_min_value"))) {
|
||||
aot_set_last_error("llvm build fcmp failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(is_greater = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOGE, operand,
|
||||
max_value, "fcmp_max_value"))) {
|
||||
aot_set_last_error("llvm build fcmp failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(res = LLVMBuildOr(comp_ctx->builder, is_less, is_greater, "is_overflow"))) {
|
||||
aot_set_last_error("llvm build logic and failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check if float value out of range */
|
||||
if (!(check_overflow_succ =
|
||||
LLVMAppendBasicBlockInContext(comp_ctx->context,
|
||||
func_ctx->func,
|
||||
"check_overflow_succ"))) {
|
||||
aot_set_last_error("llvm add basic block failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
LLVMMoveBasicBlockAfter(check_overflow_succ,
|
||||
LLVMGetInsertBlock(comp_ctx->builder));
|
||||
|
||||
if (!(aot_emit_exception(comp_ctx, func_ctx, EXCE_INTEGER_OVERFLOW,
|
||||
true, res, check_overflow_succ)))
|
||||
goto fail;
|
||||
|
||||
if (sign)
|
||||
res = LLVMBuildFPToSI(comp_ctx->builder, operand, dest_type, name);
|
||||
else
|
||||
res = LLVMBuildFPToUI(comp_ctx->builder, operand, dest_type, name);
|
||||
if (!res) {
|
||||
aot_set_last_error("llvm build conversion failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dest_type == I32_TYPE)
|
||||
PUSH_I32(res);
|
||||
else if (dest_type == I64_TYPE)
|
||||
PUSH_I64(res);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_wrap_i64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
{
|
||||
LLVMValueRef value, res;
|
||||
|
||||
POP_I64(value);
|
||||
|
||||
if (!(res = LLVMBuildTrunc(comp_ctx->builder, value, I32_TYPE, "i32_wrap_i64"))) {
|
||||
aot_set_last_error("llvm build conversion failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PUSH_I32(res);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign)
|
||||
{
|
||||
LLVMValueRef value;
|
||||
LLVMValueRef min_value, max_value;
|
||||
|
||||
POP_F32(value);
|
||||
|
||||
if (sign) {
|
||||
min_value = F32_CONST(-2147483904.0f);
|
||||
max_value = F32_CONST(2147483648.0f);
|
||||
}
|
||||
else {
|
||||
min_value = F32_CONST(-1.0f);
|
||||
max_value = F32_CONST(4294967296.0f);
|
||||
}
|
||||
|
||||
return trunc_float_to_int(comp_ctx, func_ctx, value,
|
||||
I32_TYPE, min_value, max_value,
|
||||
sign ? "i32_trunc_f32_s" : "i32_trunc_f32_u", sign);
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign)
|
||||
{
|
||||
LLVMValueRef value;
|
||||
LLVMValueRef min_value, max_value;
|
||||
|
||||
POP_F64(value);
|
||||
|
||||
if (sign) {
|
||||
min_value = F64_CONST(-2147483649.0);
|
||||
max_value = F64_CONST(2147483648.0);
|
||||
}
|
||||
else {
|
||||
min_value = F64_CONST(-1.0);
|
||||
max_value = F64_CONST(4294967296.0);
|
||||
}
|
||||
|
||||
return trunc_float_to_int(comp_ctx, func_ctx, value,
|
||||
I32_TYPE, min_value, max_value,
|
||||
sign ? "i32_trunc_f64_s" : "i32_trunc_f64_u", sign);
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_extend_i32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign)
|
||||
{
|
||||
LLVMValueRef value, res;
|
||||
|
||||
POP_I32(value);
|
||||
|
||||
if (sign)
|
||||
res = LLVMBuildSExt(comp_ctx->builder, value, I64_TYPE, "i64_extend_i32_s");
|
||||
else
|
||||
res = LLVMBuildZExt(comp_ctx->builder, value, I64_TYPE, "i64_extend_i32_u");
|
||||
if (!res) {
|
||||
aot_set_last_error("llvm build conversion failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PUSH_I64(res);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign)
|
||||
{
|
||||
LLVMValueRef value;
|
||||
LLVMValueRef min_value, max_value;
|
||||
|
||||
POP_F32(value);
|
||||
|
||||
if (sign) {
|
||||
min_value = F32_CONST(-9223373136366403584.0f);
|
||||
max_value = F32_CONST(9223372036854775808.0f);
|
||||
}
|
||||
else {
|
||||
min_value = F32_CONST(-1.0f);
|
||||
max_value = F32_CONST(18446744073709551616.0f);
|
||||
}
|
||||
|
||||
return trunc_float_to_int(comp_ctx, func_ctx, value,
|
||||
I64_TYPE, min_value, max_value,
|
||||
sign ? "i64_trunc_f32_s" : "i64_trunc_f32_u", sign);
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign)
|
||||
{
|
||||
LLVMValueRef value;
|
||||
LLVMValueRef min_value, max_value;
|
||||
|
||||
POP_F64(value);
|
||||
|
||||
if (sign) {
|
||||
min_value = F64_CONST(-9223372036854777856.0);
|
||||
max_value = F64_CONST(9223372036854775808.0);
|
||||
}
|
||||
else {
|
||||
min_value = F64_CONST(-1.0);
|
||||
max_value = F64_CONST(18446744073709551616.0);
|
||||
}
|
||||
|
||||
return trunc_float_to_int(comp_ctx, func_ctx, value,
|
||||
I64_TYPE, min_value, max_value,
|
||||
sign ? "i64_trunc_f64_s" : "i64_trunc_f64_u", sign);
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_f32_convert_i32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign)
|
||||
{
|
||||
LLVMValueRef value, res;
|
||||
|
||||
POP_I32(value);
|
||||
|
||||
if (sign)
|
||||
res = LLVMBuildSIToFP(comp_ctx->builder, value, F32_TYPE, "f32_convert_i32_s");
|
||||
else
|
||||
res = LLVMBuildUIToFP(comp_ctx->builder, value, F32_TYPE, "f32_convert_i32_u");
|
||||
if (!res) {
|
||||
aot_set_last_error("llvm build conversion failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PUSH_F32(res);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_f32_convert_i64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign)
|
||||
{
|
||||
LLVMValueRef value, res;
|
||||
|
||||
POP_I64(value);
|
||||
|
||||
if (sign)
|
||||
res = LLVMBuildSIToFP(comp_ctx->builder, value, F32_TYPE, "f32_convert_i64_s");
|
||||
else
|
||||
res = LLVMBuildUIToFP(comp_ctx->builder, value, F32_TYPE, "f32_convert_i64_u");
|
||||
if (!res) {
|
||||
aot_set_last_error("llvm build conversion failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PUSH_F32(res);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_f32_demote_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
{
|
||||
LLVMValueRef value, res;
|
||||
|
||||
POP_F64(value);
|
||||
|
||||
if (!(res = LLVMBuildFPTrunc(comp_ctx->builder, value, F32_TYPE, "f32_demote_f64"))) {
|
||||
aot_set_last_error("llvm build conversion failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PUSH_F32(res);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_f64_convert_i32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign)
|
||||
{
|
||||
LLVMValueRef value, res;
|
||||
|
||||
POP_I32(value);
|
||||
|
||||
if (sign)
|
||||
res = LLVMBuildSIToFP(comp_ctx->builder, value, F64_TYPE, "f64_convert_i32_s");
|
||||
else
|
||||
res = LLVMBuildUIToFP(comp_ctx->builder, value, F64_TYPE, "f64_convert_i32_u");
|
||||
if (!res) {
|
||||
aot_set_last_error("llvm build conversion failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PUSH_F64(res);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_f64_convert_i64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign)
|
||||
{
|
||||
LLVMValueRef value, res;
|
||||
|
||||
POP_I64(value);
|
||||
|
||||
if (sign)
|
||||
res = LLVMBuildSIToFP(comp_ctx->builder, value, F64_TYPE, "f64_convert_i64_s");
|
||||
else
|
||||
res = LLVMBuildUIToFP(comp_ctx->builder, value, F64_TYPE, "f64_convert_i64_u");
|
||||
if (!res) {
|
||||
aot_set_last_error("llvm build conversion failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PUSH_F64(res);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_f64_promote_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
{
|
||||
LLVMValueRef value, res;
|
||||
|
||||
POP_F32(value);
|
||||
|
||||
if (!(res = LLVMBuildFPExt(comp_ctx->builder, value, F64_TYPE, "f64_promote_f32"))) {
|
||||
aot_set_last_error("llvm build conversion failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PUSH_F64(res);
|
||||
|
||||
/* Avoid the promote being optimized away */
|
||||
PUSH_F64(F64_CONST(1.0));
|
||||
return aot_compile_op_f64_arithmetic(comp_ctx, func_ctx, FLOAT_MUL);
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_reinterpret_f64(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx)
|
||||
{
|
||||
LLVMValueRef value;
|
||||
POP_F64(value);
|
||||
if (!(value = LLVMBuildBitCast(comp_ctx->builder, value,
|
||||
I64_TYPE, "i64"))) {
|
||||
aot_set_last_error("llvm build fp to si failed.");
|
||||
return false;
|
||||
}
|
||||
PUSH_I64(value);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_reinterpret_f32(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx)
|
||||
{
|
||||
LLVMValueRef value;
|
||||
POP_F32(value);
|
||||
if (!(value = LLVMBuildBitCast(comp_ctx->builder, value,
|
||||
I32_TYPE, "i32"))) {
|
||||
aot_set_last_error("llvm build fp to si failed.");
|
||||
return false;
|
||||
}
|
||||
PUSH_I32(value);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_f64_reinterpret_i64(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx)
|
||||
{
|
||||
LLVMValueRef value;
|
||||
POP_I64(value);
|
||||
if (!(value = LLVMBuildBitCast(comp_ctx->builder, value,
|
||||
F64_TYPE, "f64"))) {
|
||||
aot_set_last_error("llvm build si to fp failed.");
|
||||
return false;
|
||||
}
|
||||
PUSH_F64(value);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_f32_reinterpret_i32(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx)
|
||||
{
|
||||
LLVMValueRef value;
|
||||
POP_I32(value);
|
||||
if (!(value = LLVMBuildBitCast(comp_ctx->builder, value,
|
||||
F32_TYPE, "f32"))) {
|
||||
aot_set_last_error("llvm build si to fp failed.");
|
||||
return false;
|
||||
}
|
||||
PUSH_F32(value);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
81
core/iwasm/compilation/aot_emit_conversion.h
Normal file
81
core/iwasm/compilation/aot_emit_conversion.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _AOT_EMIT_CONVERSION_H_
|
||||
#define _AOT_EMIT_CONVERSION_H_
|
||||
|
||||
#include "aot_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_wrap_i64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign);
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign);
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_extend_i32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign);
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign);
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign);
|
||||
|
||||
bool
|
||||
aot_compile_op_f32_convert_i32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign);
|
||||
|
||||
bool
|
||||
aot_compile_op_f32_convert_i64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign);
|
||||
|
||||
bool
|
||||
aot_compile_op_f32_demote_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
|
||||
bool
|
||||
aot_compile_op_f64_convert_i32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign);
|
||||
|
||||
bool
|
||||
aot_compile_op_f64_convert_i64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign);
|
||||
|
||||
bool
|
||||
aot_compile_op_f64_promote_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_reinterpret_f64(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx);
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_reinterpret_f32(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx);
|
||||
|
||||
bool
|
||||
aot_compile_op_f64_reinterpret_i64(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx);
|
||||
|
||||
bool
|
||||
aot_compile_op_f32_reinterpret_i32(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _AOT_EMIT_CONVERSION_H_ */
|
||||
|
||||
184
core/iwasm/compilation/aot_emit_exception.c
Normal file
184
core/iwasm/compilation/aot_emit_exception.c
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "aot_emit_exception.h"
|
||||
#include "../aot/aot_runtime.h"
|
||||
|
||||
static char *exce_block_names[] = {
|
||||
"exce_unreachable", /* EXCE_UNREACHABLE */
|
||||
"exce_out_of_memory", /* EXCE_OUT_OF_MEMORY */
|
||||
"exce_out_of_bounds_mem_access",/* EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS */
|
||||
"exce_integer_overflow", /* EXCE_INTEGER_OVERFLOW */
|
||||
"exce_divide_by_zero", /* EXCE_INTEGER_DIVIDE_BY_ZERO */
|
||||
"exce_invalid_convert_to_int", /* EXCE_INVALID_CONVERSION_TO_INTEGER */
|
||||
"exce_invalid_func_type_idx", /* EXCE_INVALID_FUNCTION_TYPE_INDEX */
|
||||
"exce_invalid_func_idx", /* EXCE_INVALID_FUNCTION_INDEX */
|
||||
"exce_undefined_element", /* EXCE_UNDEFINED_ELEMENT */
|
||||
"exce_uninit_element", /* EXCE_UNINITIALIZED_ELEMENT */
|
||||
"exce_call_unlinked" /* EXCE_CALL_UNLINKED_IMPORT_FUNC */
|
||||
};
|
||||
|
||||
bool
|
||||
aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
int32 exception_id,
|
||||
bool is_cond_br,
|
||||
LLVMValueRef cond_br_if,
|
||||
LLVMBasicBlockRef cond_br_else_block)
|
||||
{
|
||||
LLVMBasicBlockRef exce_block;
|
||||
LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
|
||||
LLVMValueRef exce_id = I32_CONST((uint32)exception_id), func_const, func;
|
||||
LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type;
|
||||
LLVMValueRef param_values[2];
|
||||
|
||||
bh_assert(exception_id >= 0 && exception_id < EXCE_NUM);
|
||||
|
||||
CHECK_LLVM_CONST(exce_id);
|
||||
|
||||
/* Create got_exception block if needed */
|
||||
if (!func_ctx->got_exception_block) {
|
||||
if (!(func_ctx->got_exception_block =
|
||||
LLVMAppendBasicBlockInContext(comp_ctx->context,
|
||||
func_ctx->func,
|
||||
"got_exception"))) {
|
||||
aot_set_last_error("add LLVM basic block failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder,
|
||||
func_ctx->got_exception_block);
|
||||
|
||||
/* Create exection id phi */
|
||||
if (!(func_ctx->exception_id_phi =
|
||||
LLVMBuildPhi(comp_ctx->builder,
|
||||
comp_ctx->basic_types.int32_type,
|
||||
"exception_id_phi"))) {
|
||||
aot_set_last_error("llvm build phi failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Call aot_set_exception_with_id() to throw exception */
|
||||
param_types[0] = INT8_PTR_TYPE;
|
||||
param_types[1] = I32_TYPE;
|
||||
ret_type = VOID_TYPE;
|
||||
|
||||
/* Create function type */
|
||||
if (!(func_type = LLVMFunctionType(ret_type, param_types,
|
||||
2, false))) {
|
||||
aot_set_last_error("create LLVM function type failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (comp_ctx->is_jit_mode) {
|
||||
/* Create function type */
|
||||
if (!(func_ptr_type = LLVMPointerType(func_type, 0))) {
|
||||
aot_set_last_error("create LLVM function type failed.");
|
||||
return false;
|
||||
}
|
||||
/* Create LLVM function with const function pointer */
|
||||
if (!(func_const =
|
||||
I64_CONST((uint64)(uintptr_t)aot_set_exception_with_id))
|
||||
|| !(func = LLVMConstIntToPtr(func_const, func_ptr_type))) {
|
||||
aot_set_last_error("create LLVM value failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Create LLVM function with external function pointer */
|
||||
if (!(func = LLVMGetNamedFunction(comp_ctx->module,
|
||||
"aot_set_exception_with_id"))
|
||||
&& !(func = LLVMAddFunction(comp_ctx->module,
|
||||
"aot_set_exception_with_id",
|
||||
func_type))) {
|
||||
aot_set_last_error("add LLVM function failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call the aot_set_exception_with_id() function */
|
||||
param_values[0] = func_ctx->aot_inst;
|
||||
param_values[1] = func_ctx->exception_id_phi;
|
||||
if (!LLVMBuildCall(comp_ctx->builder, func, param_values,
|
||||
2, "")) {
|
||||
aot_set_last_error("llvm build call failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Create return IR */
|
||||
AOTFuncType *aot_func_type = func_ctx->aot_func->func_type;
|
||||
if (aot_func_type->result_count) {
|
||||
switch (aot_func_type->types[aot_func_type->param_count]) {
|
||||
case VALUE_TYPE_I32:
|
||||
LLVMBuildRet(comp_ctx->builder, I32_ZERO);
|
||||
break;
|
||||
case VALUE_TYPE_I64:
|
||||
LLVMBuildRet(comp_ctx->builder, I64_ZERO);
|
||||
break;
|
||||
case VALUE_TYPE_F32:
|
||||
LLVMBuildRet(comp_ctx->builder, F32_ZERO);
|
||||
break;
|
||||
case VALUE_TYPE_F64:
|
||||
LLVMBuildRet(comp_ctx->builder, F64_ZERO);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
LLVMBuildRetVoid(comp_ctx->builder);
|
||||
}
|
||||
|
||||
/* Resume the builder position */
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr);
|
||||
}
|
||||
|
||||
/* Create exception block if needed */
|
||||
if (!(exce_block = func_ctx->exception_blocks[exception_id])) {
|
||||
if (!(func_ctx->exception_blocks[exception_id] = exce_block =
|
||||
LLVMAppendBasicBlockInContext(comp_ctx->context,
|
||||
func_ctx->func,
|
||||
exce_block_names[exception_id]))) {
|
||||
aot_set_last_error("add LLVM basic block failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Move before got_exception block */
|
||||
LLVMMoveBasicBlockBefore(exce_block, func_ctx->got_exception_block);
|
||||
|
||||
/* Add phi incoming value to got_exception block */
|
||||
LLVMAddIncoming(func_ctx->exception_id_phi, &exce_id, &exce_block, 1);
|
||||
|
||||
/* Jump to got exception block */
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, exce_block);
|
||||
if (!LLVMBuildBr(comp_ctx->builder, func_ctx->got_exception_block)) {
|
||||
aot_set_last_error("llvm build br failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Resume builder position */
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr);
|
||||
|
||||
if (!is_cond_br) {
|
||||
/* not condition br, create br IR */
|
||||
if (!LLVMBuildBr(comp_ctx->builder, exce_block)) {
|
||||
aot_set_last_error("llvm build br failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Create condition br */
|
||||
if (!LLVMBuildCondBr(comp_ctx->builder, cond_br_if,
|
||||
exce_block, cond_br_else_block)) {
|
||||
aot_set_last_error("llvm build cond br failed.");
|
||||
return false;
|
||||
}
|
||||
/* Start to translate the else block */
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, cond_br_else_block);
|
||||
}
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
27
core/iwasm/compilation/aot_emit_exception.h
Normal file
27
core/iwasm/compilation/aot_emit_exception.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _AOT_EMIT_EXCEPTION_H_
|
||||
#define _AOT_EMIT_EXCEPTION_H_
|
||||
|
||||
#include "aot_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool
|
||||
aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
int32 exception_id,
|
||||
bool is_cond_br,
|
||||
LLVMValueRef cond_br_if,
|
||||
LLVMBasicBlockRef cond_br_else_block);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _AOT_EMIT_EXCEPTION_H_ */
|
||||
|
||||
548
core/iwasm/compilation/aot_emit_function.c
Normal file
548
core/iwasm/compilation/aot_emit_function.c
Normal file
@ -0,0 +1,548 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "aot_emit_function.h"
|
||||
#include "aot_emit_exception.h"
|
||||
#include "aot_emit_control.h"
|
||||
#include "../aot/aot_runtime.h"
|
||||
|
||||
/* Check whether there was exception thrown, if yes, return directly */
|
||||
static bool
|
||||
check_exception_thrown(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
{
|
||||
AOTFuncType *aot_func_type = func_ctx->aot_func->func_type;
|
||||
LLVMBasicBlockRef block_curr, check_exce_succ;
|
||||
LLVMValueRef value, cmp;
|
||||
|
||||
/* Load the first byte of aot_module_inst->cur_exception, and check
|
||||
whether it is '\0'. If yes, no exception was thrown. */
|
||||
if (!(value = LLVMBuildLoad(comp_ctx->builder, func_ctx->cur_exception,
|
||||
"exce_value"))
|
||||
|| !(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ,
|
||||
value, I8_ZERO, "cmp"))) {
|
||||
aot_set_last_error("llvm build icmp failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Add check exection success block */
|
||||
if (!(check_exce_succ = LLVMAppendBasicBlockInContext(comp_ctx->context,
|
||||
func_ctx->func,
|
||||
"check_exce_succ"))) {
|
||||
aot_set_last_error("llvm add basic block failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
block_curr = LLVMGetInsertBlock(comp_ctx->builder);
|
||||
LLVMMoveBasicBlockAfter(check_exce_succ, block_curr);
|
||||
|
||||
/* Create function return block if it isn't created */
|
||||
if (!func_ctx->func_return_block) {
|
||||
if (!(func_ctx->func_return_block =
|
||||
LLVMAppendBasicBlockInContext(comp_ctx->context,
|
||||
func_ctx->func,
|
||||
"func_ret"))) {
|
||||
aot_set_last_error("llvm add basic block failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Create return IR */
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, func_ctx->func_return_block);
|
||||
if (aot_func_type->result_count) {
|
||||
switch (aot_func_type->types[aot_func_type->param_count]) {
|
||||
case VALUE_TYPE_I32:
|
||||
LLVMBuildRet(comp_ctx->builder, I32_ZERO);
|
||||
break;
|
||||
case VALUE_TYPE_I64:
|
||||
LLVMBuildRet(comp_ctx->builder, I64_ZERO);
|
||||
break;
|
||||
case VALUE_TYPE_F32:
|
||||
LLVMBuildRet(comp_ctx->builder, F32_ZERO);
|
||||
break;
|
||||
case VALUE_TYPE_F64:
|
||||
LLVMBuildRet(comp_ctx->builder, F64_ZERO);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
LLVMBuildRetVoid(comp_ctx->builder);
|
||||
}
|
||||
}
|
||||
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr);
|
||||
/* Create condition br */
|
||||
if (!LLVMBuildCondBr(comp_ctx->builder, cmp,
|
||||
check_exce_succ, func_ctx->func_return_block)) {
|
||||
aot_set_last_error("llvm build cond br failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, check_exce_succ);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 func_idx, uint8 **p_frame_ip)
|
||||
{
|
||||
uint32 import_func_count = comp_ctx->comp_data->import_func_count;
|
||||
AOTImportFunc *import_funcs = comp_ctx->comp_data->import_funcs;
|
||||
uint32 func_count = comp_ctx->func_ctx_count;
|
||||
AOTFuncContext **func_ctxes = comp_ctx->func_ctxes;
|
||||
AOTFuncType *func_type;
|
||||
LLVMTypeRef *param_types = NULL, ret_type, f_type, f_ptr_type;
|
||||
LLVMValueRef *param_values = NULL, value_ret, func, value, cmp;
|
||||
LLVMBasicBlockRef check_func_ptr_succ;
|
||||
int32 i, j = 0, param_count;
|
||||
void *func_ptr;
|
||||
uint64 total_size;
|
||||
bool ret = false;
|
||||
|
||||
/* Check function index */
|
||||
if (func_idx >= import_func_count + func_count) {
|
||||
aot_set_last_error("Function index out of range.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get function type */
|
||||
if (func_idx < import_func_count)
|
||||
func_type = import_funcs[func_idx].func_type;
|
||||
else
|
||||
func_type = func_ctxes[func_idx - import_func_count]->
|
||||
aot_func->func_type;
|
||||
|
||||
/* Allocate memory for parameters */
|
||||
param_count = (int32)func_type->param_count;
|
||||
total_size = sizeof(LLVMValueRef) * (uint64)(param_count + 1);
|
||||
if (total_size >= UINT32_MAX
|
||||
|| !(param_values = wasm_malloc((uint32)total_size))) {
|
||||
aot_set_last_error("Allocate memory failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* First parameter is exec env */
|
||||
param_values[j++] = func_ctx->exec_env;
|
||||
|
||||
/* Pop parameters from stack */
|
||||
for (i = param_count - 1; i >= 0; i--)
|
||||
POP(param_values[i + j], func_type->types[i]);
|
||||
|
||||
if (func_idx < import_func_count) {
|
||||
/* Get function pointer linked */
|
||||
func_ptr = import_funcs[func_idx].func_ptr_linked;
|
||||
|
||||
/* Initialize parameter types of the LLVM function */
|
||||
total_size = sizeof(LLVMTypeRef) * (uint64)(param_count + 1);
|
||||
if (total_size >= UINT32_MAX
|
||||
|| !(param_types = wasm_malloc((uint32)total_size))) {
|
||||
aot_set_last_error("Allocate memory failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
j = 0;
|
||||
param_types[j++] = comp_ctx->exec_env_type;
|
||||
|
||||
for (i = 0; i < param_count; i++)
|
||||
param_types[j++] = TO_LLVM_TYPE(func_type->types[i]);
|
||||
|
||||
/* Resolve return type of the LLVM function */
|
||||
if (func_type->result_count)
|
||||
ret_type = TO_LLVM_TYPE(func_type->types[func_type->param_count]);
|
||||
else
|
||||
ret_type = VOID_TYPE;
|
||||
|
||||
/* Resolve function prototype */
|
||||
if (!(f_type = LLVMFunctionType(ret_type, param_types,
|
||||
(uint32)param_count + 1, false))
|
||||
|| !(f_ptr_type = LLVMPointerType(f_type, 0))) {
|
||||
aot_set_last_error("create LLVM function type failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (comp_ctx->is_jit_mode) {
|
||||
if (!func_ptr) {
|
||||
/* The import function isn't linked, throw exception
|
||||
when calling it. */
|
||||
if (!aot_emit_exception(comp_ctx, func_ctx,
|
||||
EXCE_CALL_UNLINKED_IMPORT_FUNC,
|
||||
false, NULL, NULL))
|
||||
goto fail;
|
||||
ret = aot_handle_next_reachable_block(comp_ctx, func_ctx, p_frame_ip);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* JIT mode, call the linked function directly */
|
||||
if (!(value = I64_CONST((uint64)(uintptr_t)func_ptr))
|
||||
|| !(func = LLVMConstIntToPtr(value, f_ptr_type))) {
|
||||
aot_set_last_error("create LLVM value failed.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Load function pointer */
|
||||
if (!(value = I32_CONST(func_idx))
|
||||
|| !(func_ptr = LLVMBuildInBoundsGEP(comp_ctx->builder,
|
||||
func_ctx->func_ptrs,
|
||||
&value, 1, "func_ptr"))) {
|
||||
aot_set_last_error("llvm build inbounds gep failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(func = LLVMBuildLoad(comp_ctx->builder, func_ptr, "func_tmp"))) {
|
||||
aot_set_last_error("llvm build load failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check whether import function is NULL */
|
||||
if (!(cmp = LLVMBuildIsNull(comp_ctx->builder, func, "is_func_null"))) {
|
||||
aot_set_last_error("llvm build icmp failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Throw exception if import function is NULL */
|
||||
if (!(check_func_ptr_succ =
|
||||
LLVMAppendBasicBlockInContext(comp_ctx->context,
|
||||
func_ctx->func,
|
||||
"check_func_ptr_succ"))) {
|
||||
aot_set_last_error("llvm add basic block failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
LLVMMoveBasicBlockAfter(check_func_ptr_succ,
|
||||
LLVMGetInsertBlock(comp_ctx->builder));
|
||||
|
||||
if (!(aot_emit_exception(comp_ctx, func_ctx,
|
||||
EXCE_CALL_UNLINKED_IMPORT_FUNC,
|
||||
true, cmp, check_func_ptr_succ)))
|
||||
goto fail;
|
||||
|
||||
if (!(func = LLVMBuildBitCast(comp_ctx->builder, func,
|
||||
f_ptr_type, "func"))) {
|
||||
aot_set_last_error("create LLVM value failed.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
func = func_ctxes[func_idx - import_func_count]->func;
|
||||
}
|
||||
|
||||
/* Call the function */
|
||||
if (!(value_ret = LLVMBuildCall(comp_ctx->builder, func,
|
||||
param_values, (uint32)param_count + 1,
|
||||
(func_type->result_count > 0
|
||||
? "call" : "")))) {
|
||||
aot_set_last_error("LLVM build call failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Set calling convention for the call with the func's calling convention */
|
||||
LLVMSetInstructionCallConv(value_ret, LLVMGetFunctionCallConv(func));
|
||||
|
||||
if (func_type->result_count > 0)
|
||||
PUSH(value_ret, func_type->types[func_type->param_count]);
|
||||
|
||||
/* Check whether there was exception thrown when executing the function */
|
||||
if (!check_exception_thrown(comp_ctx, func_ctx))
|
||||
goto fail;
|
||||
|
||||
ret = true;
|
||||
fail:
|
||||
if (param_types)
|
||||
wasm_free(param_types);
|
||||
if (param_values)
|
||||
wasm_free(param_values);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 type_idx)
|
||||
{
|
||||
AOTFuncType *func_type;
|
||||
LLVMValueRef elem_idx, table_elem, func_idx, ftype_idx_ptr, ftype_idx;
|
||||
LLVMValueRef cmp_elem_idx, cmp_func_idx, is_ftype_match, is_ftype_mismatch;
|
||||
LLVMValueRef func, func_ptr, func_const, table_size_const, cmp_func_ptr;
|
||||
LLVMValueRef *param_values = NULL, param_values_tmp[3], value_ret;
|
||||
LLVMTypeRef *param_types = NULL, param_types_tmp[3], ret_type,
|
||||
f_type, f_ptr_type;
|
||||
LLVMBasicBlockRef check_elem_idx_succ, check_ftype_idx_succ;
|
||||
LLVMBasicBlockRef check_func_idx_succ, check_func_ptr_succ;
|
||||
int32 i, j = 0, param_count;
|
||||
uint64 total_size;
|
||||
bool ret;
|
||||
char *func_name = "aot_is_wasm_type_equal";
|
||||
|
||||
/* Check function type index */
|
||||
if (type_idx >= comp_ctx->comp_data->func_type_count) {
|
||||
aot_set_last_error("type index is overflow");
|
||||
return false;
|
||||
}
|
||||
|
||||
func_type = comp_ctx->comp_data->func_types[type_idx];
|
||||
|
||||
POP_I32(elem_idx);
|
||||
|
||||
table_size_const = I32_CONST(comp_ctx->comp_data->table_size);
|
||||
CHECK_LLVM_CONST(table_size_const);
|
||||
|
||||
/* Check if (uint32)elem index >= table size */
|
||||
if (!(cmp_elem_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE,
|
||||
elem_idx, table_size_const,
|
||||
"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_UNDEFINED_ELEMENT,
|
||||
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"))) {
|
||||
aot_set_last_error("llvm build add failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(func_idx = LLVMBuildLoad(comp_ctx->builder, table_elem, "func_idx"))) {
|
||||
aot_set_last_error("llvm build load failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check if func_idx == -1 */
|
||||
if (!(cmp_func_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ,
|
||||
func_idx, I32_NEG_ONE,
|
||||
"cmp_func_idx"))) {
|
||||
aot_set_last_error("llvm build icmp failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Throw exception if func_idx == -1 */
|
||||
if (!(check_func_idx_succ =
|
||||
LLVMAppendBasicBlockInContext(comp_ctx->context,
|
||||
func_ctx->func,
|
||||
"check_func_idx_succ"))) {
|
||||
aot_set_last_error("llvm add basic block failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
LLVMMoveBasicBlockAfter(check_func_idx_succ,
|
||||
LLVMGetInsertBlock(comp_ctx->builder));
|
||||
|
||||
if (!(aot_emit_exception(comp_ctx, func_ctx, EXCE_UNINITIALIZED_ELEMENT,
|
||||
true, cmp_func_idx, check_func_idx_succ)))
|
||||
goto fail;
|
||||
|
||||
/* Load function type index */
|
||||
if (!(ftype_idx_ptr = LLVMBuildInBoundsGEP(comp_ctx->builder,
|
||||
func_ctx->func_type_indexes,
|
||||
&func_idx, 1,
|
||||
"ftype_idx_ptr"))) {
|
||||
aot_set_last_error("llvm build inbounds gep failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(ftype_idx = LLVMBuildLoad(comp_ctx->builder, ftype_idx_ptr,
|
||||
"ftype_idx"))) {
|
||||
aot_set_last_error("llvm build load failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Call aot_is_type_equal() to check whether function type match */
|
||||
param_types_tmp[0] = INT8_PTR_TYPE;
|
||||
param_types_tmp[1] = I32_TYPE;
|
||||
param_types_tmp[2] = I32_TYPE;
|
||||
ret_type = INT8_TYPE;
|
||||
|
||||
/* Create function type */
|
||||
if (!(f_type = LLVMFunctionType(ret_type, param_types_tmp,
|
||||
3, false))) {
|
||||
aot_set_last_error("create LLVM function type failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (comp_ctx->is_jit_mode) {
|
||||
/* Create function type */
|
||||
if (!(f_ptr_type = LLVMPointerType(f_type, 0))) {
|
||||
aot_set_last_error("create LLVM function type failed.");
|
||||
goto fail;
|
||||
}
|
||||
/* Create LLVM function with const function pointer */
|
||||
if (!(func_const =
|
||||
I64_CONST((uint64)(uintptr_t)aot_is_wasm_type_equal))
|
||||
|| !(func = LLVMConstIntToPtr(func_const, f_ptr_type))) {
|
||||
aot_set_last_error("create LLVM value failed.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Create LLVM function with external function pointer */
|
||||
if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name))
|
||||
&& !(func = LLVMAddFunction(comp_ctx->module, func_name, f_type))) {
|
||||
aot_set_last_error("add LLVM function failed.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call the aot_is_type_equal() function */
|
||||
param_values_tmp[0] = func_ctx->aot_inst;
|
||||
param_values_tmp[1] = I32_CONST(type_idx);
|
||||
param_values_tmp[2] = ftype_idx;
|
||||
|
||||
CHECK_LLVM_CONST(param_values_tmp[1]);
|
||||
|
||||
if (!(is_ftype_match = LLVMBuildCall(comp_ctx->builder, func,
|
||||
param_values_tmp, 3,
|
||||
"is_ftype_match"))) {
|
||||
aot_set_last_error("llvm build icmp failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(is_ftype_mismatch = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ,
|
||||
is_ftype_match, I8_ZERO,
|
||||
"is_ftype_mismatch"))) {
|
||||
aot_set_last_error("llvm build icmp failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(check_ftype_idx_succ =
|
||||
LLVMAppendBasicBlockInContext(comp_ctx->context,
|
||||
func_ctx->func,
|
||||
"check_ftype_idx_success"))) {
|
||||
aot_set_last_error("llvm add basic block failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
LLVMMoveBasicBlockAfter(check_ftype_idx_succ,
|
||||
LLVMGetInsertBlock(comp_ctx->builder));
|
||||
|
||||
if (!(aot_emit_exception(comp_ctx, func_ctx, EXCE_INVALID_FUNCTION_TYPE_INDEX,
|
||||
true, is_ftype_mismatch, check_ftype_idx_succ)))
|
||||
goto fail;
|
||||
|
||||
/* Load function pointer */
|
||||
if (!(func_ptr = LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->func_ptrs,
|
||||
&func_idx, 1, "func_ptr"))) {
|
||||
aot_set_last_error("llvm build inbounds gep failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(func = LLVMBuildLoad(comp_ctx->builder, func_ptr, "func_tmp"))) {
|
||||
aot_set_last_error("llvm build load failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check whether import function is NULL */
|
||||
if (!(cmp_func_ptr = LLVMBuildIsNull(comp_ctx->builder, func, "is_func_null"))) {
|
||||
aot_set_last_error("llvm build is null failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Throw exception if import function is NULL */
|
||||
if (!(check_func_ptr_succ =
|
||||
LLVMAppendBasicBlockInContext(comp_ctx->context,
|
||||
func_ctx->func,
|
||||
"check_func_ptr_succ"))) {
|
||||
aot_set_last_error("llvm add basic block failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
LLVMMoveBasicBlockAfter(check_func_ptr_succ,
|
||||
LLVMGetInsertBlock(comp_ctx->builder));
|
||||
|
||||
if (!(aot_emit_exception(comp_ctx, func_ctx,
|
||||
EXCE_CALL_UNLINKED_IMPORT_FUNC,
|
||||
true, cmp_func_ptr, check_func_ptr_succ)))
|
||||
goto fail;
|
||||
|
||||
/* Initialize parameter types of the LLVM function */
|
||||
param_count = (int32)func_type->param_count;
|
||||
total_size = sizeof(LLVMTypeRef) * (uint64)(param_count + 1);
|
||||
if (total_size >= UINT32_MAX
|
||||
|| !(param_types = wasm_malloc((uint32)total_size))) {
|
||||
aot_set_last_error("Allocate memory failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
j = 0;
|
||||
param_types[j++] = comp_ctx->exec_env_type;
|
||||
for (i = 0; i < param_count; i++)
|
||||
param_types[j++] = TO_LLVM_TYPE(func_type->types[i]);
|
||||
|
||||
/* Resolve return type of the LLVM function */
|
||||
if (func_type->result_count)
|
||||
ret_type = TO_LLVM_TYPE(func_type->types[func_type->param_count]);
|
||||
else
|
||||
ret_type = VOID_TYPE;
|
||||
|
||||
/* Resolve function prototype */
|
||||
if (!(f_type = LLVMFunctionType(ret_type, param_types,
|
||||
(uint32)param_count + 1, false))
|
||||
|| !(f_ptr_type = LLVMPointerType(f_type, 0))) {
|
||||
aot_set_last_error("create LLVM function type failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(func = LLVMBuildBitCast(comp_ctx->builder, func,
|
||||
f_ptr_type, "func"))) {
|
||||
aot_set_last_error("create LLVM value failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Allocate memory for parameters */
|
||||
total_size = sizeof(LLVMValueRef) * (uint64)(param_count + 1);
|
||||
if (total_size >= UINT32_MAX
|
||||
|| !(param_values = wasm_malloc((uint32)total_size))) {
|
||||
aot_set_last_error("Allocate memory failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* First parameter is exec env */
|
||||
j = 0;
|
||||
param_values[j++] = func_ctx->exec_env;
|
||||
|
||||
/* Pop parameters from stack */
|
||||
for (i = param_count - 1; i >= 0; i--)
|
||||
POP(param_values[i + j], func_type->types[i]);
|
||||
|
||||
/* Call the function */
|
||||
if (!(value_ret = LLVMBuildCall(comp_ctx->builder, func,
|
||||
param_values, (uint32)param_count + 1,
|
||||
(func_type->result_count > 0
|
||||
? "call_indirect" : "")))) {
|
||||
aot_set_last_error("LLVM build call failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (func_type->result_count > 0)
|
||||
PUSH(value_ret, func_type->types[func_type->param_count]);
|
||||
|
||||
/* Check whether there was exception thrown when executing the function */
|
||||
if (!check_exception_thrown(comp_ctx, func_ctx))
|
||||
goto fail;
|
||||
|
||||
ret = true;
|
||||
|
||||
fail:
|
||||
if (param_values)
|
||||
wasm_free(param_values);
|
||||
if (param_types)
|
||||
wasm_free(param_types);
|
||||
return ret;
|
||||
}
|
||||
|
||||
28
core/iwasm/compilation/aot_emit_function.h
Normal file
28
core/iwasm/compilation/aot_emit_function.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _AOT_EMIT_FUNCTION_H_
|
||||
#define _AOT_EMIT_FUNCTION_H_
|
||||
|
||||
#include "aot_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool
|
||||
aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 func_idx, uint8 **p_frame_ip);
|
||||
|
||||
bool
|
||||
aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 type_idx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _AOT_EMIT_FUNCTION_H_ */
|
||||
|
||||
662
core/iwasm/compilation/aot_emit_memory.c
Normal file
662
core/iwasm/compilation/aot_emit_memory.c
Normal file
@ -0,0 +1,662 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "aot_emit_memory.h"
|
||||
#include "aot_emit_exception.h"
|
||||
#include "../aot/aot_runtime.h"
|
||||
|
||||
#define BUILD_ICMP(op, left, right, res, name) do { \
|
||||
if (!(res = LLVMBuildICmp(comp_ctx->builder, op, \
|
||||
left, right, name))) { \
|
||||
aot_set_last_error("llvm build icmp failed."); \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BUILD_OP(Op, left, right, res, name) do { \
|
||||
if (!(res = LLVMBuild##Op(comp_ctx->builder, \
|
||||
left, right, name))) { \
|
||||
aot_set_last_error("llvm build " #Op " fail."); \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BUILD_COND_BR(cmp_val, then_block, else_block) do { \
|
||||
if (!LLVMBuildCondBr(comp_ctx->builder, cmp_val, \
|
||||
then_block, else_block)) { \
|
||||
aot_set_last_error("llvm build cond br failed."); \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ADD_BASIC_BLOCK(block, name) do { \
|
||||
if (!(block = LLVMAppendBasicBlockInContext(comp_ctx->context, \
|
||||
func_ctx->func, \
|
||||
name))) { \
|
||||
aot_set_last_error("llvm add basic block failed."); \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SET_BUILD_POS(block) \
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, block)
|
||||
|
||||
static LLVMValueRef
|
||||
check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 offset, uint32 bytes)
|
||||
{
|
||||
LLVMValueRef offset_const = I32_CONST(offset);
|
||||
LLVMValueRef size_const = I32_CONST(bytes);
|
||||
LLVMValueRef addr, maddr, moffset;
|
||||
LLVMValueRef cmp, phi;
|
||||
LLVMValueRef mem_base_addr, mem_data_size;
|
||||
LLVMValueRef heap_base_addr, heap_base_offset;
|
||||
LLVMValueRef mem_offset_max = NULL, heap_offset_max = NULL;
|
||||
LLVMBasicBlockRef check_mem_space, check_heap_space, check_succ;
|
||||
LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
|
||||
|
||||
CHECK_LLVM_CONST(offset_const);
|
||||
CHECK_LLVM_CONST(size_const);
|
||||
|
||||
heap_base_addr = func_ctx->heap_base_addr;
|
||||
heap_base_offset = func_ctx->heap_base_offset;
|
||||
|
||||
POP_I32(addr);
|
||||
BUILD_OP(Add, offset_const, addr, moffset, "moffset");
|
||||
|
||||
/* return addres directly if constant offset and inside memory space */
|
||||
if (LLVMIsConstant(moffset)) {
|
||||
uint32 memory_offset = (uint32)LLVMConstIntGetZExtValue(moffset);
|
||||
uint32 init_page_count = comp_ctx->comp_data->mem_init_page_count;
|
||||
if (init_page_count > 0
|
||||
&& memory_offset <= NumBytesPerPage * init_page_count - bytes) {
|
||||
/* inside memory space */
|
||||
if (!func_ctx->mem_space_unchanged) {
|
||||
if (!(mem_base_addr = LLVMBuildLoad(comp_ctx->builder,
|
||||
func_ctx->mem_base_addr,
|
||||
"mem_base"))) {
|
||||
aot_set_last_error("llvm build load failed.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mem_base_addr = func_ctx->mem_base_addr;
|
||||
}
|
||||
|
||||
/* maddr = mem_base_addr + moffset */
|
||||
if (!(maddr = LLVMBuildInBoundsGEP(comp_ctx->builder,
|
||||
mem_base_addr,
|
||||
&moffset, 1, "maddr"))) {
|
||||
aot_set_last_error("llvm build add failed.");
|
||||
goto fail;
|
||||
}
|
||||
return maddr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add basic blocks */
|
||||
ADD_BASIC_BLOCK(check_heap_space, "check_heap_space");
|
||||
ADD_BASIC_BLOCK(check_succ, "check_succ");
|
||||
|
||||
LLVMMoveBasicBlockAfter(check_heap_space, block_curr);
|
||||
LLVMMoveBasicBlockAfter(check_succ, check_heap_space);
|
||||
|
||||
/* Add return maddress phi for check_succ block */
|
||||
SET_BUILD_POS(check_succ);
|
||||
if (!(phi = LLVMBuildPhi(comp_ctx->builder,
|
||||
INT8_PTR_TYPE, "maddr_phi"))) {
|
||||
aot_set_last_error("llvm build phi failed.");
|
||||
goto fail;
|
||||
}
|
||||
SET_BUILD_POS(block_curr);
|
||||
|
||||
/* Get memory data size */
|
||||
if (!func_ctx->mem_space_unchanged) {
|
||||
if (!(mem_data_size = LLVMBuildLoad(comp_ctx->builder,
|
||||
func_ctx->mem_data_size,
|
||||
"mem_data_size"))) {
|
||||
aot_set_last_error("llvm build load failed.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mem_data_size = func_ctx->mem_data_size;
|
||||
}
|
||||
|
||||
if (comp_ctx->comp_data->mem_init_page_count == 0) {
|
||||
ADD_BASIC_BLOCK(check_mem_space, "check_mem_space");
|
||||
LLVMMoveBasicBlockAfter(check_mem_space, block_curr);
|
||||
|
||||
/* if mem_data_size is zero, check heap space */
|
||||
BUILD_ICMP(LLVMIntEQ, mem_data_size, I32_ZERO, cmp,
|
||||
"cmp_mem_data_size");
|
||||
BUILD_COND_BR(cmp, check_heap_space, check_mem_space);
|
||||
SET_BUILD_POS(check_mem_space);
|
||||
}
|
||||
|
||||
/* Get memory base address */
|
||||
if (!func_ctx->mem_space_unchanged) {
|
||||
if (!(mem_base_addr = LLVMBuildLoad(comp_ctx->builder,
|
||||
func_ctx->mem_base_addr,
|
||||
"mem_base"))) {
|
||||
aot_set_last_error("llvm build load failed.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mem_base_addr = func_ctx->mem_base_addr;
|
||||
}
|
||||
|
||||
/* maddr = mem_base_addr + moffset */
|
||||
if (!(maddr = LLVMBuildInBoundsGEP(comp_ctx->builder, mem_base_addr,
|
||||
&moffset, 1, "maddr"))) {
|
||||
aot_set_last_error("llvm build add failed.");
|
||||
goto fail;
|
||||
}
|
||||
block_curr = LLVMGetInsertBlock(comp_ctx->builder);
|
||||
LLVMAddIncoming(phi, &maddr, &block_curr, 1);
|
||||
|
||||
if (!func_ctx->mem_space_unchanged) {
|
||||
/* mem_offset_max = mem_data_size - bytes to load/read */
|
||||
if (!(mem_offset_max = LLVMBuildSub(comp_ctx->builder,
|
||||
mem_data_size, size_const,
|
||||
"mem_offset_max"))) {
|
||||
aot_set_last_error("llvm build sub failed.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (bytes == 1)
|
||||
mem_offset_max = func_ctx->mem_bound_1_byte;
|
||||
else if (bytes == 2)
|
||||
mem_offset_max = func_ctx->mem_bound_2_bytes;
|
||||
else if (bytes == 4)
|
||||
mem_offset_max = func_ctx->mem_bound_4_bytes;
|
||||
else if (bytes == 8)
|
||||
mem_offset_max = func_ctx->mem_bound_8_bytes;
|
||||
}
|
||||
|
||||
/* in linear memory if (uint32)moffset <= (uint32)mem_offset_max,
|
||||
else check heap space */
|
||||
BUILD_ICMP(LLVMIntULE, moffset, mem_offset_max, cmp, "cmp_mem_offset");
|
||||
|
||||
/* Create condtion br */
|
||||
BUILD_COND_BR(cmp, check_succ, check_heap_space);
|
||||
|
||||
/* Start to translate the check_heap_space block */
|
||||
SET_BUILD_POS(check_heap_space);
|
||||
|
||||
/* moffset -= heap_base_offset */
|
||||
if (!(moffset = LLVMBuildSub(comp_ctx->builder,
|
||||
moffset, heap_base_offset,
|
||||
"moffset_to_heap"))) {
|
||||
aot_set_last_error("llvm build sub failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* maddr = heap_base_addr + moffset */
|
||||
if (!(maddr = LLVMBuildInBoundsGEP(comp_ctx->builder, heap_base_addr,
|
||||
&moffset, 1, "maddr"))) {
|
||||
aot_set_last_error("llvm build add failed.");
|
||||
goto fail;
|
||||
}
|
||||
block_curr = LLVMGetInsertBlock(comp_ctx->builder);
|
||||
LLVMAddIncoming(phi, &maddr, &block_curr, 1);
|
||||
|
||||
/* heap space base addr and size is unchanged,
|
||||
the heap boundary is unchanged also. */
|
||||
if (bytes == 1)
|
||||
heap_offset_max = func_ctx->heap_bound_1_byte;
|
||||
else if (bytes == 2)
|
||||
heap_offset_max = func_ctx->heap_bound_2_bytes;
|
||||
else if (bytes == 4)
|
||||
heap_offset_max = func_ctx->heap_bound_4_bytes;
|
||||
else if (bytes == 8)
|
||||
heap_offset_max = func_ctx->heap_bound_8_bytes;
|
||||
|
||||
/* in heap space if (uint32)moffset <= (uint32)heap_offset_max,
|
||||
else throw exception */
|
||||
BUILD_ICMP(LLVMIntUGT, moffset, heap_offset_max, cmp, "cmp_heap_offset");
|
||||
if (!aot_emit_exception(comp_ctx, func_ctx,
|
||||
EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS,
|
||||
true, cmp, check_succ))
|
||||
goto fail;
|
||||
|
||||
SET_BUILD_POS(check_succ);
|
||||
return phi;
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define BUILD_PTR_CAST(ptr_type) do { \
|
||||
if (!(maddr = LLVMBuildBitCast(comp_ctx->builder, maddr,\
|
||||
ptr_type, "data_ptr"))) {\
|
||||
aot_set_last_error("llvm build bit cast failed."); \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BUILD_LOAD() do { \
|
||||
if (!(value = LLVMBuildLoad(comp_ctx->builder, maddr, \
|
||||
"data"))) { \
|
||||
aot_set_last_error("llvm build load failed."); \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BUILD_TRUNC(data_type) do { \
|
||||
if (!(value = LLVMBuildTrunc(comp_ctx->builder, value, \
|
||||
data_type, "val_trunc"))){ \
|
||||
aot_set_last_error("llvm build trunc failed."); \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BUILD_STORE() do { \
|
||||
if (!LLVMBuildStore(comp_ctx->builder, value, maddr)) { \
|
||||
aot_set_last_error("llvm build store failed."); \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BUILD_SIGN_EXT(dst_type) do { \
|
||||
if (!(value = LLVMBuildSExt(comp_ctx->builder, value, \
|
||||
dst_type, "data_s_ext"))) { \
|
||||
aot_set_last_error("llvm build sign ext failed."); \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BUILD_ZERO_EXT(dst_type) do { \
|
||||
if (!(value = LLVMBuildZExt(comp_ctx->builder, value, \
|
||||
dst_type, "data_z_ext"))) { \
|
||||
aot_set_last_error("llvm build zero ext failed."); \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 align, uint32 offset, uint32 bytes, bool sign)
|
||||
{
|
||||
LLVMValueRef maddr, value = NULL;
|
||||
|
||||
if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, bytes)))
|
||||
return false;
|
||||
|
||||
switch (bytes) {
|
||||
case 4:
|
||||
BUILD_PTR_CAST(INT32_PTR_TYPE);
|
||||
BUILD_LOAD();
|
||||
break;
|
||||
case 2:
|
||||
case 1:
|
||||
if (bytes == 2)
|
||||
BUILD_PTR_CAST(INT16_PTR_TYPE);
|
||||
else
|
||||
BUILD_PTR_CAST(INT8_PTR_TYPE);
|
||||
BUILD_LOAD();
|
||||
if (sign)
|
||||
BUILD_SIGN_EXT(I32_TYPE);
|
||||
else
|
||||
BUILD_ZERO_EXT(I32_TYPE);
|
||||
break;
|
||||
default:
|
||||
bh_assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
PUSH_I32(value);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 align, uint32 offset, uint32 bytes, bool sign)
|
||||
{
|
||||
LLVMValueRef maddr, value = NULL;
|
||||
|
||||
if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, bytes)))
|
||||
return false;
|
||||
|
||||
switch (bytes) {
|
||||
case 8:
|
||||
BUILD_PTR_CAST(INT64_PTR_TYPE);
|
||||
BUILD_LOAD();
|
||||
break;
|
||||
case 4:
|
||||
case 2:
|
||||
case 1:
|
||||
if (bytes == 4)
|
||||
BUILD_PTR_CAST(INT32_PTR_TYPE);
|
||||
else if (bytes == 2)
|
||||
BUILD_PTR_CAST(INT16_PTR_TYPE);
|
||||
else
|
||||
BUILD_PTR_CAST(INT8_PTR_TYPE);
|
||||
BUILD_LOAD();
|
||||
if (sign)
|
||||
BUILD_SIGN_EXT(I64_TYPE);
|
||||
else
|
||||
BUILD_ZERO_EXT(I64_TYPE);
|
||||
break;
|
||||
default:
|
||||
bh_assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
PUSH_I64(value);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_f32_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 align, uint32 offset)
|
||||
{
|
||||
LLVMValueRef maddr, value;
|
||||
|
||||
if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, 4)))
|
||||
return false;
|
||||
|
||||
BUILD_PTR_CAST(F32_PTR_TYPE);
|
||||
BUILD_LOAD();
|
||||
PUSH_F32(value);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_f64_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 align, uint32 offset)
|
||||
{
|
||||
LLVMValueRef maddr, value;
|
||||
|
||||
if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, 8)))
|
||||
return false;
|
||||
|
||||
BUILD_PTR_CAST(F64_PTR_TYPE);
|
||||
BUILD_LOAD();
|
||||
PUSH_F64(value);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_store(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 align, uint32 offset, uint32 bytes)
|
||||
{
|
||||
LLVMValueRef maddr, value;
|
||||
|
||||
POP_I32(value);
|
||||
|
||||
if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, bytes)))
|
||||
return false;
|
||||
|
||||
switch (bytes) {
|
||||
case 4:
|
||||
BUILD_PTR_CAST(INT32_PTR_TYPE);
|
||||
break;
|
||||
case 2:
|
||||
BUILD_PTR_CAST(INT16_PTR_TYPE);
|
||||
BUILD_TRUNC(INT16_TYPE);
|
||||
break;
|
||||
case 1:
|
||||
BUILD_PTR_CAST(INT8_PTR_TYPE);
|
||||
BUILD_TRUNC(INT8_TYPE);
|
||||
break;
|
||||
default:
|
||||
bh_assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
BUILD_STORE();
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_store(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 align, uint32 offset, uint32 bytes)
|
||||
{
|
||||
LLVMValueRef maddr, value;
|
||||
|
||||
POP_I64(value);
|
||||
|
||||
if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, bytes)))
|
||||
return false;
|
||||
|
||||
switch (bytes) {
|
||||
case 8:
|
||||
BUILD_PTR_CAST(INT64_PTR_TYPE);
|
||||
break;
|
||||
case 4:
|
||||
BUILD_PTR_CAST(INT32_PTR_TYPE);
|
||||
BUILD_TRUNC(I32_TYPE);
|
||||
break;
|
||||
case 2:
|
||||
BUILD_PTR_CAST(INT16_PTR_TYPE);
|
||||
BUILD_TRUNC(INT16_TYPE);
|
||||
break;
|
||||
case 1:
|
||||
BUILD_PTR_CAST(INT8_PTR_TYPE);
|
||||
BUILD_TRUNC(INT8_TYPE);
|
||||
break;
|
||||
default:
|
||||
bh_assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
BUILD_STORE();
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_f32_store(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 align, uint32 offset)
|
||||
{
|
||||
LLVMValueRef maddr, value;
|
||||
|
||||
POP_F32(value);
|
||||
|
||||
if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, 4)))
|
||||
return false;
|
||||
|
||||
BUILD_PTR_CAST(F32_PTR_TYPE);
|
||||
BUILD_STORE();
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_f64_store(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 align, uint32 offset)
|
||||
{
|
||||
LLVMValueRef maddr, value;
|
||||
|
||||
POP_F64(value);
|
||||
|
||||
if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, 8)))
|
||||
return false;
|
||||
|
||||
BUILD_PTR_CAST(F64_PTR_TYPE);
|
||||
BUILD_STORE();
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static LLVMValueRef
|
||||
get_memory_size(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
{
|
||||
uint32 offset = offsetof(AOTModuleInstance, mem_cur_page_count);
|
||||
LLVMValueRef mem_size_offset, mem_size_ptr, mem_size;
|
||||
|
||||
/* mem_size_offset = aot_inst + offset */
|
||||
mem_size_offset = I32_CONST(offset);
|
||||
CHECK_LLVM_CONST(mem_size_offset);
|
||||
if (!(mem_size_ptr = LLVMBuildInBoundsGEP(comp_ctx->builder,
|
||||
func_ctx->aot_inst,
|
||||
&mem_size_offset, 1,
|
||||
"mem_size_ptr_tmp"))) {
|
||||
aot_set_last_error("llvm build inbounds gep failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* cast to int32* */
|
||||
if (!(mem_size_ptr = LLVMBuildBitCast(comp_ctx->builder, mem_size_ptr,
|
||||
INT32_PTR_TYPE, "mem_size_ptr"))) {
|
||||
aot_set_last_error("llvm build bitcast failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* load memory size, or current page count */
|
||||
if (!(mem_size = LLVMBuildLoad(comp_ctx->builder,
|
||||
mem_size_ptr, "mem_size"))) {
|
||||
aot_set_last_error("llvm build load failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return mem_size;
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_memory_size(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
{
|
||||
LLVMValueRef mem_size = get_memory_size(comp_ctx, func_ctx);
|
||||
|
||||
if (mem_size)
|
||||
PUSH_I32(mem_size);
|
||||
return mem_size ? true : false;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
{
|
||||
LLVMValueRef mem_size = get_memory_size(comp_ctx, func_ctx);
|
||||
LLVMValueRef delta, param_values[2], ret_value, func, value;
|
||||
LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type;
|
||||
|
||||
if (!mem_size)
|
||||
return false;
|
||||
|
||||
POP_I32(delta);
|
||||
|
||||
/* Function type of wasm_runtime_enlarge_memory() */
|
||||
param_types[0] = INT8_PTR_TYPE;
|
||||
param_types[1] = I32_TYPE;
|
||||
ret_type = INT8_TYPE;
|
||||
|
||||
if (!(func_type = LLVMFunctionType(ret_type, param_types, 2, 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)wasm_runtime_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";
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call function wasm_runtime_enlarge_memory() */
|
||||
param_values[0] = func_ctx->aot_inst;
|
||||
param_values[1] = delta;
|
||||
if (!(ret_value = LLVMBuildCall(comp_ctx->builder, func,
|
||||
param_values, 2, "call"))) {
|
||||
aot_set_last_error("llvm build call failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* convert call result from i8 to i1 */
|
||||
if (!(ret_value = LLVMBuildIntCast(comp_ctx->builder, ret_value,
|
||||
INT1_TYPE, "mem_grow_ret"))) {
|
||||
aot_set_last_error("llvm build bit cast failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ret_value = ret_value == true ? delta : pre_page_count */
|
||||
if (!(ret_value = LLVMBuildSelect(comp_ctx->builder, ret_value,
|
||||
mem_size, I32_NEG_ONE,
|
||||
"mem_grow_ret"))) {
|
||||
aot_set_last_error("llvm build select failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PUSH_I32(ret_value);
|
||||
|
||||
/* To be simple, call wasm_runtime_set_exception() no matter
|
||||
enlarge success or not */
|
||||
param_types[1] = VOID_PTR_TYPE;
|
||||
ret_type = VOID_TYPE;
|
||||
if (!(func_type = LLVMFunctionType(ret_type, param_types, 2, 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)wasm_runtime_set_exception))
|
||||
|| !(func = LLVMConstIntToPtr(value, func_ptr_type))) {
|
||||
aot_set_last_error("create LLVM value failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
char *func_name = "wasm_runtime_set_exception";
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call function wasm_runtime_set_exception(aot_inst, NULL) */
|
||||
param_values[1] = LLVMConstNull(VOID_PTR_TYPE);
|
||||
CHECK_LLVM_CONST(param_values[1]);
|
||||
if (!(LLVMBuildCall(comp_ctx->builder, func, param_values, 2, ""))) {
|
||||
aot_set_last_error("llvm build call failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
58
core/iwasm/compilation/aot_emit_memory.h
Normal file
58
core/iwasm/compilation/aot_emit_memory.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _AOT_EMIT_MEMORY_H_
|
||||
#define _AOT_EMIT_MEMORY_H_
|
||||
|
||||
#include "aot_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 align, uint32 offset, uint32 bytes, bool sign);
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 align, uint32 offset, uint32 bytes, bool sign);
|
||||
|
||||
bool
|
||||
aot_compile_op_f32_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 align, uint32 offset);
|
||||
|
||||
bool
|
||||
aot_compile_op_f64_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 align, uint32 offset);
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_store(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 align, uint32 offset, uint32 bytes);
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_store(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 align, uint32 offset, uint32 bytes);
|
||||
|
||||
bool
|
||||
aot_compile_op_f32_store(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 align, uint32 offset);
|
||||
|
||||
bool
|
||||
aot_compile_op_f64_store(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 align, uint32 offset);
|
||||
|
||||
bool
|
||||
aot_compile_op_memory_size(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
|
||||
bool
|
||||
aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _AOT_EMIT_MEMORY_H_ */
|
||||
|
||||
1175
core/iwasm/compilation/aot_emit_numberic.c
Normal file
1175
core/iwasm/compilation/aot_emit_numberic.c
Normal file
File diff suppressed because it is too large
Load Diff
84
core/iwasm/compilation/aot_emit_numberic.h
Normal file
84
core/iwasm/compilation/aot_emit_numberic.h
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _AOT_EMIT_NUMBERIC_H_
|
||||
#define _AOT_EMIT_NUMBERIC_H_
|
||||
|
||||
#include "aot_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_clz(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_ctz(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_popcnt(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_clz(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_ctz(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_popcnt(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
IntArithmetic arith_op, uint8 **p_frame_ip);
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
IntArithmetic arith_op, uint8 **p_frame_ip);
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_bitwise(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
IntBitwise bitwise_op);
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_bitwise(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
IntBitwise bitwise_op);
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_shift(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
IntShift shift_op);
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_shift(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
IntShift shift_op);
|
||||
|
||||
bool
|
||||
aot_compile_op_f32_math(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
FloatMath math_op);
|
||||
|
||||
bool
|
||||
aot_compile_op_f64_math(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
FloatMath math_op);
|
||||
|
||||
bool
|
||||
aot_compile_op_f32_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
FloatArithmetic arith_op);
|
||||
|
||||
bool
|
||||
aot_compile_op_f64_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
FloatArithmetic arith_op);
|
||||
|
||||
bool
|
||||
aot_compile_op_f32_copysign(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
|
||||
bool
|
||||
aot_compile_op_f64_copysign(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _AOT_EMIT_NUMBERIC_H_ */
|
||||
|
||||
102
core/iwasm/compilation/aot_emit_parametric.c
Normal file
102
core/iwasm/compilation/aot_emit_parametric.c
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "aot_emit_parametric.h"
|
||||
|
||||
static bool
|
||||
pop_value_from_wasm_stack(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
LLVMValueRef *p_value,
|
||||
bool is_32, uint8 *p_type)
|
||||
{
|
||||
AOTValue *aot_value;
|
||||
uint8 type;
|
||||
|
||||
if (!func_ctx->block_stack.block_list_end) {
|
||||
aot_set_last_error("WASM block stack underflow.");
|
||||
return false;
|
||||
}
|
||||
if (!func_ctx->block_stack.block_list_end->value_stack.value_list_end) {
|
||||
aot_set_last_error("WASM data stack underflow.");
|
||||
return false;
|
||||
}
|
||||
|
||||
aot_value = aot_value_stack_pop
|
||||
(&func_ctx->block_stack.block_list_end->value_stack);
|
||||
type = aot_value->type;
|
||||
|
||||
if (aot_value->type == VALUE_TYPE_I1) {
|
||||
if (!(aot_value->value =
|
||||
LLVMBuildZExt(comp_ctx->builder, aot_value->value,
|
||||
I32_TYPE, "val_s_ext"))) {
|
||||
aot_set_last_error("llvm build sign ext failed.");
|
||||
return false;
|
||||
}
|
||||
type = aot_value->type = VALUE_TYPE_I32;
|
||||
}
|
||||
|
||||
if (p_type != NULL) {
|
||||
*p_type = aot_value->type;
|
||||
}
|
||||
if (p_value != NULL) {
|
||||
*p_value = aot_value->value;
|
||||
}
|
||||
|
||||
wasm_free(aot_value);
|
||||
|
||||
if ((is_32
|
||||
&& (type != VALUE_TYPE_I32 && type != VALUE_TYPE_F32))
|
||||
|| (!is_32
|
||||
&& (type != VALUE_TYPE_I64 && type != VALUE_TYPE_F64))) {
|
||||
aot_set_last_error("invalid WASM stack data type.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
aot_compile_op_drop(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool is_drop_32)
|
||||
{
|
||||
if (!pop_value_from_wasm_stack(comp_ctx, func_ctx, NULL, is_drop_32, NULL))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_select(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool is_select_32)
|
||||
{
|
||||
LLVMValueRef val1, val2, cond, selected;
|
||||
uint8 val1_type, val2_type;
|
||||
|
||||
POP_COND(cond);
|
||||
|
||||
if (!pop_value_from_wasm_stack(comp_ctx, func_ctx, &val2, is_select_32, &val2_type)
|
||||
|| !pop_value_from_wasm_stack(comp_ctx, func_ctx, &val1, is_select_32, &val1_type))
|
||||
return false;
|
||||
|
||||
if (val1_type != val2_type) {
|
||||
aot_set_last_error("invalid stack values with different type");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(selected = LLVMBuildSelect(comp_ctx->builder,
|
||||
cond, val1, val2,
|
||||
"select"))) {
|
||||
aot_set_last_error("llvm build select failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PUSH(selected, val1_type);
|
||||
|
||||
return true;
|
||||
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
29
core/iwasm/compilation/aot_emit_parametric.h
Normal file
29
core/iwasm/compilation/aot_emit_parametric.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _AOT_EMIT_PARAMETRIC_H_
|
||||
#define _AOT_EMIT_PARAMETRIC_H_
|
||||
|
||||
#include "aot_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool
|
||||
aot_compile_op_drop(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool is_drop_32);
|
||||
|
||||
bool
|
||||
aot_compile_op_select(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool is_select_32);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _AOT_EMIT_PARAMETRIC_H_ */
|
||||
|
||||
193
core/iwasm/compilation/aot_emit_variable.c
Normal file
193
core/iwasm/compilation/aot_emit_variable.c
Normal file
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "aot_emit_variable.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;
|
||||
|
||||
CHECK_LOCAL(local_idx);
|
||||
|
||||
snprintf(name, sizeof(name), "%s%d%s", "local", local_idx, "#");
|
||||
if (!(value = LLVMBuildLoad(comp_ctx->builder,
|
||||
func_ctx->locals[local_idx],
|
||||
name))) {
|
||||
aot_set_last_error("llvm build load fail");
|
||||
return false;
|
||||
}
|
||||
|
||||
PUSH(value, get_local_type(func_ctx, 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;
|
||||
}
|
||||
|
||||
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);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 global_idx, bool is_set)
|
||||
{
|
||||
AOTCompData *comp_data = comp_ctx->comp_data;
|
||||
uint32 import_global_count = comp_data->import_global_count;
|
||||
uint32 global_base_offset = offsetof(AOTModuleInstance,
|
||||
global_table_heap_data.bytes);
|
||||
uint32 global_offset;
|
||||
uint8 global_type;
|
||||
LLVMValueRef offset, global_ptr, global;
|
||||
LLVMTypeRef ptr_type = NULL;
|
||||
|
||||
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 = LLVMBuildInBoundsGEP(comp_ctx->builder, 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:
|
||||
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;
|
||||
default:
|
||||
bh_assert(0);
|
||||
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 = LLVMBuildLoad(comp_ctx->builder,
|
||||
global_ptr, "global"))) {
|
||||
aot_set_last_error("llvm build load failed.");
|
||||
return false;
|
||||
}
|
||||
PUSH(global, global_type);
|
||||
}
|
||||
else {
|
||||
POP(global, global_type);
|
||||
if (!LLVMBuildStore(comp_ctx->builder, global, global_ptr)) {
|
||||
aot_set_last_error("llvm build store failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_set_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 global_idx)
|
||||
{
|
||||
return compile_global(comp_ctx, func_ctx, global_idx, true);
|
||||
}
|
||||
|
||||
40
core/iwasm/compilation/aot_emit_variable.h
Normal file
40
core/iwasm/compilation/aot_emit_variable.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _AOT_EMIT_VARIABLE_H_
|
||||
#define _AOT_EMIT_VARIABLE_H_
|
||||
|
||||
#include "aot_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool
|
||||
aot_compile_op_get_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 local_idx);
|
||||
|
||||
bool
|
||||
aot_compile_op_set_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 local_idx);
|
||||
|
||||
bool
|
||||
aot_compile_op_tee_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 local_idx);
|
||||
|
||||
bool
|
||||
aot_compile_op_get_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 global_idx);
|
||||
|
||||
bool
|
||||
aot_compile_op_set_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 global_idx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _AOT_EMIT_VARIABLE_H_ */
|
||||
|
||||
1230
core/iwasm/compilation/aot_llvm.c
Normal file
1230
core/iwasm/compilation/aot_llvm.c
Normal file
File diff suppressed because it is too large
Load Diff
270
core/iwasm/compilation/aot_llvm.h
Normal file
270
core/iwasm/compilation/aot_llvm.h
Normal file
@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _AOT_LLVM_H_
|
||||
#define _AOT_LLVM_H_
|
||||
|
||||
#include "aot.h"
|
||||
#include "llvm-c/Types.h"
|
||||
#include "llvm-c/Target.h"
|
||||
#include "llvm-c/Core.h"
|
||||
#include "llvm-c/Object.h"
|
||||
#include "llvm-c/ExecutionEngine.h"
|
||||
#include "llvm-c/Analysis.h"
|
||||
#include "llvm-c/Transforms/Scalar.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Value in the WASM operation stack, each stack element
|
||||
* is an LLVM value
|
||||
*/
|
||||
typedef struct AOTValue {
|
||||
struct AOTValue *next;
|
||||
struct AOTValue *prev;
|
||||
LLVMValueRef value;
|
||||
/* VALUE_TYPE_I32/I64/F32/F64/VOID */
|
||||
uint8 type;
|
||||
} AOTValue;
|
||||
|
||||
/**
|
||||
* Value stack, represents stack elements in a WASM block
|
||||
*/
|
||||
typedef struct AOTValueStack {
|
||||
AOTValue *value_list_head;
|
||||
AOTValue *value_list_end;
|
||||
} AOTValueStack;
|
||||
|
||||
typedef struct AOTBlock {
|
||||
struct AOTBlock *next;
|
||||
struct AOTBlock *prev;
|
||||
|
||||
/* Block index */
|
||||
uint32 block_index;
|
||||
/* BLOCK_TYPE_BLOCK/LOOP/IF/FUNCTION */
|
||||
uint32 block_type;
|
||||
/* VALUE_TYPE_I32/I64/F32/F64/VOID */
|
||||
uint8 return_type;
|
||||
/* Whether it is reachable */
|
||||
bool is_reachable;
|
||||
/* Whether skip translation of wasm else branch */
|
||||
bool skip_wasm_code_else;
|
||||
|
||||
/* code of else opcode of this block, if it is a IF block */
|
||||
uint8 *wasm_code_else;
|
||||
/* code end of this block */
|
||||
uint8 *wasm_code_end;
|
||||
|
||||
/* LLVM label points to code begin */
|
||||
LLVMBasicBlockRef llvm_entry_block;
|
||||
/* LLVM label points to code else */
|
||||
LLVMBasicBlockRef llvm_else_block;
|
||||
/* LLVM label points to code end */
|
||||
LLVMBasicBlockRef llvm_end_block;
|
||||
|
||||
/* WASM operation stack */
|
||||
AOTValueStack value_stack;
|
||||
|
||||
/* Return value of this block, a PHI node */
|
||||
LLVMValueRef return_value_phi;
|
||||
} AOTBlock;
|
||||
|
||||
/**
|
||||
* Block stack, represents WASM block stack elements
|
||||
*/
|
||||
typedef struct AOTBlockStack {
|
||||
AOTBlock *block_list_head;
|
||||
AOTBlock *block_list_end;
|
||||
/* Current block index of each block type */
|
||||
uint32 block_index[3];
|
||||
} AOTBlockStack;
|
||||
|
||||
typedef struct AOTFuncContext {
|
||||
AOTFunc *aot_func;
|
||||
LLVMValueRef func;
|
||||
AOTBlockStack block_stack;
|
||||
|
||||
LLVMValueRef exec_env;
|
||||
LLVMValueRef aot_inst;
|
||||
LLVMValueRef table_base;
|
||||
|
||||
LLVMValueRef mem_data_size;
|
||||
LLVMValueRef mem_base_addr;
|
||||
LLVMValueRef mem_bound_1_byte;
|
||||
LLVMValueRef mem_bound_2_bytes;
|
||||
LLVMValueRef mem_bound_4_bytes;
|
||||
LLVMValueRef mem_bound_8_bytes;
|
||||
|
||||
LLVMValueRef heap_base_offset;
|
||||
LLVMValueRef heap_base_addr;
|
||||
LLVMValueRef heap_data_size;
|
||||
LLVMValueRef heap_bound_1_byte;
|
||||
LLVMValueRef heap_bound_2_bytes;
|
||||
LLVMValueRef heap_bound_4_bytes;
|
||||
LLVMValueRef heap_bound_8_bytes;
|
||||
|
||||
LLVMValueRef cur_exception;
|
||||
|
||||
bool mem_space_unchanged;
|
||||
|
||||
LLVMBasicBlockRef *exception_blocks;
|
||||
LLVMBasicBlockRef got_exception_block;
|
||||
LLVMBasicBlockRef func_return_block;
|
||||
LLVMValueRef exception_id_phi;
|
||||
LLVMValueRef func_ptrs;
|
||||
LLVMValueRef func_type_indexes;
|
||||
LLVMValueRef locals[1];
|
||||
} AOTFuncContext;
|
||||
|
||||
typedef struct AOTLLVMTypes {
|
||||
LLVMTypeRef int1_type;
|
||||
LLVMTypeRef int8_type;
|
||||
LLVMTypeRef int16_type;
|
||||
LLVMTypeRef int32_type;
|
||||
LLVMTypeRef int64_type;
|
||||
LLVMTypeRef float32_type;
|
||||
LLVMTypeRef float64_type;
|
||||
LLVMTypeRef void_type;
|
||||
|
||||
LLVMTypeRef int8_ptr_type;
|
||||
LLVMTypeRef int16_ptr_type;
|
||||
LLVMTypeRef int32_ptr_type;
|
||||
LLVMTypeRef int64_ptr_type;
|
||||
LLVMTypeRef float32_ptr_type;
|
||||
LLVMTypeRef float64_ptr_type;
|
||||
LLVMTypeRef void_ptr_type;
|
||||
|
||||
LLVMTypeRef meta_data_type;
|
||||
} AOTLLVMTypes;
|
||||
|
||||
typedef struct AOTLLVMConsts {
|
||||
LLVMValueRef i8_zero;
|
||||
LLVMValueRef i32_zero;
|
||||
LLVMValueRef i64_zero;
|
||||
LLVMValueRef f32_zero;
|
||||
LLVMValueRef f64_zero;
|
||||
LLVMValueRef i32_one;
|
||||
LLVMValueRef i32_two;
|
||||
LLVMValueRef i32_four;
|
||||
LLVMValueRef i32_eight;
|
||||
LLVMValueRef i32_neg_one;
|
||||
LLVMValueRef i64_neg_one;
|
||||
LLVMValueRef i32_min;
|
||||
LLVMValueRef i64_min;
|
||||
LLVMValueRef i32_31;
|
||||
LLVMValueRef i32_32;
|
||||
LLVMValueRef i64_63;
|
||||
LLVMValueRef i64_64;
|
||||
} AOTLLVMConsts;
|
||||
|
||||
/**
|
||||
* Compiler context
|
||||
*/
|
||||
typedef struct AOTCompContext {
|
||||
AOTCompData *comp_data;
|
||||
|
||||
/* LLVM variables required to emit LLVM IR */
|
||||
LLVMContextRef context;
|
||||
LLVMModuleRef module;
|
||||
LLVMBuilderRef builder;
|
||||
LLVMTargetMachineRef target_machine;
|
||||
char *target_cpu;
|
||||
char target_arch[16];
|
||||
|
||||
/* LLVM execution engine required by JIT */
|
||||
LLVMExecutionEngineRef exec_engine;
|
||||
bool is_jit_mode;
|
||||
|
||||
/* Whether optimize the JITed code */
|
||||
bool optimize;
|
||||
|
||||
/* LLVM pass manager to optimize the JITed code */
|
||||
LLVMPassManagerRef pass_mgr;
|
||||
|
||||
/* LLVM floating-point rounding mode metadata */
|
||||
LLVMValueRef fp_rounding_mode;
|
||||
|
||||
/* LLVM floating-point exception behavior metadata */
|
||||
LLVMValueRef fp_exception_behavior;
|
||||
|
||||
/* LLVM data types */
|
||||
AOTLLVMTypes basic_types;
|
||||
LLVMTypeRef exec_env_type;
|
||||
LLVMTypeRef aot_inst_type;
|
||||
|
||||
/* LLVM const values */
|
||||
AOTLLVMConsts llvm_consts;
|
||||
|
||||
/* Function contexts */
|
||||
AOTFuncContext **func_ctxes;
|
||||
uint32 func_ctx_count;
|
||||
} AOTCompContext;
|
||||
|
||||
enum {
|
||||
AOT_FORMAT_FILE,
|
||||
AOT_OBJECT_FILE,
|
||||
AOT_LLVMIR_UNOPT_FILE,
|
||||
AOT_LLVMIR_OPT_FILE,
|
||||
};
|
||||
|
||||
typedef struct AOTCompOption{
|
||||
bool is_jit_mode;
|
||||
char *target_arch;
|
||||
char *target_abi;
|
||||
char *target_cpu;
|
||||
char *cpu_features;
|
||||
uint32 opt_level;
|
||||
uint32 output_format;
|
||||
} AOTCompOption, *aot_comp_option_t;
|
||||
|
||||
AOTCompContext *
|
||||
aot_create_comp_context(AOTCompData *comp_data,
|
||||
aot_comp_option_t option);
|
||||
|
||||
void
|
||||
aot_destroy_comp_context(AOTCompContext *comp_ctx);
|
||||
|
||||
bool
|
||||
aot_compile_wasm(AOTCompContext *comp_ctx);
|
||||
|
||||
uint8*
|
||||
aot_emit_elf_file(AOTCompContext *comp_ctx, uint32 *p_elf_file_size);
|
||||
|
||||
void
|
||||
aot_destroy_elf_file(uint8 *elf_file);
|
||||
|
||||
void
|
||||
aot_value_stack_push(AOTValueStack *stack, AOTValue *value);
|
||||
|
||||
AOTValue *
|
||||
aot_value_stack_pop(AOTValueStack *stack);
|
||||
|
||||
void
|
||||
aot_value_stack_destroy(AOTValueStack *stack);
|
||||
|
||||
void
|
||||
aot_block_stack_push(AOTBlockStack *stack, AOTBlock *block);
|
||||
|
||||
AOTBlock *
|
||||
aot_block_stack_pop(AOTBlockStack *stack);
|
||||
|
||||
void
|
||||
aot_block_stack_destroy(AOTBlockStack *stack);
|
||||
|
||||
void
|
||||
aot_block_destroy(AOTBlock *block);
|
||||
|
||||
LLVMTypeRef
|
||||
wasm_type_to_llvm_type(AOTLLVMTypes *llvm_types, uint8 wasm_type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _AOT_LLVM_H_ */
|
||||
|
||||
8
core/iwasm/compilation/iwasm_compl.cmake
Normal file
8
core/iwasm/compilation/iwasm_compl.cmake
Normal file
@ -0,0 +1,8 @@
|
||||
set (IWASM_COMPL_DIR ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
include_directories(${IWASM_COMPL_DIR})
|
||||
|
||||
file (GLOB_RECURSE source_all ${IWASM_COMPL_DIR}/*.c)
|
||||
|
||||
set (IWASM_COMPL_SOURCE ${source_all})
|
||||
|
||||
Reference in New Issue
Block a user