| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- /*
- * Copyright (C) 2019 Intel Corporation. All rights reserved.
- * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- */
- #include "aot_emit_variable.h"
- #include "aot_emit_exception.h"
- #include "../aot/aot_runtime.h"
- #define CHECK_LOCAL(idx) \
- do { \
- if (idx >= func_ctx->aot_func->func_type->param_count \
- + func_ctx->aot_func->local_count) { \
- aot_set_last_error("local index out of range"); \
- return false; \
- } \
- } while (0)
- static uint8
- get_local_type(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
- uint32 local_idx)
- {
- AOTFunc *aot_func = func_ctx->aot_func;
- uint32 param_count = aot_func->func_type->param_count;
- uint8 local_type;
- local_type = local_idx < param_count
- ? aot_func->func_type->types[local_idx]
- : aot_func->local_types_wp[local_idx - param_count];
- if (comp_ctx->enable_gc && aot_is_type_gc_reftype(local_type))
- local_type = VALUE_TYPE_GC_REF;
- return local_type;
- }
- bool
- aot_compile_op_get_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
- uint32 local_idx)
- {
- char name[32];
- LLVMValueRef value;
- AOTValue *aot_value_top;
- uint8 local_type;
- CHECK_LOCAL(local_idx);
- local_type = get_local_type(comp_ctx, func_ctx, local_idx);
- snprintf(name, sizeof(name), "%s%d%s", "local", local_idx, "#");
- if (!(value = LLVMBuildLoad2(comp_ctx->builder, TO_LLVM_TYPE(local_type),
- func_ctx->locals[local_idx], name))) {
- aot_set_last_error("llvm build load fail");
- return false;
- }
- PUSH(value, local_type);
- aot_value_top =
- func_ctx->block_stack.block_list_end->value_stack.value_list_end;
- aot_value_top->is_local = true;
- aot_value_top->local_idx = local_idx;
- return true;
- fail:
- return false;
- }
- static bool
- aot_compile_op_set_or_tee_local(AOTCompContext *comp_ctx,
- AOTFuncContext *func_ctx, uint32 local_idx,
- bool is_tee_local)
- {
- LLVMValueRef value;
- uint8 local_type;
- uint32 n;
- CHECK_LOCAL(local_idx);
- local_type = get_local_type(comp_ctx, func_ctx, local_idx);
- POP(value, local_type);
- if (comp_ctx->aot_frame) {
- /* Get the slot index */
- n = func_ctx->aot_func->local_offsets[local_idx];
- bh_assert(comp_ctx->aot_frame->lp[n].type == local_type);
- switch (local_type) {
- case VALUE_TYPE_I32:
- set_local_i32(comp_ctx->aot_frame, n, value);
- break;
- case VALUE_TYPE_I64:
- set_local_i64(comp_ctx->aot_frame, n, value);
- break;
- case VALUE_TYPE_F32:
- set_local_f32(comp_ctx->aot_frame, n, value);
- break;
- case VALUE_TYPE_F64:
- set_local_f64(comp_ctx->aot_frame, n, value);
- break;
- case VALUE_TYPE_V128:
- set_local_v128(comp_ctx->aot_frame, n, value);
- break;
- case VALUE_TYPE_FUNCREF:
- case VALUE_TYPE_EXTERNREF:
- set_local_ref(comp_ctx->aot_frame, n, value, local_type);
- break;
- #if WASM_ENABLE_GC != 0
- case VALUE_TYPE_GC_REF:
- set_local_gc_ref(comp_ctx->aot_frame, n, value, local_type);
- break;
- #endif
- default:
- bh_assert(0);
- break;
- }
- }
- if (!LLVMBuildStore(comp_ctx->builder, value,
- func_ctx->locals[local_idx])) {
- aot_set_last_error("llvm build store fail");
- return false;
- }
- if (is_tee_local) {
- PUSH(value, local_type);
- }
- aot_checked_addr_list_del(func_ctx, local_idx);
- return true;
- fail:
- return false;
- }
- bool
- aot_compile_op_set_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
- uint32 local_idx)
- {
- return aot_compile_op_set_or_tee_local(comp_ctx, func_ctx, local_idx,
- false);
- }
- bool
- aot_compile_op_tee_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
- uint32 local_idx)
- {
- return aot_compile_op_set_or_tee_local(comp_ctx, func_ctx, local_idx, true);
- }
- static bool
- compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
- uint32 global_idx, bool is_set, bool is_aux_stack)
- {
- const AOTCompData *comp_data = comp_ctx->comp_data;
- uint32 import_global_count = comp_data->import_global_count;
- uint32 global_base_offset;
- uint32 global_offset;
- uint8 global_type;
- LLVMValueRef offset, global_ptr, global, res;
- LLVMTypeRef ptr_type = NULL;
- global_base_offset =
- offsetof(AOTModuleInstance, global_table_data.bytes)
- + sizeof(AOTMemoryInstance) * comp_ctx->comp_data->memory_count;
- bh_assert(global_idx < import_global_count + comp_data->global_count);
- if (global_idx < import_global_count) {
- global_offset =
- global_base_offset
- /* Get global data offset according to target info */
- + (comp_ctx->pointer_size == sizeof(uint64)
- ? comp_data->import_globals[global_idx].data_offset_64bit
- : comp_data->import_globals[global_idx].data_offset_32bit);
- global_type = comp_data->import_globals[global_idx].type.val_type;
- }
- else {
- global_offset =
- global_base_offset
- /* Get global data offset according to target info */
- + (comp_ctx->pointer_size == sizeof(uint64)
- ? comp_data->globals[global_idx - import_global_count]
- .data_offset_64bit
- : comp_data->globals[global_idx - import_global_count]
- .data_offset_32bit);
- global_type =
- comp_data->globals[global_idx - import_global_count].type.val_type;
- }
- if (comp_ctx->enable_gc && aot_is_type_gc_reftype(global_type))
- global_type = VALUE_TYPE_GC_REF;
- offset = I32_CONST(global_offset);
- if (!(global_ptr = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
- func_ctx->aot_inst, &offset, 1,
- "global_ptr_tmp"))) {
- aot_set_last_error("llvm build in bounds gep failed.");
- return false;
- }
- switch (global_type) {
- case VALUE_TYPE_I32:
- case VALUE_TYPE_EXTERNREF:
- case VALUE_TYPE_FUNCREF:
- ptr_type = INT32_PTR_TYPE;
- break;
- case VALUE_TYPE_I64:
- ptr_type = INT64_PTR_TYPE;
- break;
- case VALUE_TYPE_F32:
- ptr_type = F32_PTR_TYPE;
- break;
- case VALUE_TYPE_F64:
- ptr_type = F64_PTR_TYPE;
- break;
- case VALUE_TYPE_V128:
- ptr_type = V128_PTR_TYPE;
- break;
- #if WASM_ENABLE_GC != 0
- case VALUE_TYPE_GC_REF:
- ptr_type = GC_REF_PTR_TYPE;
- break;
- #endif
- default:
- bh_assert("unknown type");
- break;
- }
- if (!(global_ptr = LLVMBuildBitCast(comp_ctx->builder, global_ptr, ptr_type,
- "global_ptr"))) {
- aot_set_last_error("llvm build bit cast failed.");
- return false;
- }
- if (!is_set) {
- if (!(global =
- LLVMBuildLoad2(comp_ctx->builder, TO_LLVM_TYPE(global_type),
- global_ptr, "global"))) {
- aot_set_last_error("llvm build load failed.");
- return false;
- }
- /* All globals' data is 4-byte aligned */
- LLVMSetAlignment(global, 4);
- PUSH(global, global_type);
- }
- else {
- POP(global, global_type);
- if (is_aux_stack && comp_ctx->enable_aux_stack_check) {
- LLVMBasicBlockRef block_curr =
- LLVMGetInsertBlock(comp_ctx->builder);
- LLVMBasicBlockRef check_overflow_succ, check_underflow_succ;
- LLVMValueRef cmp, global_i64;
- /* Add basic blocks */
- if (!(check_overflow_succ = LLVMAppendBasicBlockInContext(
- comp_ctx->context, func_ctx->func,
- "check_overflow_succ"))) {
- aot_set_last_error("llvm add basic block failed.");
- return false;
- }
- LLVMMoveBasicBlockAfter(check_overflow_succ, block_curr);
- if (!(check_underflow_succ = LLVMAppendBasicBlockInContext(
- comp_ctx->context, func_ctx->func,
- "check_underflow_succ"))) {
- aot_set_last_error("llvm add basic block failed.");
- return false;
- }
- LLVMMoveBasicBlockAfter(check_underflow_succ, check_overflow_succ);
- if (!(global_i64 = LLVMBuildZExt(comp_ctx->builder, global,
- I64_TYPE, "global_i64"))) {
- aot_set_last_error("llvm build zext failed.");
- return false;
- }
- /* Check aux stack overflow */
- if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntULE, global_i64,
- func_ctx->aux_stack_bound, "cmp"))) {
- aot_set_last_error("llvm build icmp failed.");
- return false;
- }
- if (!aot_emit_exception(comp_ctx, func_ctx, EXCE_AUX_STACK_OVERFLOW,
- true, cmp, check_overflow_succ)) {
- return false;
- }
- /* Check aux stack underflow */
- LLVMPositionBuilderAtEnd(comp_ctx->builder, check_overflow_succ);
- if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGT, global_i64,
- func_ctx->aux_stack_bottom, "cmp"))) {
- aot_set_last_error("llvm build icmp failed.");
- return false;
- }
- if (!aot_emit_exception(comp_ctx, func_ctx,
- EXCE_AUX_STACK_UNDERFLOW, true, cmp,
- check_underflow_succ)) {
- return false;
- }
- LLVMPositionBuilderAtEnd(comp_ctx->builder, check_underflow_succ);
- }
- if (!(res = LLVMBuildStore(comp_ctx->builder, global, global_ptr))) {
- aot_set_last_error("llvm build store failed.");
- return false;
- }
- /* All globals' data is 4-byte aligned */
- LLVMSetAlignment(res, 4);
- }
- return true;
- fail:
- return false;
- }
- bool
- aot_compile_op_get_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
- uint32 global_idx)
- {
- return compile_global(comp_ctx, func_ctx, global_idx, false, false);
- }
- bool
- aot_compile_op_set_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
- uint32 global_idx, bool is_aux_stack)
- {
- return compile_global(comp_ctx, func_ctx, global_idx, true, is_aux_stack);
- }
|