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:
wenyongh
2020-01-21 13:26:14 +08:00
committed by Wang Xin
parent 2a4528c749
commit 46b93b9d22
464 changed files with 25137 additions and 7911 deletions

View 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);
}

View 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_ */

View 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;
}

View 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_ */

File diff suppressed because it is too large Load Diff

View 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;
}

View 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_ */

View 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;
}

View 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_ */

View 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);
}

View 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_ */

View 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;
}

View 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_ */

View 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;
}

View 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_ */

View 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;
}

View 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_ */

View 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;
}

View 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_ */

File diff suppressed because it is too large Load Diff

View 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_ */

View 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;
}

View 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_ */

View 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);
}

View 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_ */

File diff suppressed because it is too large Load Diff

View 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_ */

View 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})