Implement XIP feature and enable ARC target support (#694)

Implement XIP (Execution In Place) feature for AOT mode to enable running the AOT code inside AOT file directly, without memory mapping the executable memory for AOT code and applying relocations for text section. Developer can use wamrc with "--enable-indirect-mode --disable-llvm-intrinsics" flags to generate the AOT file and run iwasm with "--xip" flag. Known issues: there might still be some relocations in the text section which access the ".rodata" like sections.

And also enable ARC target support for both interpreter mode and AOT mode.

Signed-off-by: Wenyong Huang <wenyong.huang@intel.com>
This commit is contained in:
Wenyong Huang
2021-08-12 17:44:39 +08:00
committed by GitHub
parent 8fd89bd415
commit db695fada4
44 changed files with 2613 additions and 263 deletions

View File

@ -7,7 +7,7 @@
#include "aot_compiler.h"
#include "aot_emit_exception.h"
#include "../aot/aot_runtime.h"
#include "../aot/aot_intrinsic.h"
LLVMTypeRef
wasm_type_to_llvm_type(AOTLLVMTypes *llvm_types, uint8 wasm_type)
@ -38,7 +38,7 @@ wasm_type_to_llvm_type(AOTLLVMTypes *llvm_types, uint8 wasm_type)
*/
static LLVMValueRef
aot_add_llvm_func(AOTCompContext *comp_ctx, AOTFuncType *aot_func_type,
uint32 func_index)
uint32 func_index, LLVMTypeRef *p_func_type)
{
LLVMValueRef func = NULL;
LLVMTypeRef *param_types, ret_type, func_type;
@ -107,6 +107,9 @@ aot_add_llvm_func(AOTCompContext *comp_ctx, AOTFuncType *aot_func_type,
LLVMSetValueName(local_value, "");
}
if (p_func_type)
*p_func_type = func_type;
fail:
wasm_runtime_free(param_types);
return func;
@ -604,6 +607,7 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx,
LLVMValueRef stack_bound_offset = I32_FOUR, stack_bound_addr;
LLVMValueRef aux_stack_bound_offset = I32_SIX, aux_stack_bound_addr;
LLVMValueRef aux_stack_bottom_offset = I32_SEVEN, aux_stack_bottom_addr;
LLVMValueRef native_symbol_offset = I32_EIGHT, native_symbol_addr;
char local_name[32];
uint64 size;
uint32 i, j = 0;
@ -621,7 +625,8 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx,
func_ctx->aot_func = func;
/* Add LLVM function */
if (!(func_ctx->func = aot_add_llvm_func(comp_ctx, aot_func_type, func_index)))
if (!(func_ctx->func = aot_add_llvm_func(comp_ctx, aot_func_type,
func_index, &func_ctx->func_type)))
goto fail;
/* Create function's first AOTBlock */
@ -741,6 +746,27 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx,
goto fail;
}
if (!(native_symbol_addr =
LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->exec_env,
&native_symbol_offset, 1, "native_symbol_addr"))) {
aot_set_last_error("llvm build in bounds gep failed");
goto fail;
}
if (!(func_ctx->native_symbol =
LLVMBuildLoad(comp_ctx->builder, native_symbol_addr,
"native_symbol_tmp"))) {
aot_set_last_error("llvm build bit cast failed");
goto fail;
}
if (!(func_ctx->native_symbol =
LLVMBuildBitCast(comp_ctx->builder, func_ctx->native_symbol,
comp_ctx->exec_env_type, "native_symbol"))) {
aot_set_last_error("llvm build bit cast failed");
goto fail;
}
for (i = 0; i < aot_func_type->param_count; i++, j++) {
snprintf(local_name, sizeof(local_name), "l%d", i);
func_ctx->locals[i] =
@ -814,7 +840,7 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx,
}
else {
if (!(func_ctx->last_alloca = LLVMBuildAlloca(comp_ctx->builder, INT8_TYPE,
"stack_ptr"))) {
"stack_ptr"))) {
aot_set_last_error("llvm build alloca failed.");
goto fail;
}
@ -1089,7 +1115,8 @@ static ArchItem valid_archs[] = {
{ "thumbv8m.main", true },
{ "thumbv8.1m.main", true },
{ "riscv32", true},
{ "riscv64", true}
{ "riscv64", true},
{ "arc", true }
};
static const char *valid_abis[] = {
@ -1230,6 +1257,10 @@ aot_create_comp_context(AOTCompData *comp_data,
goto fail;
}
if (BH_LIST_ERROR == bh_list_init(&comp_ctx->native_symbols)) {
goto fail;
}
if (option->enable_bulk_memory)
comp_ctx->enable_bulk_memory = true;
@ -1248,6 +1279,12 @@ aot_create_comp_context(AOTCompData *comp_data,
if (option->enable_aux_stack_check)
comp_ctx->enable_aux_stack_check = true;
if (option->is_indirect_mode)
comp_ctx->is_indirect_mode = true;
if (option->disable_llvm_intrinsics)
comp_ctx->disable_llvm_intrinsics = true;
if (option->is_jit_mode) {
char *triple_jit = NULL;
@ -1496,7 +1533,12 @@ aot_create_comp_context(AOTCompData *comp_data,
goto fail;
}
if (!LLVMTargetHasAsmBackend(target)) {
/* Report error if target isn't arc and hasn't asm backend.
For arc target, as it cannot emit to memory buffer of elf file currently,
we let it emit to assembly file instead, and then call arc-gcc to compile
asm file to elf file, and read elf file to memory buffer. */
if (strncmp(comp_ctx->target_arch, "arc", 3)
&& !LLVMTargetHasAsmBackend(target)) {
snprintf(buf, sizeof(buf),
"no asm backend for this target (%s).", LLVMGetTargetName(target));
aot_set_last_error(buf);
@ -1631,6 +1673,18 @@ aot_create_comp_context(AOTCompData *comp_data,
aot_create_func_contexts(comp_data, comp_ctx)))
goto fail;
if (cpu) {
int len = strlen(cpu) + 1;
if (!(comp_ctx->target_cpu = wasm_runtime_malloc(len))) {
aot_set_last_error("allocate memory failed");
goto fail;
}
bh_memcpy_s(comp_ctx->target_cpu, len, cpu, len);
}
if (comp_ctx->disable_llvm_intrinsics)
aot_intrinsic_fill_capability_flags(comp_ctx);
ret = comp_ctx;
fail:
@ -1676,9 +1730,65 @@ aot_destroy_comp_context(AOTCompContext *comp_ctx)
aot_destroy_func_contexts(comp_ctx->func_ctxes,
comp_ctx->func_ctx_count);
if (bh_list_length(&comp_ctx->native_symbols) > 0) {
AOTNativeSymbol *sym = bh_list_first_elem(&comp_ctx->native_symbols);
while (sym) {
AOTNativeSymbol *t = bh_list_elem_next(sym);
bh_list_remove(&comp_ctx->native_symbols, sym);
wasm_runtime_free(sym);
sym = t;
}
}
if (comp_ctx->target_cpu) {
wasm_runtime_free(comp_ctx->target_cpu);
}
wasm_runtime_free(comp_ctx);
}
int32
aot_get_native_symbol_index(AOTCompContext *comp_ctx, const char *symbol)
{
int32 idx = -1;
AOTNativeSymbol *sym = NULL;
sym = bh_list_first_elem(&comp_ctx->native_symbols);
/* Lookup an existing symobl record */
while (sym) {
if (strcmp(sym->symbol, symbol) == 0) {
idx = sym->index;
break;
}
sym = bh_list_elem_next(sym);
}
/* Given symbol is not exist in list, then we alloc a new index for it */
if (idx < 0) {
sym = wasm_runtime_malloc(sizeof(AOTNativeSymbol));
if (!sym) {
aot_set_last_error("alloc native symbol failed.");
return idx;
}
idx = bh_list_length(&comp_ctx->native_symbols);
sym->symbol = symbol;
sym->index = idx;
if (BH_LIST_ERROR == bh_list_insert(&comp_ctx->native_symbols, sym)) {
wasm_runtime_free(sym);
aot_set_last_error("alloc index for native symbol failed.");
return -1;
}
}
return idx;
}
void
aot_value_stack_push(AOTValueStack *stack, AOTValue *value)
{
@ -1901,6 +2011,7 @@ aot_build_zero_function_ret(AOTCompContext *comp_ctx,
static LLVMValueRef
__call_llvm_intrinsic(const AOTCompContext *comp_ctx,
const AOTFuncContext *func_ctx,
const char *name,
LLVMTypeRef ret_type,
LLVMTypeRef *param_types,
@ -1909,25 +2020,67 @@ __call_llvm_intrinsic(const AOTCompContext *comp_ctx,
{
LLVMValueRef func, ret;
LLVMTypeRef func_type;
const char *symname;
int32 func_idx;
/* Declare llvm intrinsic function if necessary */
if (!(func = LLVMGetNamedFunction(comp_ctx->module, name))) {
if (!(func_type = LLVMFunctionType(ret_type, param_types,
(uint32)param_count, false))) {
aot_set_last_error("create LLVM function type failed.");
if (comp_ctx->disable_llvm_intrinsics
&& (aot_intrinsic_check_capability(comp_ctx, name) == false)) {
if (func_ctx == NULL) {
aot_set_last_error_v("invalid func_ctx for intrinsic: %s", name);
return NULL;
}
if (!(func = LLVMAddFunction(comp_ctx->module, name, func_type))) {
aot_set_last_error("add LLVM function failed.");
if (!(func_type = LLVMFunctionType(ret_type, param_types,
(uint32)param_count, false))) {
aot_set_last_error("create LLVM intrinsic function type failed.");
return NULL;
}
if (!(func_type = LLVMPointerType(func_type, 0))) {
aot_set_last_error(
"create LLVM intrinsic function pointer type failed.");
return NULL;
}
if (!(symname = aot_intrinsic_get_symbol(name))) {
aot_set_last_error_v("runtime intrinsic not implemented: %s\n",
name);
return NULL;
}
func_idx =
aot_get_native_symbol_index((AOTCompContext *)comp_ctx, symname);
if (func_idx < 0) {
aot_set_last_error_v("get runtime intrinsc index failed: %s\n",
name);
return NULL;
}
if (!(func = aot_get_func_from_table(comp_ctx, func_ctx->native_symbol,
func_type, func_idx))) {
aot_set_last_error_v("get runtime intrinsc failed: %s\n", name);
return NULL;
}
}
else {
/* Declare llvm intrinsic function if necessary */
if (!(func = LLVMGetNamedFunction(comp_ctx->module, name))) {
if (!(func_type = LLVMFunctionType(ret_type, param_types,
(uint32)param_count, false))) {
aot_set_last_error("create LLVM intrinsic function type failed.");
return NULL;
}
if (!(func = LLVMAddFunction(comp_ctx->module, name, func_type))) {
aot_set_last_error("add LLVM intrinsic function failed.");
return NULL;
}
}
}
/* Call the LLVM intrinsic function */
if (!(ret = LLVMBuildCall(comp_ctx->builder, func, param_values,
(uint32)param_count, "call"))) {
aot_set_last_error("llvm build call failed.");
aot_set_last_error("llvm build intrinsic call failed.");
return NULL;
}
@ -1936,6 +2089,7 @@ __call_llvm_intrinsic(const AOTCompContext *comp_ctx,
LLVMValueRef
aot_call_llvm_intrinsic(const AOTCompContext *comp_ctx,
const AOTFuncContext *func_ctx,
const char *name,
LLVMTypeRef ret_type,
LLVMTypeRef *param_types,
@ -1961,7 +2115,7 @@ aot_call_llvm_intrinsic(const AOTCompContext *comp_ctx,
param_values[i++] = va_arg(argptr, LLVMValueRef);
va_end(argptr);
ret = __call_llvm_intrinsic(comp_ctx, name, ret_type, param_types,
ret = __call_llvm_intrinsic(comp_ctx, func_ctx, name, ret_type, param_types,
param_count, param_values);
wasm_runtime_free(param_values);
@ -1971,6 +2125,7 @@ aot_call_llvm_intrinsic(const AOTCompContext *comp_ctx,
LLVMValueRef
aot_call_llvm_intrinsic_v(const AOTCompContext *comp_ctx,
const AOTFuncContext *func_ctx,
const char *name,
LLVMTypeRef ret_type,
LLVMTypeRef *param_types,
@ -1993,10 +2148,46 @@ aot_call_llvm_intrinsic_v(const AOTCompContext *comp_ctx,
while (i < param_count)
param_values[i++] = va_arg(param_value_list, LLVMValueRef);
ret = __call_llvm_intrinsic(comp_ctx, name, ret_type, param_types,
ret = __call_llvm_intrinsic(comp_ctx, func_ctx, name, ret_type, param_types,
param_count, param_values);
wasm_runtime_free(param_values);
return ret;
}
LLVMValueRef
aot_get_func_from_table(const AOTCompContext *comp_ctx, LLVMValueRef base,
LLVMTypeRef func_type, int32 index)
{
LLVMValueRef func;
LLVMValueRef func_addr;
if (!(func_addr = I32_CONST(index))) {
aot_set_last_error("construct function index failed.");
goto fail;
}
if (!(func_addr = LLVMBuildInBoundsGEP(comp_ctx->builder, base, &func_addr,
1, "func_addr"))) {
aot_set_last_error("get function addr by index failed.");
goto fail;
}
func = LLVMBuildLoad(comp_ctx->builder, func_addr, "func_tmp");
if (func == NULL) {
aot_set_last_error("get function pointer failed.");
goto fail;
}
if (!(func = LLVMBuildBitCast(comp_ctx->builder, func, func_type,
"func"))) {
aot_set_last_error("cast function fialed.");
goto fail;
}
return func;
fail:
return NULL;
}