From db695fada42e6eed7cc9a94af7a48b4f1369009e Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 12 Aug 2021 17:44:39 +0800 Subject: [PATCH] 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 --- build-scripts/config_common.cmake | 2 + .../app-native-shared/restful_utils.c | 211 ++++-- core/app-mgr/app-manager/module_wasm_app.c | 6 +- core/app-mgr/app-manager/module_wasm_app.h | 13 +- core/config.h | 7 +- core/iwasm/aot/aot_intrinsic.c | 407 ++++++++++++ core/iwasm/aot/aot_intrinsic.h | 180 +++++ core/iwasm/aot/aot_loader.c | 182 ++++- core/iwasm/aot/aot_reloc.h | 38 +- core/iwasm/aot/aot_runtime.c | 4 +- core/iwasm/aot/aot_runtime.h | 22 +- core/iwasm/aot/arch/aot_reloc_arc.c | 237 +++++++ core/iwasm/aot/iwasm_aot.cmake | 2 + core/iwasm/common/arch/invokeNative_arc.s | 69 ++ core/iwasm/common/iwasm_common.cmake | 2 + core/iwasm/common/wasm_exec_env.c | 12 + core/iwasm/common/wasm_runtime_common.c | 75 ++- core/iwasm/compilation/aot.h | 6 + core/iwasm/compilation/aot_compiler.c | 13 +- core/iwasm/compilation/aot_emit_aot_file.c | 137 +++- core/iwasm/compilation/aot_emit_exception.c | 18 + core/iwasm/compilation/aot_emit_function.c | 53 +- core/iwasm/compilation/aot_emit_memory.c | 27 +- core/iwasm/compilation/aot_emit_numberic.c | 58 +- core/iwasm/compilation/aot_llvm.c | 223 ++++++- core/iwasm/compilation/aot_llvm.h | 27 +- .../compilation/simd/simd_access_lanes.c | 2 +- .../compilation/simd/simd_bitmask_extracts.c | 2 +- .../compilation/simd/simd_bool_reductions.c | 4 +- .../iwasm/compilation/simd/simd_conversions.c | 2 +- .../compilation/simd/simd_floating_point.c | 2 +- .../compilation/simd/simd_sat_int_arith.c | 2 +- core/iwasm/include/aot_export.h | 4 +- core/shared/platform/common/math/math.c | 625 ++++++++++++++++-- .../platform/common/posix/posix_thread.c | 2 +- .../platform/zephyr/platform_internal.h | 4 + core/shared/platform/zephyr/zephyr_platform.c | 5 + product-mini/platforms/nuttx/wamr.mk | 52 +- product-mini/platforms/posix/main.c | 31 +- .../platforms/zephyr/simple/build_and_run.sh | 11 +- .../platforms/zephyr/simple/prj_qemu_arc.conf | 6 + .../platforms/zephyr/simple/src/main.c | 36 +- wamr-compiler/build_llvm_arc.sh | 47 ++ wamr-compiler/main.c | 8 + 44 files changed, 2613 insertions(+), 263 deletions(-) create mode 100644 core/iwasm/aot/aot_intrinsic.c create mode 100644 core/iwasm/aot/aot_intrinsic.h create mode 100644 core/iwasm/aot/arch/aot_reloc_arc.c create mode 100644 core/iwasm/common/arch/invokeNative_arc.s create mode 100644 product-mini/platforms/zephyr/simple/prj_qemu_arc.conf create mode 100755 wamr-compiler/build_llvm_arc.sh diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 36fb7f9cd..e08027137 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -42,6 +42,8 @@ elseif (WAMR_BUILD_TARGET STREQUAL "RISCV32" OR WAMR_BUILD_TARGET STREQUAL "RISC add_definitions(-DBUILD_TARGET_RISCV32_ILP32D) elseif (WAMR_BUILD_TARGET STREQUAL "RISCV32_ILP32") add_definitions(-DBUILD_TARGET_RISCV32_ILP32) +elseif (WAMR_BUILD_TARGET STREQUAL "ARC") + add_definitions(-DBUILD_TARGET_ARC) else () message (FATAL_ERROR "-- WAMR build target isn't set") endif () diff --git a/core/app-framework/app-native-shared/restful_utils.c b/core/app-framework/app-native-shared/restful_utils.c index 5268b22a7..74bd59a52 100644 --- a/core/app-framework/app-native-shared/restful_utils.c +++ b/core/app-framework/app-native-shared/restful_utils.c @@ -32,29 +32,44 @@ #define REQUES_PACKET_VER 1 #define REQUEST_PACKET_FIX_PART_LEN 18 #define REQUEST_PACKET_URL_OFFSET REQUEST_PACKET_FIX_PART_LEN -#define REQUEST_PACKET_URL_LEN *((uint16*)( (char*) buffer + 12))) //!!! to ensure little endian -#define REQUEST_PACKET_PAYLOAD_LEN *((uint32*)( (char*) buffer + 14))) //!!! to ensure little endian +#define REQUEST_PACKET_URL_LEN *((uint16*)((char*) buffer + 12)) /* to ensure little endian */ +#define REQUEST_PACKET_PAYLOAD_LEN *((uint32*)((char*) buffer + 14)) /* to ensure little endian */ #define REQUEST_PACKET_URL(buffer) ((char*) buffer + REQUEST_PACKET_URL_OFFSET) #define REQUEST_PACKET_PAYLOAD(buffer) ((char*) buffer + REQUEST_PACKET_URL_OFFSET + REQUEST_PACKET_URL_LEN(buffer)) #define RESPONSE_PACKET_FIX_PART_LEN 16 -char * pack_request(request_t *request, int * size) +char * +pack_request(request_t *request, int *size) { int url_len = strlen(request->url) + 1; int len = REQUEST_PACKET_FIX_PART_LEN + url_len + request->payload_len; - char * packet = (char*) WA_MALLOC(len); - if (packet == NULL) + uint16 u16; + uint32 u32; + char *packet; + + if ((packet = (char*) WA_MALLOC(len)) == NULL) return NULL; - // TODO: ensure little endian for words and dwords + /* TODO: ensure little endian for words and dwords */ *packet = REQUES_PACKET_VER; *((uint8*) (packet + 1)) = request->action; - *((uint16*) (packet + 2)) = htons(request->fmt); - *((uint32*) (packet + 4)) = htonl(request->mid); - *((uint32*) (packet + 8)) = htonl(request->sender); - *((uint16*) (packet + 12)) = htons(url_len); - *((uint32*) (packet + 14)) = htonl(request->payload_len); + + u16 = htons(request->fmt); + memcpy(packet + 2, &u16, 2); + + u32 = htonl(request->mid); + memcpy(packet + 4, &u32, 4); + + u32 = htonl(request->sender); + memcpy(packet + 8, &u32, 4); + + u16 = htons(url_len); + memcpy(packet + 12, &u16, 2); + + u32 = htonl(request->payload_len); + memcpy(packet + 14, &u32, 4); + strcpy(packet + REQUEST_PACKET_URL_OFFSET, request->url); memcpy(packet + REQUEST_PACKET_URL_OFFSET + url_len, request->payload, request->payload_len); @@ -63,35 +78,53 @@ char * pack_request(request_t *request, int * size) return packet; } -void free_req_resp_packet(char * packet) +void +free_req_resp_packet(char *packet) { WA_FREE(packet); } -request_t * unpack_request(char * packet, int size, request_t * request) +request_t * +unpack_request(char *packet, int size, request_t *request) { + uint16 url_len, u16; + uint32 payload_len, u32; + if (*packet != REQUES_PACKET_VER) { return NULL; } if (size < REQUEST_PACKET_FIX_PART_LEN) { return NULL; } - uint16 url_len = ntohs(*((uint16*) (packet + 12))); - uint32 payload_len = ntohl(*((uint32*) (packet + 14))); - if (size != ( REQUEST_PACKET_FIX_PART_LEN + url_len + payload_len)) { + memcpy(&u16, packet + 12, 2); + url_len = ntohs(u16); + + memcpy(&u32, packet + 14, 4); + payload_len = ntohl(u32); + + if (size != (REQUEST_PACKET_FIX_PART_LEN + url_len + payload_len)) { return NULL; } + if (*(packet + REQUEST_PACKET_FIX_PART_LEN + url_len - 1) != 0) { return NULL; } request->action = *((uint8*) (packet + 1)); - request->fmt = ntohs(*((uint16*) (packet + 2))); - request->mid = ntohl(*((uint32*) (packet + 4))); - request->sender = ntohl(*((uint32*) (packet + 8))); + + memcpy(&u16, packet + 2, 2); + request->fmt = ntohs(u16); + + memcpy(&u32, packet + 4, 4); + request->mid = ntohl(u32); + + memcpy(&u32, packet + 8, 4); + request->sender = ntohl(u32); + request->payload_len = payload_len; request->url = REQUEST_PACKET_URL(packet); + if (payload_len > 0) request->payload = packet + REQUEST_PACKET_URL_OFFSET + url_len; else @@ -100,20 +133,33 @@ request_t * unpack_request(char * packet, int size, request_t * request) return request; } -char * pack_response(response_t *response, int * size) +char * +pack_response(response_t *response, int *size) { int len = RESPONSE_PACKET_FIX_PART_LEN + response->payload_len; - char * packet = (char*) WA_MALLOC(len); - if (packet == NULL) + uint16 u16; + uint32 u32; + char *packet; + + if ((packet = (char*) WA_MALLOC(len)) == NULL) return NULL; - // TODO: ensure little endian for words and dwords + /* TODO: ensure little endian for words and dwords */ *packet = REQUES_PACKET_VER; *((uint8*) (packet + 1)) = response->status; - *((uint16*) (packet + 2)) = htons(response->fmt); - *((uint32*) (packet + 4)) = htonl(response->mid); - *((uint32*) (packet + 8)) = htonl(response->reciever); - *((uint32*) (packet + 12)) = htonl(response->payload_len); + + u16 = htons(response->fmt); + memcpy(packet + 2, &u16, 2); + + u32 = htonl(response->mid); + memcpy(packet + 4, &u32, 4); + + u32 = htonl(response->reciever); + memcpy(packet + 8, &u32, 4); + + u32 = htonl(response->payload_len); + memcpy(packet + 12, &u32, 4); + memcpy(packet + RESPONSE_PACKET_FIX_PART_LEN, response->payload, response->payload_len); @@ -121,20 +167,34 @@ char * pack_response(response_t *response, int * size) return packet; } -response_t * unpack_response(char * packet, int size, response_t * response) +response_t * +unpack_response(char *packet, int size, response_t *response) { + uint16 u16; + uint32 payload_len, u32; + if (*packet != REQUES_PACKET_VER) return NULL; + if (size < RESPONSE_PACKET_FIX_PART_LEN) return NULL; - uint32 payload_len = ntohl(*((uint32*) (packet + 12))); - if (size != ( RESPONSE_PACKET_FIX_PART_LEN + payload_len)) + + memcpy(&u32, packet + 12, 4); + payload_len = ntohl(u32); + if (size != (RESPONSE_PACKET_FIX_PART_LEN + payload_len)) return NULL; response->status = *((uint8*) (packet + 1)); - response->fmt = ntohs(*((uint16*) (packet + 2))); - response->mid = ntohl(*((uint32*) (packet + 4))); - response->reciever = ntohl(*((uint32*) (packet + 8))); + + memcpy(&u16, packet + 2, 2); + response->fmt = ntohs(u16); + + memcpy(&u32, packet + 4, 4); + response->mid = ntohl(u32); + + memcpy(&u32, packet + 8, 4); + response->reciever = ntohl(u32); + response->payload_len = payload_len; if (payload_len > 0) response->payload = packet + RESPONSE_PACKET_FIX_PART_LEN; @@ -144,7 +204,8 @@ response_t * unpack_response(char * packet, int size, response_t * response) return response; } -request_t *clone_request(request_t *request) +request_t * +clone_request(request_t *request) { /* deep clone */ request_t *req = (request_t *) WA_MALLOC(sizeof(request_t)); @@ -164,12 +225,14 @@ request_t *clone_request(request_t *request) req->payload_len = request->payload_len; if (request->payload_len) { - req->payload = (char *) WA_MALLOC(request->payload_len); + req->payload = (char *)WA_MALLOC(request->payload_len); if (!req->payload) goto fail; memcpy(req->payload, request->payload, request->payload_len); - } else { - // when payload_len is 0, the payload may be used for carrying some handle or integer + } + else { + /* when payload_len is 0, the payload may be used for + carrying some handle or integer */ req->payload = request->payload; } @@ -180,7 +243,8 @@ fail: return NULL; } -void request_cleaner(request_t *request) +void +request_cleaner(request_t *request) { if (request->url != NULL) WA_FREE(request->url); @@ -190,7 +254,8 @@ void request_cleaner(request_t *request) WA_FREE(request); } -void response_cleaner(response_t * response) +void +response_cleaner(response_t *response) { if (response->payload != NULL && response->payload_len > 0) WA_FREE(response->payload); @@ -198,9 +263,11 @@ void response_cleaner(response_t * response) WA_FREE(response); } -response_t * clone_response(response_t * response) +response_t * +clone_response(response_t *response) { - response_t *clone = (response_t *) WA_MALLOC(sizeof(response_t)); + response_t *clone = (response_t *)WA_MALLOC(sizeof(response_t)); + if (clone == NULL) return NULL; @@ -215,8 +282,10 @@ response_t * clone_response(response_t * response) if (!clone->payload) goto fail; memcpy(clone->payload, response->payload, response->payload_len); - } else { - // when payload_len is 0, the payload may be used for carrying some handle or integer + } + else { + /* when payload_len is 0, the payload may be used for + carrying some handle or integer */ clone->payload = response->payload; } return clone; @@ -226,8 +295,9 @@ fail: return NULL; } -response_t * set_response(response_t * response, int status, int fmt, - const char *payload, int payload_len) +response_t * +set_response(response_t *response, int status, int fmt, + const char *payload, int payload_len) { response->payload = (void *)payload; response->payload_len = payload_len; @@ -236,8 +306,9 @@ response_t * set_response(response_t * response, int status, int fmt, return response; } -response_t * make_response_for_request(request_t * request, - response_t * response) +response_t * +make_response_for_request(request_t *request, + response_t *response) { response->mid = request->mid; response->reciever = request->sender; @@ -245,10 +316,12 @@ response_t * make_response_for_request(request_t * request, return response; } -request_t * init_request(request_t * request, char *url, int action, int fmt, - void *payload, int payload_len) +static unsigned int mid = 0; + +request_t * +init_request(request_t *request, char *url, int action, int fmt, + void *payload, int payload_len) { - static unsigned int mid = 0; request->url = url; request->action = action; request->fmt = fmt; @@ -269,7 +342,8 @@ request_t * init_request(request_t * request, char *url, int action, int fmt, 3. it ensure the leading_str "/abc" can pass "/abc?cde */ -int check_url_start(const char* url, int url_len, const char * leading_str) +int +check_url_start(const char *url, int url_len, const char *leading_str) { int offset = 0; if (*leading_str == '/') @@ -284,28 +358,27 @@ int check_url_start(const char* url, int url_len, const char * leading_str) if (len == 0) return 0; - // ensure leading_str not end with "/" + /* ensure leading_str not end with "/" */ if (leading_str[len - 1] == '/') { len--; if (len == 0) return 0; } - // equal length + /* equal length */ if (url_len == len) { if (memcmp(url, leading_str, url_len) == 0) { return (offset + len); - } else { + } + else { return 0; } } if (url_len < len) return 0; - else if (memcmp(url, leading_str, len) != 0) return 0; - else if (url[len] != '/' && url[len] != '?') return 0; else @@ -318,7 +391,8 @@ int check_url_start(const char* url, int url_len, const char * leading_str) // * sample 3: /abcd*, match any url started with "/abcd" // * sample 4: /abcd/*, exclude "/abcd" -bool match_url(char * pattern, char * matched) +bool +match_url(char *pattern, char *matched) { if (*pattern == '/') pattern++; @@ -352,17 +426,19 @@ bool match_url(char * pattern, char * matched) return false; - } else if (pattern[len - 1] == '*') { + } + else if (pattern[len - 1] == '*') { if (pattern[len - 2] == '/') { if (strncmp(pattern, matched, len - 1) == 0) return true; - else return false; - } else { + } + else { return (strncmp(pattern, matched, len - 1) == 0); } - } else { + } + else { return (strcmp(pattern, matched) == 0); } } @@ -371,10 +447,11 @@ bool match_url(char * pattern, char * matched) * get the value of the key from following format buffer: * key1=value1;key2=value2;key3=value3 */ -char * find_key_value(char * buffer, int buffer_len, char * key, char * value, - int value_len, char delimiter) +char * +find_key_value(char *buffer, int buffer_len, char *key, char *value, + int value_len, char delimiter) { - char * p = buffer; + char *p = buffer; int remaining = buffer_len; int key_len = strlen(key); @@ -387,13 +464,13 @@ char * find_key_value(char * buffer, int buffer_len, char * key, char * value, if (remaining <= key_len) return NULL; - // find the key + /* find the key */ if (0 == strncmp(p, key, key_len) && p[key_len] == '=') { p += (key_len + 1); remaining -= (key_len + 1); char * v = value; memset(value, 0, value_len); - value_len--; // ensure last char is 0 + value_len--; /* ensure last char is 0 */ while (*p != delimiter && remaining > 0 && value_len > 0) { *v++ = *p++; remaining--; @@ -402,7 +479,7 @@ char * find_key_value(char * buffer, int buffer_len, char * key, char * value, return value; } - // goto next key + /* goto next key */ while (*p != delimiter && remaining > 0) { p++; remaining--; diff --git a/core/app-mgr/app-manager/module_wasm_app.c b/core/app-mgr/app-manager/module_wasm_app.c index a3e7a2a76..f7752bd5b 100644 --- a/core/app-mgr/app-manager/module_wasm_app.c +++ b/core/app-mgr/app-manager/module_wasm_app.c @@ -653,7 +653,8 @@ wasm_app_module_install(request_t * msg) AOT_SECTION_TYPE_FUNCTION, AOT_SECTION_TYPE_EXPORT, AOT_SECTION_TYPE_RELOCATION, - AOT_SECTION_TYPE_SIGANATURE + AOT_SECTION_TYPE_SIGANATURE, + AOT_SECTION_TYPE_CUSTOM, }; aot_file = &wasm_app_file->u.aot; @@ -1375,7 +1376,8 @@ wasm_app_module_on_install_request_byte_arrive(uint8 ch, /* Notes: integers are always little endian encoded in AOT file */ if (!is_little_endian()) exchange_uint32(p); - if (cur_section->section_type < AOT_SECTION_TYPE_SIGANATURE) { + if (cur_section->section_type < AOT_SECTION_TYPE_SIGANATURE + || cur_section->section_type == AOT_SECTION_TYPE_CUSTOM) { recv_ctx.phase = Phase_AOT_Section_Size; recv_ctx.size_in_phase = 0; } diff --git a/core/app-mgr/app-manager/module_wasm_app.h b/core/app-mgr/app-manager/module_wasm_app.h index 7a967e220..8965a975f 100644 --- a/core/app-mgr/app-manager/module_wasm_app.h +++ b/core/app-mgr/app-manager/module_wasm_app.h @@ -29,12 +29,13 @@ extern "C" { typedef enum AOTSectionType { AOT_SECTION_TYPE_TARGET_INFO = 0, - AOT_SECTION_TYPE_INIT_DATA, - AOT_SECTION_TYPE_TEXT, - AOT_SECTION_TYPE_FUNCTION, - AOT_SECTION_TYPE_EXPORT, - AOT_SECTION_TYPE_RELOCATION, - AOT_SECTION_TYPE_SIGANATURE + AOT_SECTION_TYPE_INIT_DATA = 1, + AOT_SECTION_TYPE_TEXT = 2, + AOT_SECTION_TYPE_FUNCTION = 3, + AOT_SECTION_TYPE_EXPORT = 4, + AOT_SECTION_TYPE_RELOCATION = 5, + AOT_SECTION_TYPE_SIGANATURE = 6, + AOT_SECTION_TYPE_CUSTOM = 100, } AOTSectionType; enum { diff --git a/core/config.h b/core/config.h index 7f0c01789..6659d62ba 100644 --- a/core/config.h +++ b/core/config.h @@ -19,7 +19,8 @@ && !defined(BUILD_TARGET_RISCV64_LP64D) \ && !defined(BUILD_TARGET_RISCV64_LP64) \ && !defined(BUILD_TARGET_RISCV32_ILP32D) \ - && !defined(BUILD_TARGET_RISCV32_ILP32) + && !defined(BUILD_TARGET_RISCV32_ILP32) \ + && !defined(BUILD_TARGET_ARC) #if defined(__x86_64__) || defined(__x86_64) #define BUILD_TARGET_X86_64 #elif defined(__amd64__) || defined(__amd64) @@ -42,6 +43,8 @@ #define BUILD_TARGET_RISCV64_LP64D #elif defined(__riscv) && (__riscv_xlen == 32) #define BUILD_TARGET_RISCV32_ILP32D +#elif defined(__arc__) +#define BUILD_TARGET_ARC #else #error "Build target isn't set" #endif @@ -237,7 +240,9 @@ #define APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT 1 / 3 /* Default min/max heap size of each app */ +#ifndef APP_HEAP_SIZE_DEFAULT #define APP_HEAP_SIZE_DEFAULT (8 * 1024) +#endif #define APP_HEAP_SIZE_MIN (256) #define APP_HEAP_SIZE_MAX (512 * 1024 * 1024) diff --git a/core/iwasm/aot/aot_intrinsic.c b/core/iwasm/aot/aot_intrinsic.c new file mode 100644 index 000000000..34e6cd7cb --- /dev/null +++ b/core/iwasm/aot/aot_intrinsic.c @@ -0,0 +1,407 @@ +/* + * Copyright (C) 2021 XiaoMi Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "aot_intrinsic.h" + +typedef struct { + const char *llvm_intrinsic; + const char *native_intrinsic; + uint64 flag; +} aot_intrinsic; + +static const aot_intrinsic g_intrinsic_mapping[] = { + { "llvm.experimental.constrained.fadd.f32", "aot_intrinsic_fadd_f32", + AOT_INTRINSIC_FLAG_F32_FADD }, + { "llvm.experimental.constrained.fadd.f64", "aot_intrinsic_fadd_f64", + AOT_INTRINSIC_FLAG_F64_FADD }, + { "llvm.experimental.constrained.fsub.f32", "aot_intrinsic_fsub_f32", + AOT_INTRINSIC_FLAG_F32_FSUB }, + { "llvm.experimental.constrained.fsub.f64", "aot_intrinsic_fsub_f64", + AOT_INTRINSIC_FLAG_F64_FSUB }, + { "llvm.experimental.constrained.fmul.f32", "aot_intrinsic_fmul_f32", + AOT_INTRINSIC_FLAG_F32_FMUL }, + { "llvm.experimental.constrained.fmul.f64", "aot_intrinsic_fmul_f64", + AOT_INTRINSIC_FLAG_F64_FMUL }, + { "llvm.experimental.constrained.fdiv.f32", "aot_intrinsic_fdiv_f32", + AOT_INTRINSIC_FLAG_F32_FDIV }, + { "llvm.experimental.constrained.fdiv.f64", "aot_intrinsic_fdiv_f64", + AOT_INTRINSIC_FLAG_F64_FDIV }, + { "llvm.fabs.f32", "aot_intrinsic_fabs_f32", AOT_INTRINSIC_FLAG_F32_FABS }, + { "llvm.fabs.f64", "aot_intrinsic_fabs_f64", AOT_INTRINSIC_FLAG_F64_FABS }, + { "llvm.ceil.f32", "aot_intrinsic_ceil_f32", AOT_INTRINSIC_FLAG_F32_CEIL }, + { "llvm.ceil.f64", "aot_intrinsic_ceil_f64", AOT_INTRINSIC_FLAG_F64_CEIL }, + { "llvm.floor.f32", "aot_intrinsic_floor_f32", + AOT_INTRINSIC_FLAG_F32_FLOOR }, + { "llvm.floor.f64", "aot_intrinsic_floor_f64", + AOT_INTRINSIC_FLAG_F64_FLOOR }, + { "llvm.trunc.f32", "aot_intrinsic_trunc_f32", + AOT_INTRINSIC_FLAG_F32_TRUNC }, + { "llvm.trunc.f64", "aot_intrinsic_trunc_f64", + AOT_INTRINSIC_FLAG_F64_TRUNC }, + { "llvm.rint.f32", "aot_intrinsic_rint_f32", AOT_INTRINSIC_FLAG_F32_RINT }, + { "llvm.rint.f64", "aot_intrinsic_rint_f64", AOT_INTRINSIC_FLAG_F64_RINT }, + { "llvm.sqrt.f32", "aot_intrinsic_sqrt_f32", AOT_INTRINSIC_FLAG_F32_SQRT }, + { "llvm.sqrt.f64", "aot_intrinsic_sqrt_f64", AOT_INTRINSIC_FLAG_F64_SQRT }, + { "llvm.copysign.f32", "aot_intrinsic_copysign_f32", + AOT_INTRINSIC_FLAG_F32_COPYSIGN }, + { "llvm.copysign.f64", "aot_intrinsic_copysign_f64", + AOT_INTRINSIC_FLAG_F64_COPYSIGN }, + { "llvm.minnum.f32", "aot_intrinsic_fmin_f32", AOT_INTRINSIC_FLAG_F32_MIN }, + { "llvm.minnum.f64", "aot_intrinsic_fmin_f64", AOT_INTRINSIC_FLAG_F64_MIN }, + { "llvm.maxnum.f32", "aot_intrinsic_fmax_f32", AOT_INTRINSIC_FLAG_F32_MAX }, + { "llvm.maxnum.f64", "aot_intrinsic_fmax_f64", AOT_INTRINSIC_FLAG_F64_MAX }, + { "llvm.ctlz.i32", "aot_intrinsic_clz_i32", AOT_INTRINSIC_FLAG_I32_CLZ }, + { "llvm.ctlz.i64", "aot_intrinsic_clz_i64", AOT_INTRINSIC_FLAG_I64_CLZ }, + { "llvm.cttz.i32", "aot_intrinsic_ctz_i32", AOT_INTRINSIC_FLAG_I32_CTZ }, + { "llvm.cttz.i64", "aot_intrinsic_ctz_i64", AOT_INTRINSIC_FLAG_I64_CTZ }, + { "llvm.ctpop.i32", "aot_intrinsic_popcnt_i32", AOT_INTRINSIC_FLAG_I32_POPCNT }, + { "llvm.ctpop.i64", "aot_intrinsic_popcnt_i64", AOT_INTRINSIC_FLAG_I64_POPCNT }, +}; + +static const uint32 g_intrinsic_count = + sizeof(g_intrinsic_mapping) / sizeof(aot_intrinsic); + +float32 +aot_intrinsic_fadd_f32(float32 a, float32 b) +{ + return a + b; +} + +float64 +aot_intrinsic_fadd_f64(float64 a, float64 b) +{ + return a + b; +} + +float32 +aot_intrinsic_fsub_f32(float32 a, float32 b) +{ + return a - b; +} + +float64 +aot_intrinsic_fsub_f64(float64 a, float64 b) +{ + return a - b; +} + +float32 +aot_intrinsic_fmul_f32(float32 a, float32 b) +{ + return a * b; +} + +float64 +aot_intrinsic_fmul_f64(float64 a, float64 b) +{ + return a * b; +} + +float32 +aot_intrinsic_fdiv_f32(float32 a, float32 b) +{ + return a / b; +} + +float64 +aot_intrinsic_fdiv_f64(float64 a, float64 b) +{ + return a / b; +} + +float32 +aot_intrinsic_fabs_f32(float32 a) +{ + return (float32)fabs(a); +} + +float64 +aot_intrinsic_fabs_f64(float64 a) +{ + return fabs(a); +} + +float32 +aot_intrinsic_ceil_f32(float32 a) +{ + return (float32)ceilf(a); +} + +float64 +aot_intrinsic_ceil_f64(float64 a) +{ + return ceil(a); +} + +float32 +aot_intrinsic_floor_f32(float32 a) +{ + return (float32)floorf(a); +} + +float64 +aot_intrinsic_floor_f64(float64 a) +{ + return floor(a); +} + +float32 +aot_intrinsic_trunc_f32(float32 a) +{ + return (float32)trunc(a); +} + +float64 +aot_intrinsic_trunc_f64(float64 a) +{ + return trunc(a); +} + +float32 +aot_intrinsic_rint_f32(float32 a) +{ + return (float32)rint(a); +} + +float64 +aot_intrinsic_rint_f64(float64 a) +{ + return rint(a); +} + +float32 +aot_intrinsic_sqrt_f32(float32 a) +{ + return (float32)sqrt(a); +} + +float64 +aot_intrinsic_sqrt_f64(float64 a) +{ + return sqrt(a); +} + +float32 +aot_intrinsic_copysign_f32(float32 a, float32 b) +{ + return signbit(b) ? (float32)-fabs(a) : (float32)fabs(a); +} + +float64 +aot_intrinsic_copysign_f64(float64 a, float64 b) +{ + return signbit(b) ? -fabs(a) : fabs(a); +} + +float32 +aot_intrinsic_fmin_f32(float32 a, float32 b) +{ + if (isnan(a)) + return a; + else if (isnan(b)) + return b; + else + return (float32)fmin(a, b); +} + +float64 +aot_intrinsic_fmin_f64(float64 a, float64 b) +{ + float64 c = fmin(a, b); + if (c==0 && a==b) + return signbit(a) ? a : b; + return c; +} + +float32 +aot_intrinsic_fmax_f32(float32 a, float32 b) +{ + if (isnan(a)) + return a; + else if (isnan(b)) + return b; + else + return (float32)fmax(a, b); +} + +float64 +aot_intrinsic_fmax_f64(float64 a, float64 b) +{ + float64 c = fmax(a, b); + if (c==0 && a==b) + return signbit(a) ? b : a; + return c; +} + +uint32 +aot_intrinsic_clz_i32(uint32 type) +{ + uint32 num = 0; + if (type == 0) + return 32; + while (!(type & 0x80000000)) { + num++; + type <<= 1; + } + return num; +} + +uint32 +aot_intrinsic_clz_i64(uint64 type) +{ + uint32 num = 0; + if (type == 0) + return 64; + while (!(type & 0x8000000000000000LL)) { + num++; + type <<= 1; + } + return num; +} + +uint32 +aot_intrinsic_ctz_i32(uint32 type) +{ + uint32 num = 0; + if (type == 0) + return 32; + while (!(type & 1)) { + num++; + type >>= 1; + } + return num; +} + +uint32 +aot_intrinsic_ctz_i64(uint64 type) +{ + uint32 num = 0; + if (type == 0) + return 64; + while (!(type & 1)) { + num++; + type >>= 1; + } + return num; +} + +uint32 +aot_intrinsic_popcnt_i32(uint32 u) +{ + uint32 ret = 0; + while (u) { + u = (u & (u - 1)); + ret++; + } + return ret; +} + +uint32 +aot_intrinsic_popcnt_i64(uint64 u) +{ + uint32 ret = 0; + while (u) { + u = (u & (u - 1)); + ret++; + } + return ret; +} + +const char * +aot_intrinsic_get_symbol(const char *llvm_intrinsic) +{ + uint32 cnt; + for (cnt = 0; cnt < g_intrinsic_count; cnt++) { + if (!strcmp(llvm_intrinsic, g_intrinsic_mapping[cnt].llvm_intrinsic)) { + return g_intrinsic_mapping[cnt].native_intrinsic; + } + } + return NULL; +} + +#if WASM_ENABLE_WAMR_COMPILER != 0 || WASM_ENABLE_JIT != 0 + +static void +add_intrinsic_capability(AOTCompContext *comp_ctx, uint64 flag) +{ + uint64 group = AOT_INTRINSIC_GET_GROUP_FROM_FLAG(flag); + if (group < sizeof(comp_ctx->flags) / sizeof(uint64)) { + comp_ctx->flags[group] |= flag; + } + else { + bh_log(BH_LOG_LEVEL_WARNING, __FILE__, __LINE__, + "intrinsic exceeds max limit."); + } +} + +static void +add_f32_common_intrinsics_for_thumb2_fpu(AOTCompContext *comp_ctx) +{ + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_FABS); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_FADD); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_FSUB); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_FMUL); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_FDIV); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_SQRT); +} + +static void +add_f64_common_intrinsics_for_thumb2_fpu(AOTCompContext *comp_ctx) +{ + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_FABS); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_FADD); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_FSUB); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_FMUL); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_FDIV); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_SQRT); +} + +bool +aot_intrinsic_check_capability(const AOTCompContext *comp_ctx, + const char *llvm_intrinsic) +{ + uint32 cnt; + uint64 flag; + uint64 group; + + for (cnt = 0; cnt < g_intrinsic_count; cnt++) { + if (!strcmp(llvm_intrinsic, g_intrinsic_mapping[cnt].llvm_intrinsic)) { + flag = g_intrinsic_mapping[cnt].flag; + group = AOT_INTRINSIC_GET_GROUP_FROM_FLAG(flag); + flag &= AOT_INTRINSIC_FLAG_MASK; + if (group < sizeof(comp_ctx->flags) / sizeof(uint64)) { + if (comp_ctx->flags[group] & flag) { + return true; + } + } + else { + bh_log(BH_LOG_LEVEL_WARNING, __FILE__, __LINE__, + "intrinsic exceeds max limit."); + } + } + } + return false; +} + +void +aot_intrinsic_fill_capability_flags(AOTCompContext *comp_ctx) +{ + memset(comp_ctx->flags, 0, sizeof(comp_ctx->flags)); + + if (!comp_ctx->target_cpu) + return; + + if (!strncmp(comp_ctx->target_arch, "thumb", 5)) { + if (!strcmp(comp_ctx->target_cpu, "cortex-m4")) { + add_f32_common_intrinsics_for_thumb2_fpu(comp_ctx); + } + else if (!strcmp(comp_ctx->target_cpu, "cortex-m7")) { + add_f32_common_intrinsics_for_thumb2_fpu(comp_ctx); + add_f64_common_intrinsics_for_thumb2_fpu(comp_ctx); + } + } +} + +#endif /* WASM_ENABLE_WAMR_COMPILER != 0 || WASM_ENABLE_JIT != 0 */ diff --git a/core/iwasm/aot/aot_intrinsic.h b/core/iwasm/aot/aot_intrinsic.h new file mode 100644 index 000000000..b6297199d --- /dev/null +++ b/core/iwasm/aot/aot_intrinsic.h @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2021 XiaoMi Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _AOT_INTRINSIC_H +#define _AOT_INTRINSIC_H + +#if WASM_ENABLE_WAMR_COMPILER != 0 +#include "aot_llvm.h" +#endif + +#include "aot_runtime.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define AOT_INTRINSIC_GROUPS 2 + +/* Use uint64 as flag container: + * - The upper 16 bits are the intrinsic group number + * - The lower 48 bits are the intrinsic capability mask + */ + +#define AOT_INTRINSIC_FLAG(group, value) \ + ((((uint64)(group & 0xffffLL)) << 48) | (uint64)value) + +#define AOT_INTRINSIC_FLAG_MASK (0x0000ffffffffffffLL) + +#define AOT_INTRINSIC_GET_GROUP_FROM_FLAG(flag) \ + ((((uint64)flag) >> 48) & 0xffffLL) + +#define AOT_INTRINSIC_FLAG_F32_FADD AOT_INTRINSIC_FLAG(0, 0x000000000001) +#define AOT_INTRINSIC_FLAG_F32_FSUB AOT_INTRINSIC_FLAG(0, 0x000000000002) +#define AOT_INTRINSIC_FLAG_F32_FMUL AOT_INTRINSIC_FLAG(0, 0x000000000004) +#define AOT_INTRINSIC_FLAG_F32_FDIV AOT_INTRINSIC_FLAG(0, 0x000000000008) +#define AOT_INTRINSIC_FLAG_F32_FABS AOT_INTRINSIC_FLAG(0, 0x000000000010) +#define AOT_INTRINSIC_FLAG_F32_CEIL AOT_INTRINSIC_FLAG(0, 0x000000000020) +#define AOT_INTRINSIC_FLAG_F32_FLOOR AOT_INTRINSIC_FLAG(0, 0x000000000040) +#define AOT_INTRINSIC_FLAG_F32_TRUNC AOT_INTRINSIC_FLAG(0, 0x000000000080) +#define AOT_INTRINSIC_FLAG_F32_RINT AOT_INTRINSIC_FLAG(0, 0x000000000100) +#define AOT_INTRINSIC_FLAG_F32_SQRT AOT_INTRINSIC_FLAG(0, 0x000000000200) +#define AOT_INTRINSIC_FLAG_F32_COPYSIGN AOT_INTRINSIC_FLAG(0, 0x000000000400) +#define AOT_INTRINSIC_FLAG_F32_MIN AOT_INTRINSIC_FLAG(0, 0x000000000800) +#define AOT_INTRINSIC_FLAG_F32_MAX AOT_INTRINSIC_FLAG(0, 0x000000001000) +#define AOT_INTRINSIC_FLAG_I32_CLZ AOT_INTRINSIC_FLAG(0, 0x000000002000) +#define AOT_INTRINSIC_FLAG_I32_CTZ AOT_INTRINSIC_FLAG(0, 0x000000004000) +#define AOT_INTRINSIC_FLAG_I32_POPCNT AOT_INTRINSIC_FLAG(0, 0x000000008000) + +#define AOT_INTRINSIC_FLAG_F64_FADD AOT_INTRINSIC_FLAG(1, 0x000000000001) +#define AOT_INTRINSIC_FLAG_F64_FSUB AOT_INTRINSIC_FLAG(1, 0x000000000002) +#define AOT_INTRINSIC_FLAG_F64_FMUL AOT_INTRINSIC_FLAG(1, 0x000000000004) +#define AOT_INTRINSIC_FLAG_F64_FDIV AOT_INTRINSIC_FLAG(1, 0x000000000008) +#define AOT_INTRINSIC_FLAG_F64_FABS AOT_INTRINSIC_FLAG(1, 0x000000000010) +#define AOT_INTRINSIC_FLAG_F64_CEIL AOT_INTRINSIC_FLAG(1, 0x000000000020) +#define AOT_INTRINSIC_FLAG_F64_FLOOR AOT_INTRINSIC_FLAG(1, 0x000000000040) +#define AOT_INTRINSIC_FLAG_F64_TRUNC AOT_INTRINSIC_FLAG(1, 0x000000000080) +#define AOT_INTRINSIC_FLAG_F64_RINT AOT_INTRINSIC_FLAG(1, 0x000000000100) +#define AOT_INTRINSIC_FLAG_F64_SQRT AOT_INTRINSIC_FLAG(1, 0x000000000200) +#define AOT_INTRINSIC_FLAG_F64_COPYSIGN AOT_INTRINSIC_FLAG(1, 0x000000000400) +#define AOT_INTRINSIC_FLAG_F64_MIN AOT_INTRINSIC_FLAG(1, 0x000000000800) +#define AOT_INTRINSIC_FLAG_F64_MAX AOT_INTRINSIC_FLAG(1, 0x000000001000) +#define AOT_INTRINSIC_FLAG_I64_CLZ AOT_INTRINSIC_FLAG(1, 0x000000002000) +#define AOT_INTRINSIC_FLAG_I64_CTZ AOT_INTRINSIC_FLAG(1, 0x000000004000) +#define AOT_INTRINSIC_FLAG_I64_POPCNT AOT_INTRINSIC_FLAG(1, 0x000000008000) + +float32 +aot_intrinsic_fadd_f32(float32 a, float32 b); + +float64 +aot_intrinsic_fadd_f64(float64 a, float64 b); + +float32 +aot_intrinsic_fsub_f32(float32 a, float32 b); + +float64 +aot_intrinsic_fsub_f64(float64 a, float64 b); + +float32 +aot_intrinsic_fmul_f32(float32 a, float32 b); + +float64 +aot_intrinsic_fmul_f64(float64 a, float64 b); + +float32 +aot_intrinsic_fdiv_f32(float32 a, float32 b); + +float64 +aot_intrinsic_fdiv_f64(float64 a, float64 b); + +float32 +aot_intrinsic_fabs_f32(float32 a); + +float64 +aot_intrinsic_fabs_f64(float64 a); + +float32 +aot_intrinsic_ceil_f32(float32 a); + +float64 +aot_intrinsic_ceil_f64(float64 a); + +float32 +aot_intrinsic_floor_f32(float32 a); + +float64 +aot_intrinsic_floor_f64(float64 a); + +float32 +aot_intrinsic_trunc_f32(float32 a); + +float64 +aot_intrinsic_trunc_f64(float64 a); + +float32 +aot_intrinsic_rint_f32(float32 a); + +float64 +aot_intrinsic_rint_f64(float64 a); + +float32 +aot_intrinsic_sqrt_f32(float32 a); + +float64 +aot_intrinsic_sqrt_f64(float64 a); + +float32 +aot_intrinsic_copysign_f32(float32 a, float32 b); + +float64 +aot_intrinsic_copysign_f64(float64 a, float64 b); + +float32 +aot_intrinsic_fmin_f32(float32 a, float32 b); + +float64 +aot_intrinsic_fmin_f64(float64 a, float64 b); + +float32 +aot_intrinsic_fmax_f32(float32 a, float32 b); + +float64 +aot_intrinsic_fmax_f64(float64 a, float64 b); + +uint32 +aot_intrinsic_clz_i32(uint32 type); + +uint32 +aot_intrinsic_clz_i64(uint64 type); + +uint32 +aot_intrinsic_ctz_i32(uint32 type); + +uint32 +aot_intrinsic_ctz_i64(uint64 type); + +uint32 +aot_intrinsic_popcnt_i32(uint32 u); + +uint32 +aot_intrinsic_popcnt_i64(uint64 u); + +const char * +aot_intrinsic_get_symbol(const char *llvm_intrinsic); + +#if WASM_ENABLE_WAMR_COMPILER != 0 || WASM_ENABLE_JIT != 0 +bool +aot_intrinsic_check_capability(const AOTCompContext *comp_ctx, + const char *llvm_intrinsic); + +void +aot_intrinsic_fill_capability_flags(AOTCompContext *comp_ctx); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* end of _AOT_INTRINSIC_H */ diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 59e7f3f6a..599af2d24 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -181,6 +181,8 @@ GET_U64_FROM_ADDR(uint32 *addr) #define E_MACHINE_IA_64 50 /* Intel Merced */ #define E_MACHINE_MIPS_X 51 /* Stanford MIPS-X */ #define E_MACHINE_X86_64 62 /* AMD x86-64 architecture */ +#define E_MACHINE_ARC_COMPACT 93 /* ARC International ARCompact */ +#define E_MACHINE_ARC_COMPACT2 195 /* Synopsys ARCompact V2 */ #define E_MACHINE_XTENSA 94 /* Tensilica Xtensa Architecture */ #define E_MACHINE_RISCV 243 /* RISC-V 32/64 */ #define E_MACHINE_WIN_X86_64 0x8664 /* Windowx x86-64 architecture */ @@ -261,6 +263,10 @@ get_aot_file_target(AOTTargetInfo *target_info, case E_MACHINE_RISCV: machine_type = "riscv"; break; + case E_MACHINE_ARC_COMPACT: + case E_MACHINE_ARC_COMPACT2: + machine_type = "arc"; + break; default: set_error_buf_v(error_buf, error_buf_size, "unknown machine type %d", @@ -368,6 +374,90 @@ fail: return false; } +static void * +get_native_symbol_by_name(const char *name) +{ + void *func = NULL; + uint32 symnum = 0; + SymbolMap *sym = NULL; + + sym = get_target_symbol_map(&symnum); + + while (symnum--) { + if (strcmp(sym->symbol_name, name) == 0) { + func = sym->symbol_addr; + break; + } + sym++; + } + + return func; +} + +static bool +load_native_symbol_section(const uint8 *buf, const uint8 *buf_end, + AOTModule *module, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = buf, *p_end = buf_end; + uint32 cnt; + int32 i; + const char *symbol; + + read_uint32(p, p_end, cnt); + + module->native_symbol_count = cnt; + + if (cnt > 0) { + module->native_symbol_list = wasm_runtime_malloc(cnt * sizeof(void *)); + if (module->native_symbol_list == NULL) { + set_error_buf(error_buf, error_buf_size, + "malloc native symbol list failed"); + goto fail; + } + + for (i = cnt - 1; i >= 0; i--) { + read_string(p, p_end, symbol); + module->native_symbol_list[i] = get_native_symbol_by_name(symbol); + if (module->native_symbol_list[i] == NULL) { + set_error_buf_v(error_buf, error_buf_size, + "missing native symbol: %s", symbol); + goto fail; + } + } + } + + return true; +fail: + return false; +} + +static bool +load_custom_section(const uint8 *buf, const uint8 *buf_end, + AOTModule *module, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = buf, *p_end = buf_end; + uint32 sub_section_type; + + read_uint32(p, p_end, sub_section_type); + buf = p; + + switch (sub_section_type) { + case AOT_CUSTOM_SECTION_NATIVE_SYMBOL: + if (!load_native_symbol_section(buf, buf_end, module, + error_buf, error_buf_size)) + goto fail; + break; + default: + break; + } + + return true; +fail: + return false; +} + static void destroy_import_memories(AOTImportMemory *import_memories, bool is_jit_mode) @@ -1167,8 +1257,8 @@ load_text_section(const uint8 *buf, const uint8 *buf_end, module->code = (void*)(buf + module->literal_size); module->code_size = (uint32)(buf_end - (uint8*)module->code); - if (module->code_size > 0) { - plt_base = (uint8*)buf_end - get_plt_table_size(); + if ((module->code_size > 0) && (module->native_symbol_count == 0)) { + plt_base = (uint8 *)buf_end - get_plt_table_size(); init_plt_table(plt_base); } return true; @@ -1920,6 +2010,13 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, || !strcmp(group->section_name, ".text") #endif ) { + if (module->native_symbol_count > 0) { + set_error_buf(error_buf, error_buf_size, + "cannot apply relocation to text section " + "for aot file generated with " + "\"--enable-indirect-mode\" flag"); + goto fail; + } if (!do_text_relocation(module, group, error_buf, error_buf_size)) goto fail; } @@ -1993,7 +2090,8 @@ load_from_sections(AOTModule *module, AOTSection *sections, if ((last_section_type == (uint32)-1 && section_type != AOT_SECTION_TYPE_TARGET_INFO) || (last_section_type != (uint32)-1 - && section_type != last_section_type + 1)) { + && (section_type != last_section_type + 1 + && section_type != AOT_SECTION_TYPE_CUSTOM))) { set_error_buf(error_buf, error_buf_size, "invalid section order"); return false; @@ -2030,6 +2128,11 @@ load_from_sections(AOTModule *module, AOTSection *sections, error_buf, error_buf_size)) return false; break; + case AOT_SECTION_TYPE_CUSTOM: + if (!load_custom_section(buf, buf_end, module, + error_buf, error_buf_size)) + return false; + break; default: set_error_buf(error_buf, error_buf_size, "invalid aot section type"); @@ -2039,7 +2142,8 @@ load_from_sections(AOTModule *module, AOTSection *sections, section = section->next; } - if (last_section_type != AOT_SECTION_TYPE_RELOCATION) { + if (last_section_type != AOT_SECTION_TYPE_RELOCATION + && last_section_type != AOT_SECTION_TYPE_CUSTOM) { set_error_buf(error_buf, error_buf_size, "section missing"); return false; @@ -2208,21 +2312,69 @@ destroy_sections(AOTSection *section_list, bool destroy_aot_text) } static bool -create_sections(const uint8 *buf, uint32 size, +resolve_native_symbols(const uint8 *buf, uint32 size, uint32 *p_count, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = buf, *p_end = buf + size; + uint32 section_type; + uint32 section_size = 0; + + p += 8; + while (p < p_end) { + read_uint32(p, p_end, section_type); + if (section_type <= AOT_SECTION_TYPE_SIGANATURE + || section_type == AOT_SECTION_TYPE_CUSTOM) { + read_uint32(p, p_end, section_size); + CHECK_BUF(p, p_end, section_size); + if (section_type == AOT_SECTION_TYPE_CUSTOM) { + read_uint32(p, p_end, section_type); + if (section_type == AOT_CUSTOM_SECTION_NATIVE_SYMBOL) { + /* Read the count of native symbol */ + read_uint32(p, p_end, *p_count); + return true; + } + p -= sizeof(uint32); + } + } + else if (section_type > AOT_SECTION_TYPE_SIGANATURE) { + set_error_buf(error_buf, error_buf_size, + "resolve native symbol failed"); + break; + } + p += section_size; + } + return true; +fail: + return false; +} + +static bool +create_sections(AOTModule *module, + const uint8 *buf, uint32 size, AOTSection **p_section_list, char *error_buf, uint32 error_buf_size) { AOTSection *section_list = NULL, *section_list_end = NULL, *section; const uint8 *p = buf, *p_end = buf + size; + bool destory_aot_text = false; + uint32 native_symbol_count = 0; uint32 section_type; uint32 section_size; uint64 total_size; uint8 *aot_text; + if (!resolve_native_symbols(buf, size, &native_symbol_count, + error_buf, error_buf_size)) { + goto fail; + } + + module->native_symbol_count = native_symbol_count; + p += 8; while (p < p_end) { read_uint32(p, p_end, section_type); - if (section_type < AOT_SECTION_TYPE_SIGANATURE) { + if (section_type < AOT_SECTION_TYPE_SIGANATURE + || section_type == AOT_SECTION_TYPE_CUSTOM) { read_uint32(p, p_end, section_size); CHECK_BUF(p, p_end, section_size); @@ -2238,7 +2390,7 @@ create_sections(const uint8 *buf, uint32 size, section->section_body_size = section_size; if (section_type == AOT_SECTION_TYPE_TEXT) { - if (section_size > 0) { + if ((section_size > 0) && (native_symbol_count == 0)) { int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC; #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) \ @@ -2270,6 +2422,7 @@ create_sections(const uint8 *buf, uint32 size, bh_memcpy_s(aot_text, (uint32)total_size, section->section_body, (uint32)section_size); section->section_body = aot_text; + destory_aot_text = true; if ((uint32)total_size > section->section_body_size) { memset(aot_text + (uint32)section_size, @@ -2277,8 +2430,6 @@ create_sections(const uint8 *buf, uint32 size, section->section_body_size = (uint32)total_size; } } - else - section->section_body = NULL; } if (!section_list) @@ -2307,7 +2458,7 @@ create_sections(const uint8 *buf, uint32 size, return true; fail: if (section_list) - destroy_sections(section_list, true); + destroy_sections(section_list, destory_aot_text); return false; } @@ -2333,14 +2484,16 @@ load(const uint8 *buf, uint32 size, AOTModule *module, return false; } - if (!create_sections(buf, size, §ion_list, error_buf, error_buf_size)) + if (!create_sections(module, buf, size, §ion_list, + error_buf, error_buf_size)) return false; ret = load_from_sections(module, section_list, error_buf, error_buf_size); if (!ret) { /* If load_from_sections() fails, then aot text is destroyed in destroy_sections() */ - destroy_sections(section_list, true); + destroy_sections(section_list, + module->native_symbol_count == 0 ? true : false); /* aot_unload() won't destroy aot text again */ module->code = NULL; } @@ -2616,6 +2769,9 @@ aot_unload(AOTModule *module) module->mem_init_data_count, module->is_jit_mode); + if (module->native_symbol_list) + wasm_runtime_free(module->native_symbol_list); + if (module->import_tables) destroy_import_tables(module->import_tables, module->is_jit_mode); @@ -2658,7 +2814,7 @@ aot_unload(AOTModule *module) if (module->const_str_set) bh_hash_map_destroy(module->const_str_set); - if (module->code) { + if (module->code && (module->native_symbol_count == 0)) { /* The layout is: literal size + literal + code (with plt table) */ uint8 *mmap_addr = module->literal - sizeof(uint32); uint32 total_size = sizeof(uint32) diff --git a/core/iwasm/aot/aot_reloc.h b/core/iwasm/aot/aot_reloc.h index 7c1673cf7..21ecd1377 100644 --- a/core/iwasm/aot/aot_reloc.h +++ b/core/iwasm/aot/aot_reloc.h @@ -4,6 +4,7 @@ */ #include "aot_runtime.h" +#include "aot_intrinsic.h" typedef struct { const char *symbol_name; @@ -48,6 +49,40 @@ typedef struct { #define REG_AOT_TRACE_SYM() #endif +#define REG_INTRINSIC_SYM() \ + REG_SYM(aot_intrinsic_fabs_f32), \ + REG_SYM(aot_intrinsic_fabs_f64), \ + REG_SYM(aot_intrinsic_floor_f32), \ + REG_SYM(aot_intrinsic_floor_f64), \ + REG_SYM(aot_intrinsic_ceil_f32), \ + REG_SYM(aot_intrinsic_ceil_f64), \ + REG_SYM(aot_intrinsic_trunc_f32), \ + REG_SYM(aot_intrinsic_trunc_f64), \ + REG_SYM(aot_intrinsic_rint_f32), \ + REG_SYM(aot_intrinsic_rint_f64), \ + REG_SYM(aot_intrinsic_sqrt_f32), \ + REG_SYM(aot_intrinsic_sqrt_f64), \ + REG_SYM(aot_intrinsic_copysign_f32), \ + REG_SYM(aot_intrinsic_copysign_f64), \ + REG_SYM(aot_intrinsic_fadd_f32), \ + REG_SYM(aot_intrinsic_fadd_f64), \ + REG_SYM(aot_intrinsic_fsub_f32), \ + REG_SYM(aot_intrinsic_fsub_f64), \ + REG_SYM(aot_intrinsic_fmul_f32), \ + REG_SYM(aot_intrinsic_fmul_f64), \ + REG_SYM(aot_intrinsic_fdiv_f32), \ + REG_SYM(aot_intrinsic_fdiv_f64), \ + REG_SYM(aot_intrinsic_fmin_f32), \ + REG_SYM(aot_intrinsic_fmin_f64), \ + REG_SYM(aot_intrinsic_fmax_f32), \ + REG_SYM(aot_intrinsic_fmax_f64), \ + REG_SYM(aot_intrinsic_clz_i32), \ + REG_SYM(aot_intrinsic_clz_i64), \ + REG_SYM(aot_intrinsic_ctz_i32), \ + REG_SYM(aot_intrinsic_ctz_i64), \ + REG_SYM(aot_intrinsic_popcnt_i32), \ + REG_SYM(aot_intrinsic_popcnt_i64), \ + #define REG_COMMON_SYMBOLS \ REG_SYM(aot_set_exception_with_id), \ REG_SYM(aot_invoke_native), \ @@ -71,7 +106,8 @@ typedef struct { REG_BULK_MEMORY_SYM() \ REG_ATOMIC_WAIT_SYM() \ REG_REF_TYPES_SYM() \ - REG_AOT_TRACE_SYM() + REG_AOT_TRACE_SYM() \ + REG_INTRINSIC_SYM() \ #define CHECK_RELOC_OFFSET(data_size) do { \ if (!check_reloc_offset(target_section_size, reloc_offset, data_size, \ diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 404ec33f4..2acf04edb 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -2233,7 +2233,7 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, AOTImportFunc *import_func; const char *signature; void *attachment; - char buf[128]; + char buf[96]; bh_assert(func_idx < aot_module->import_func_count); @@ -2282,7 +2282,7 @@ aot_call_indirect(WASMExecEnv *exec_env, AOTImportFunc *import_func; const char *signature = NULL; void *attachment = NULL; - char buf[128]; + char buf[96]; bool ret; /* this function is called from native code, so exec_env->handle and diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index af51347fd..159aac24f 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -40,14 +40,20 @@ typedef enum AOTExceptionID { typedef enum AOTSectionType { AOT_SECTION_TYPE_TARGET_INFO = 0, - AOT_SECTION_TYPE_INIT_DATA, - AOT_SECTION_TYPE_TEXT, - AOT_SECTION_TYPE_FUNCTION, - AOT_SECTION_TYPE_EXPORT, - AOT_SECTION_TYPE_RELOCATION, - AOT_SECTION_TYPE_SIGANATURE + AOT_SECTION_TYPE_INIT_DATA = 1, + AOT_SECTION_TYPE_TEXT = 2, + AOT_SECTION_TYPE_FUNCTION = 3, + AOT_SECTION_TYPE_EXPORT = 4, + AOT_SECTION_TYPE_RELOCATION = 5, + AOT_SECTION_TYPE_SIGANATURE = 6, + AOT_SECTION_TYPE_CUSTOM = 100, } AOTSectionType; +typedef enum AOTCustomSectionType { + AOT_CUSTOM_SECTION_NATIVE_SYMBOL = 1, + AOT_CUSTOM_SECTION_ACCESS_CONTROL = 2, +} AOTCustomSectionType; + typedef struct AOTObjectDataSection { char *name; uint8 *data; @@ -125,6 +131,10 @@ typedef struct AOTModule { uint32 mem_init_data_count; AOTMemInitData **mem_init_data_list; + /* native symobl */ + uint32 native_symbol_count; + void **native_symbol_list; + /* import tables */ uint32 import_table_count; AOTImportTable *import_tables; diff --git a/core/iwasm/aot/arch/aot_reloc_arc.c b/core/iwasm/aot/arch/aot_reloc_arc.c new file mode 100644 index 000000000..d3dbcf213 --- /dev/null +++ b/core/iwasm/aot/arch/aot_reloc_arc.c @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "aot_reloc.h" + +#define R_ARC_S21H_PCREL 14 +#define R_ARC_S21W_PCREL 15 +#define R_ARC_S25H_PCREL 16 +#define R_ARC_S25W_PCREL 17 +#define R_ARC_32 4 +#define R_ARC_32_ME 27 + +void __st_r13_to_r15(); +void __st_r13_to_r16(); +void __st_r13_to_r17(); +void __st_r13_to_r18(); +void __st_r13_to_r19(); +void __st_r13_to_r20(); +void __st_r13_to_r21(); +void __st_r13_to_r22(); +void __st_r13_to_r23(); +void __st_r13_to_r24(); +void __st_r13_to_r25(); +void __ld_r13_to_r15(); +void __ld_r13_to_r16(); +void __ld_r13_to_r17(); +void __ld_r13_to_r18(); +void __ld_r13_to_r19(); +void __ld_r13_to_r20(); +void __ld_r13_to_r21(); +void __ld_r13_to_r22(); +void __ld_r13_to_r23(); +void __ld_r13_to_r24(); +void __ld_r13_to_r25(); +void __adddf3(); +void __addsf3(); +void __divdf3(); +void __divdi3(); +void __divsf3(); +void __divsi3(); +void __eqsf2(); +void __extendsfdf2(); +void __fixdfsi(); +void __floatsidf(); +void __floatsisf(); +void __gedf2(); +void __gtdf2(); +void __ledf2(); +void __lesf2(); +void __ltdf2(); +void __muldf3(); +void __mulsf3(); +void __subdf3(); +void __subsf3(); +void __truncdfsf2(); +void __unorddf2(); + +static SymbolMap target_sym_map[] = { + REG_COMMON_SYMBOLS + REG_SYM(__st_r13_to_r15), + REG_SYM(__st_r13_to_r16), + REG_SYM(__st_r13_to_r17), + REG_SYM(__st_r13_to_r18), + REG_SYM(__st_r13_to_r19), + REG_SYM(__st_r13_to_r20), + REG_SYM(__st_r13_to_r21), + REG_SYM(__st_r13_to_r22), + REG_SYM(__st_r13_to_r23), + REG_SYM(__st_r13_to_r24), + REG_SYM(__st_r13_to_r25), + REG_SYM(__ld_r13_to_r15), + REG_SYM(__ld_r13_to_r16), + REG_SYM(__ld_r13_to_r17), + REG_SYM(__ld_r13_to_r18), + REG_SYM(__ld_r13_to_r19), + REG_SYM(__ld_r13_to_r20), + REG_SYM(__ld_r13_to_r21), + REG_SYM(__ld_r13_to_r22), + REG_SYM(__ld_r13_to_r23), + REG_SYM(__ld_r13_to_r24), + REG_SYM(__ld_r13_to_r25), + REG_SYM (__adddf3), + REG_SYM (__addsf3), + REG_SYM (__divdf3), + REG_SYM (__divdi3), + REG_SYM (__divsf3), + REG_SYM (__divsi3), + REG_SYM (__eqsf2), + REG_SYM (__extendsfdf2), + REG_SYM (__fixdfsi), + REG_SYM (__floatsidf), + REG_SYM (__floatsisf), + REG_SYM (__gedf2), + REG_SYM (__gtdf2), + REG_SYM (__ledf2), + REG_SYM (__lesf2), + REG_SYM (__ltdf2), + REG_SYM (__muldf3), + REG_SYM (__mulsf3), + REG_SYM (__subdf3), + REG_SYM (__subsf3), + REG_SYM (__truncdfsf2), + REG_SYM (__unorddf2), + +}; + +static void +set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) +{ + if (error_buf != NULL) + snprintf(error_buf, error_buf_size, "%s", string); +} + +SymbolMap * +get_target_symbol_map(uint32 *sym_num) +{ + *sym_num = sizeof(target_sym_map) / sizeof(SymbolMap); + return target_sym_map; +} + +void +get_current_target(char *target_buf, uint32 target_buf_size) +{ + snprintf(target_buf, target_buf_size, "arc"); +} + +uint32 +get_plt_table_size() +{ + return 0; +} + +void +init_plt_table(uint8 *plt) +{ + (void)plt; +} + +static bool +check_reloc_offset(uint32 target_section_size, + uint64 reloc_offset, uint32 reloc_data_size, + char *error_buf, uint32 error_buf_size) +{ + if (!(reloc_offset < (uint64)target_section_size + && reloc_offset + reloc_data_size <= (uint64)target_section_size)) { + set_error_buf(error_buf, error_buf_size, + "AOT module load failed: invalid relocation offset."); + return false; + } + return true; +} + +static uint32 +middle_endian_convert(uint32 insn) +{ + return ((insn & 0xFFFF0000) >> 16) | ((insn & 0x0000FFFF) << 16); +} + +bool +apply_relocation(AOTModule *module, + uint8 *target_section_addr, uint32 target_section_size, + uint64 reloc_offset, uint64 reloc_addend, + uint32 reloc_type, void *symbol_addr, int32 symbol_index, + char *error_buf, uint32 error_buf_size) +{ + switch (reloc_type) { + case R_ARC_S25W_PCREL: + { + uint32 insn = LOAD_I32(target_section_addr + reloc_offset); + int32 addend, value; + uintptr_t S, A, P; + + CHECK_RELOC_OFFSET(sizeof(void*)); + + /* Convert from middle endian */ + insn = middle_endian_convert(insn); + + addend = ((insn << 28) >> 28) << 10; + /* Extract the next 10 bits from Position 6 to 15 in insn */ + addend |= ((insn << 16) >> 22); + addend = addend << 9; + /* Extract the remaining 9 bits from Position 18 to 26 in insn */ + addend |= ((insn << 5) >> 23); + /* Fill in 2 bits to get the 25 bit Offset Value */ + addend = addend << 2; + + /* (S + A) - P */ + S = (uintptr_t)(uint8*)symbol_addr; + A = (uintptr_t)reloc_addend; + P = (uintptr_t)(target_section_addr + reloc_offset); + P &= (uintptr_t)~3; + value = (int32)(S + A + addend - P); + + insn = insn & 0xf8030030; + insn |= ((((value >> 2) & 0x1ff) << 18) + | (((value >> 2) & 0x7fe00) >> 3) + | (((value >> 2) & 0x780000) >> 19)); + + /* Convert to middle endian */ + insn = middle_endian_convert(insn); + + STORE_U32(target_section_addr + reloc_offset, insn); + break; + } + case R_ARC_32: + case R_ARC_32_ME: + { + uint32 insn; + + CHECK_RELOC_OFFSET(sizeof(void*)); + + /* (S + A) */ + insn = (uint32)(uintptr_t) + ((uint8*)symbol_addr + reloc_addend); + + if (reloc_type == R_ARC_32_ME) + /* Convert to middle endian */ + insn = middle_endian_convert(insn); + + STORE_U32(target_section_addr + reloc_offset, insn); + break; + } + default: + { + if (error_buf != NULL) + snprintf(error_buf, error_buf_size, + "Load relocation section failed: " + "invalid relocation type %d.", + reloc_type); + return false; + } + } + return true; +} + diff --git a/core/iwasm/aot/iwasm_aot.cmake b/core/iwasm/aot/iwasm_aot.cmake index a5195d83f..2a6856873 100644 --- a/core/iwasm/aot/iwasm_aot.cmake +++ b/core/iwasm/aot/iwasm_aot.cmake @@ -25,6 +25,8 @@ elseif (WAMR_BUILD_TARGET STREQUAL "XTENSA") set (arch_source ${IWASM_AOT_DIR}/arch/aot_reloc_xtensa.c) elseif (WAMR_BUILD_TARGET MATCHES "RISCV*") set (arch_source ${IWASM_AOT_DIR}/arch/aot_reloc_riscv.c) +elseif (WAMR_BUILD_TARGET STREQUAL "ARC") + set (arch_source ${IWASM_AOT_DIR}/arch/aot_reloc_arc.c) else () message (FATAL_ERROR "Build target isn't set") endif () diff --git a/core/iwasm/common/arch/invokeNative_arc.s b/core/iwasm/common/arch/invokeNative_arc.s new file mode 100644 index 000000000..e448eea65 --- /dev/null +++ b/core/iwasm/common/arch/invokeNative_arc.s @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + + .text + .align 2 +#ifndef BH_PLATFORM_DARWIN + .globl invokeNative + .type invokeNative, function +invokeNative: +#else + .globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ + +/* + * Arguments passed in: + * r0: function ptr + * r1: argv + * r2: nstacks + * ARC ABI: + * r0-r7: function arguments, caller-saved + * r8-r12: temp registers, caller-saved + */ + + push_s blink /* push return addr */ + st.aw fp, [sp, -4] /* push fp */ + mov fp, sp /* fp = sp */ + + mov r8, r0 /* r8 = func_ptr */ + mov r9, r1 /* r9 = argv */ + mov r10, r2 /* r10 = nstacks */ + + ld r0, [r9, 0] /* r0 = argv[0] */ + ld r1, [r9, 4] /* r1 = argv[1] */ + ld r2, [r9, 8] /* r2 = argv[2] */ + ld r3, [r9, 12] /* r3 = argv[3] */ + ld r4, [r9, 16] /* r4 = argv[4] */ + ld r5, [r9, 20] /* r5 = argv[5] */ + ld r6, [r9, 24] /* r6 = argv[6] */ + ld r7, [r9, 28] /* r7 = argv[7] */ + + add r9, r9, 32 /* r9 = stack_args */ + breq r10, 0, call_func /* if (r10 == 0) goto call_func */ + + asl r11, r10, 2 /* r11 = nstacks * 4 */ + sub sp, sp, r11 /* sp = sp - nstacks * 4 */ + and sp, sp, ~7 /* make sp 8-byte aligned */ + mov r11, sp /* r11 = sp */ + +loop_stack_args: + breq r10, 0, call_func /* if (r10 == 0) goto call_func */ + ld r12, [r9] /* r12 = stack_args[i] */ + st r12, [r11] /* stack[i] = r12 */ + add r9, r9, 4 /* r9 = r9 + 4 */ + add r11, r11, 4 /* r11 = r11 + 4 */ + sub r10, r10, 1 /* r10 = r10 + 1 */ + j loop_stack_args + +call_func: + jl [r8] /* call function */ + + mov sp, fp /* sp = fp */ + ld.ab fp, [sp, 4] /* pop fp */ + pop_s blink /* pop return addr */ + j_s [blink] /* ret */ + nop_s + diff --git a/core/iwasm/common/iwasm_common.cmake b/core/iwasm/common/iwasm_common.cmake index 6bcbbdaed..de0826e2c 100644 --- a/core/iwasm/common/iwasm_common.cmake +++ b/core/iwasm/common/iwasm_common.cmake @@ -68,6 +68,8 @@ elseif (WAMR_BUILD_TARGET STREQUAL "XTENSA") set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_xtensa.s) elseif (WAMR_BUILD_TARGET MATCHES "RISCV*") set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_riscv.S) +elseif (WAMR_BUILD_TARGET STREQUAL "ARC") + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_arc.s) else () message (FATAL_ERROR "Build target isn't set") endif () diff --git a/core/iwasm/common/wasm_exec_env.c b/core/iwasm/common/wasm_exec_env.c index d1c2cfe20..f54f0931f 100644 --- a/core/iwasm/common/wasm_exec_env.c +++ b/core/iwasm/common/wasm_exec_env.c @@ -12,6 +12,10 @@ #include "../aot/aot_runtime.h" #endif +#if WASM_ENABLE_AOT != 0 +#include "aot_runtime.h" +#endif + #if WASM_ENABLE_THREAD_MGR != 0 #include "../libraries/thread-mgr/thread_manager.h" #endif @@ -50,6 +54,14 @@ wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst, exec_env->wasm_stack.s.bottom + stack_size; exec_env->wasm_stack.s.top = exec_env->wasm_stack.s.bottom; +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + AOTModuleInstance *i = (AOTModuleInstance *)module_inst; + AOTModule *m = (AOTModule *)i->aot_module.ptr; + exec_env->native_symbol = m->native_symbol_list; + } +#endif + #if WASM_ENABLE_MEMORY_TRACING != 0 wasm_runtime_dump_exec_env_mem_consumption(exec_env); #endif diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 09e8d4286..a65a63d39 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -2480,7 +2480,8 @@ fail: #if defined(BUILD_TARGET_ARM_VFP) \ || defined(BUILD_TARGET_THUMB_VFP) \ || defined(BUILD_TARGET_RISCV32_ILP32D) \ - || defined(BUILD_TARGET_RISCV32_ILP32) + || defined(BUILD_TARGET_RISCV32_ILP32) \ + || defined(BUILD_TARGET_ARC) typedef void (*GenericFunctionPointer)(); int64 invokeNative(GenericFunctionPointer f, uint32 *args, uint32 n_stacks); @@ -2496,8 +2497,7 @@ static Int64FuncPtr invokeNative_Int64 = (Int64FuncPtr)(uintptr_t)invokeNative; static Int32FuncPtr invokeNative_Int32 = (Int32FuncPtr)(uintptr_t)invokeNative; static VoidFuncPtr invokeNative_Void = (VoidFuncPtr)(uintptr_t)invokeNative; -#if !defined(BUILD_TARGET_RISCV32_ILP32D) \ - && !defined(BUILD_TARGET_RISCV32_ILP32) +#if defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) #define MAX_REG_INTS 4 #define MAX_REG_FLOATS 16 #else @@ -2519,7 +2519,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, uint32 result_count = func_type->result_count; uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0; bool ret = false; -#if !defined(BUILD_TARGET_RISCV32_ILP32) +#if !defined(BUILD_TARGET_RISCV32_ILP32) && !defined(BUILD_TARGET_ARC) uint32 *fps; int n_fps = 0; #else @@ -2544,14 +2544,15 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, break; case VALUE_TYPE_I64: if (n_ints < MAX_REG_INTS - 1) { -#if !defined(BUILD_TARGET_RISCV32_ILP32) && !defined(BUILD_TARGET_RISCV32_ILP32D) +#if defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) /* 64-bit data must be 8 bytes aligned in arm */ if (n_ints & 1) n_ints++; #endif n_ints += 2; } -#if defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_RISCV32_ILP32D) +#if defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_RISCV32_ILP32D) \ + || defined(BUILD_TARGET_ARC) /* part in register, part in stack */ else if (n_ints == MAX_REG_INTS - 1) { n_ints++; @@ -2561,8 +2562,10 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, else { /* 64-bit data in stack must be 8 bytes aligned in arm and riscv32 */ +#if !defined(BUILD_TARGET_ARC) if (n_stacks & 1) n_stacks++; +#endif n_stacks += 2; } break; @@ -2575,23 +2578,26 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, break; case VALUE_TYPE_F64: if (n_fps < MAX_REG_FLOATS - 1) { -#if !defined(BUILD_TARGET_RISCV32_ILP32) +#if !defined(BUILD_TARGET_RISCV32_ILP32) && !defined(BUILD_TARGET_ARC) /* 64-bit data must be 8 bytes aligned in arm */ if (n_fps & 1) n_fps++; #endif n_fps += 2; } -#if defined(BUILD_TARGET_RISCV32_ILP32) +#if defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_ARC) else if (n_fps == MAX_REG_FLOATS - 1) { n_fps++; n_stacks++; } #endif else { - /* 64-bit data must be 8 bytes aligned in arm */ + /* 64-bit data in stack must be 8 bytes aligned + in arm and riscv32 */ +#if !defined(BUILD_TARGET_ARC) if (n_stacks & 1) n_stacks++; +#endif n_stacks += 2; } break; @@ -2634,11 +2640,11 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, n_stacks++; } -#if !defined(BUILD_TARGET_RISCV32_ILP32) && !defined(BUILD_TARGET_RISCV32_ILP32D) +#if defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) argc1 = MAX_REG_INTS + MAX_REG_FLOATS + n_stacks; -#elif defined(BUILD_TARGET_RISCV32_ILP32) +#elif defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_ARC) argc1 = MAX_REG_INTS + n_stacks; -#else +#else /* for BUILD_TARGET_RISCV32_ILP32D */ argc1 = MAX_REG_INTS + MAX_REG_FLOATS * 2 + n_stacks; #endif @@ -2651,12 +2657,12 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, } ints = argv1; -#if !defined(BUILD_TARGET_RISCV32_ILP32) && !defined(BUILD_TARGET_RISCV32_ILP32D) +#if defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) fps = ints + MAX_REG_INTS; stacks = fps + MAX_REG_FLOATS; -#elif defined(BUILD_TARGET_RISCV32_ILP32) +#elif defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_ARC) stacks = ints + MAX_REG_INTS; -#else +#else /* for BUILD_TARGET_RISCV32_ILP32D */ fps = ints + MAX_REG_INTS; stacks = fps + MAX_REG_FLOATS * 2; #endif @@ -2719,16 +2725,16 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, case VALUE_TYPE_I64: { if (n_ints < MAX_REG_INTS - 1) { -#if !defined(BUILD_TARGET_RISCV32_ILP32) && !defined(BUILD_TARGET_RISCV32_ILP32D) +#if defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) /* 64-bit data must be 8 bytes aligned in arm */ if (n_ints & 1) n_ints++; #endif - *(uint64*)&ints[n_ints] = *(uint64*)argv_src; - n_ints += 2; - argv_src += 2; + ints[n_ints++] = *argv_src++; + ints[n_ints++] = *argv_src++; } -#if defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_RISCV32_ILP32D) +#if defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_RISCV32_ILP32D) \ + || defined(BUILD_TARGET_ARC) else if (n_ints == MAX_REG_INTS - 1) { ints[n_ints++] = *argv_src++; stacks[n_stacks++] = *argv_src++; @@ -2737,11 +2743,12 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, else { /* 64-bit data in stack must be 8 bytes aligned in arm and riscv32 */ +#if !defined(BUILD_TARGET_ARC) if (n_stacks & 1) n_stacks++; - *(uint64*)&stacks[n_stacks] = *(uint64*)argv_src; - n_stacks += 2; - argv_src += 2; +#endif + stacks[n_stacks++] = *argv_src++; + stacks[n_stacks++] = *argv_src++; } break; } @@ -2757,28 +2764,29 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, case VALUE_TYPE_F64: { if (n_fps < MAX_REG_FLOATS - 1) { -#if !defined(BUILD_TARGET_RISCV32_ILP32) +#if !defined(BUILD_TARGET_RISCV32_ILP32) && !defined(BUILD_TARGET_ARC) /* 64-bit data must be 8 bytes aligned in arm */ if (n_fps & 1) n_fps++; #endif - *(float64*)&fps[n_fps] = *(float64*)argv_src; - n_fps += 2; - argv_src += 2; + fps[n_fps++] = *argv_src++; + fps[n_fps++] = *argv_src++; } -#if defined(BUILD_TARGET_RISCV32_ILP32) +#if defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_ARC) else if (n_fps == MAX_REG_FLOATS - 1) { fps[n_fps++] = *argv_src++; stacks[n_stacks++] = *argv_src++; } #endif else { - /* 64-bit data must be 8 bytes aligned in arm */ + /* 64-bit data in stack must be 8 bytes aligned + in arm and riscv32 */ +#if !defined(BUILD_TARGET_ARC) if (n_stacks & 1) n_stacks++; - *(float64*)&stacks[n_stacks] = *(float64*)argv_src; - n_stacks += 2; - argv_src += 2; +#endif + stacks[n_stacks++] = *argv_src++; + stacks[n_stacks++] = *argv_src++; } break; } @@ -2885,7 +2893,8 @@ fail: #endif /* end of defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) \ || defined(BUILD_TARGET_RISCV32_ILP32D) - || defined(BUILD_TARGET_RISCV32_ILP32) */ + || defined(BUILD_TARGET_RISCV32_ILP32) + || defined(BUILD_TARGET_ARC) */ #if defined(BUILD_TARGET_X86_32) \ || defined(BUILD_TARGET_ARM) \ diff --git a/core/iwasm/compilation/aot.h b/core/iwasm/compilation/aot.h index 44f98cf1e..6c39d6dc5 100644 --- a/core/iwasm/compilation/aot.h +++ b/core/iwasm/compilation/aot.h @@ -229,6 +229,12 @@ typedef struct AOTCompData { WASMModule *wasm_module; } AOTCompData; +typedef struct AOTNativeSymbol { + bh_list_link link; + const char *symbol; + int32 index; +} AOTNativeSymbol; + AOTCompData* aot_create_comp_data(WASMModule *module); diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index 0254cf378..097d4f901 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -2111,19 +2111,26 @@ bool aot_emit_object_file(AOTCompContext *comp_ctx, char *file_name) { char *err = NULL; + LLVMCodeGenFileType file_type = LLVMObjectFile; + LLVMTargetRef target = + LLVMGetTargetMachineTarget(comp_ctx->target_machine); bh_print_time("Begin to emit object file"); + if (!strncmp(LLVMGetTargetName(target), "arc", 3)) + /* Emit to assmelby file instead for arc target + as it cannot emit to object file */ + file_type = LLVMAssemblyFile; + if (LLVMTargetMachineEmitToFile(comp_ctx->target_machine, comp_ctx->module, - file_name, - LLVMObjectFile, + file_name, file_type, &err) != 0) { if (err) { LLVMDisposeMessage(err); err = NULL; } - aot_set_last_error("emit elf to memory buffer failed."); + aot_set_last_error("emit elf to object file failed."); return false; } diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index 9fab6cfaf..660c515e7 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -790,6 +790,23 @@ get_relocation_section_size(AOTObjectData *obj_data) is_32bit_binary(obj_data->binary)); } +static uint32 +get_native_symbol_list_size(AOTCompContext *comp_ctx) +{ + uint32 len = 0; + AOTNativeSymbol *sym = NULL; + + sym = bh_list_first_elem(&comp_ctx->native_symbols); + + while (sym) { + len = align_uint(len, 2); + len += get_string_size(sym->symbol); + sym = bh_list_elem_next(sym); + } + + return len; +} + static uint32 get_aot_file_size(AOTCompContext *comp_ctx, AOTCompData *comp_data, AOTObjectData *obj_data) @@ -835,6 +852,14 @@ get_aot_file_size(AOTCompContext *comp_ctx, AOTCompData *comp_data, size += (uint32)sizeof(uint32) * 2; size += get_relocation_section_size(obj_data); + if (get_native_symbol_list_size(comp_ctx) > 0) { + /* emit only when threre are native symbols */ + size = align_uint(size, 4); + /* section id + section size + sub section id + symbol count */ + size += (uint32)sizeof(uint32) * 4; + size += get_native_symbol_list_size(comp_ctx); + } + return size; } @@ -1505,6 +1530,38 @@ aot_emit_relocation_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset, return true; } +static bool +aot_emit_native_symbol(uint8 *buf, uint8 *buf_end, uint32 *p_offset, + AOTCompContext *comp_ctx) +{ + uint32 offset = *p_offset; + AOTNativeSymbol *sym = NULL; + + if (bh_list_length(&comp_ctx->native_symbols) == 0) + /* emit only when threre are native symbols */ + return true; + + *p_offset = offset = align_uint(offset, 4); + + EMIT_U32(AOT_SECTION_TYPE_CUSTOM); + /* sub section id + symbol count + symbol list */ + EMIT_U32(sizeof(uint32) * 2 + get_native_symbol_list_size(comp_ctx)); + EMIT_U32(AOT_CUSTOM_SECTION_NATIVE_SYMBOL); + EMIT_U32(bh_list_length(&comp_ctx->native_symbols)); + + sym = bh_list_first_elem(&comp_ctx->native_symbols); + + while (sym) { + offset = align_uint(offset, 2); + EMIT_STR(sym->symbol); + sym = bh_list_elem_next(sym); + } + + *p_offset = offset; + + return true; +} + typedef uint32 U32; typedef int32 I32; typedef uint16 U16; @@ -2164,6 +2221,8 @@ aot_obj_data_create(AOTCompContext *comp_ctx) { char *err = NULL; AOTObjectData *obj_data; + LLVMTargetRef target = + LLVMGetTargetMachineTarget(comp_ctx->target_machine); bh_print_time("Begin to emit object file to buffer"); @@ -2173,11 +2232,76 @@ aot_obj_data_create(AOTCompContext *comp_ctx) } memset(obj_data, 0, sizeof(AOTObjectData)); - if (LLVMTargetMachineEmitToMemoryBuffer(comp_ctx->target_machine, - comp_ctx->module, - LLVMObjectFile, - &err, - &obj_data->mem_buf) != 0) { + bh_print_time("Begin to emit object file"); + + if (!strncmp(LLVMGetTargetName(target), "arc", 3)) { + /* Emit to assmelby file instead for arc target + as it cannot emit to object file */ + char file_name[] = "wasm-XXXXXX", buf[128]; + int fd, ret; + + if ((fd = mkstemp(file_name)) <= 0) { + aot_set_last_error("make temp file failed."); + goto fail; + } + + /* close and remove temp file */ + close(fd); + unlink(file_name); + + snprintf(buf, sizeof(buf), "%s%s", file_name, ".s"); + if (LLVMTargetMachineEmitToFile(comp_ctx->target_machine, + comp_ctx->module, + buf, LLVMAssemblyFile, + &err) != 0) { + if (err) { + LLVMDisposeMessage(err); + err = NULL; + } + aot_set_last_error("emit elf to object file failed."); + goto fail; + } + + /* call arc gcc to compile assembly file to object file */ + /* TODO: get arc gcc from environment variable firstly + and check whether the toolchain exists actually */ + snprintf(buf, sizeof(buf), "%s%s%s%s%s%s", + "/opt/zephyr-sdk/arc-zephyr-elf/bin/arc-zephyr-elf-gcc ", + "-mcpu=arcem -o ", file_name, ".o -c ", file_name, ".s"); + /* TODO: use try..catch to handle possible exceptions */ + ret = system(buf); + /* remove temp assembly file */ + snprintf(buf, sizeof(buf), "%s%s", file_name, ".s"); + unlink(buf); + + if (ret != 0) { + aot_set_last_error("failed to compile asm file to obj file " + "with arc gcc toolchain."); + goto fail; + } + + /* create memory buffer from object file */ + snprintf(buf, sizeof(buf), "%s%s", file_name, ".o"); + ret = LLVMCreateMemoryBufferWithContentsOfFile(buf, + &obj_data->mem_buf, + &err); + /* remove temp object file */ + snprintf(buf, sizeof(buf), "%s%s",file_name, ".o"); + unlink(buf); + + if (ret != 0) { + if (err) { + LLVMDisposeMessage(err); + err = NULL; + } + aot_set_last_error("create mem buffer with file failed."); + goto fail; + } + } + else if (LLVMTargetMachineEmitToMemoryBuffer(comp_ctx->target_machine, + comp_ctx->module, + LLVMObjectFile, &err, + &obj_data->mem_buf) != 0) { if (err) { LLVMDisposeMessage(err); err = NULL; @@ -2242,7 +2366,8 @@ aot_emit_aot_file_buf(AOTCompContext *comp_ctx, || !aot_emit_text_section(buf, buf_end, &offset, comp_data, obj_data) || !aot_emit_func_section(buf, buf_end, &offset, comp_data, obj_data) || !aot_emit_export_section(buf, buf_end, &offset, comp_data, obj_data) - || !aot_emit_relocation_section(buf, buf_end, &offset, comp_data, obj_data)) + || !aot_emit_relocation_section(buf, buf_end, &offset, comp_data, obj_data) + || !aot_emit_native_symbol(buf, buf_end, &offset, comp_ctx)) goto fail2; #if 0 diff --git a/core/iwasm/compilation/aot_emit_exception.c b/core/iwasm/compilation/aot_emit_exception.c index b6eb8429c..5671a12e8 100644 --- a/core/iwasm/compilation/aot_emit_exception.c +++ b/core/iwasm/compilation/aot_emit_exception.c @@ -68,6 +68,24 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return false; } } + else if (comp_ctx->is_indirect_mode) { + int32 func_index; + if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { + aot_set_last_error("create LLVM function type failed."); + return false; + } + + func_index = aot_get_native_symbol_index( + comp_ctx, "aot_set_exception_with_id"); + if (func_index < 0) { + return false; + } + if (!(func = + aot_get_func_from_table(comp_ctx, func_ctx->native_symbol, + func_ptr_type, func_index))) { + return false; + } + } else { /* Create LLVM function with external function pointer */ if (!(func = LLVMGetNamedFunction(comp_ctx->module, diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index a0fe2412f..92647918e 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -168,10 +168,26 @@ call_aot_invoke_native_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return false; } } + else if (comp_ctx->is_indirect_mode) { + int32 func_index; + if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { + aot_set_last_error("create LLVM function type failed."); + return false; + } + func_index = + aot_get_native_symbol_index(comp_ctx, func_name); + if (func_index < 0) { + return false; + } + if (!(func = aot_get_func_from_table(comp_ctx, func_ctx->native_symbol, + func_ptr_type, func_index))) { + return false; + } + } else { if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name)) - && !(func = LLVMAddFunction(comp_ctx->module, - func_name, func_type))) { + && !(func = + LLVMAddFunction(comp_ctx->module, func_name, func_type))) { aot_set_last_error("add LLVM function failed."); return false; } @@ -547,7 +563,22 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } else { - func = func_ctxes[func_idx - import_func_count]->func; + if (comp_ctx->is_indirect_mode) { + LLVMTypeRef func_ptr_type; + + if (!(func_ptr_type = LLVMPointerType( + func_ctxes[func_idx - import_func_count]->func_type, 0))) { + aot_set_last_error("construct func ptr type failed."); + goto fail; + } + if (!(func = aot_get_func_from_table(comp_ctx, func_ctx->func_ptrs, + func_ptr_type, func_idx))) { + goto fail; + } + } + else { + func = func_ctxes[func_idx - import_func_count]->func; + } aot_func = func_ctxes[func_idx - import_func_count]->aot_func; callee_cell_num = aot_func->param_cell_num + aot_func->local_cell_num + 1; @@ -650,6 +681,22 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return false; } } + else if (comp_ctx->is_indirect_mode) { + int32 func_index; + if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { + aot_set_last_error("create LLVM function type failed."); + return false; + } + func_index = + aot_get_native_symbol_index(comp_ctx, func_name); + if (func_index < 0) { + return false; + } + if (!(func = aot_get_func_from_table(comp_ctx, func_ctx->native_symbol, + func_ptr_type, func_index))) { + return false; + } + } else { if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name)) && !(func = LLVMAddFunction(comp_ctx->module, diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index 0a506143c..d7b194ce2 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -651,6 +651,7 @@ aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) LLVMValueRef mem_size = get_memory_curr_page_count(comp_ctx, func_ctx); LLVMValueRef delta, param_values[2], ret_value, func, value; LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type; + int32 func_index; if (!mem_size) return false; @@ -679,6 +680,21 @@ aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) return false; } } + else if (comp_ctx->is_indirect_mode) { + if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { + aot_set_last_error("create LLVM function type failed."); + return false; + } + func_index = + aot_get_native_symbol_index(comp_ctx, "aot_enlarge_memory"); + if (func_index < 0) { + return false; + } + if (!(func = aot_get_func_from_table(comp_ctx, func_ctx->native_symbol, + func_ptr_type, func_index))) { + return false; + } + } else { char *func_name = "aot_enlarge_memory"; /* AOT mode, delcare the function */ @@ -715,7 +731,6 @@ fail: return false; } - #if WASM_ENABLE_BULK_MEMORY != 0 static LLVMValueRef @@ -924,6 +939,8 @@ aot_compile_op_memory_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) check_bulk_memory_overflow(comp_ctx, func_ctx, dst, len))) return false; + /* TODO: lookup func ptr of "memmove" to call for XIP mode */ + if (!(res = LLVMBuildMemMove(comp_ctx->builder, dst_addr, 1, src_addr, 1, len))) { aot_set_last_error("llvm build memmove failed."); @@ -947,7 +964,13 @@ aot_compile_op_memory_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) check_bulk_memory_overflow(comp_ctx, func_ctx, dst, len))) return false; - val = LLVMBuildIntCast2(comp_ctx->builder, val, INT8_TYPE, true, "mem_set_value"); + if (!(val = LLVMBuildIntCast2(comp_ctx->builder, val, INT8_TYPE, + true, "mem_set_value"))) { + aot_set_last_error("llvm build int cast2 failed."); + return false; + } + + /* TODO: lookup func ptr of "memset" to call for XIP mode */ if (!(res = LLVMBuildMemSet(comp_ctx->builder, dst_addr, val, len, 1))) { diff --git a/core/iwasm/compilation/aot_emit_numberic.c b/core/iwasm/compilation/aot_emit_numberic.c index b1c1e0e79..df83bc25d 100644 --- a/core/iwasm/compilation/aot_emit_numberic.c +++ b/core/iwasm/compilation/aot_emit_numberic.c @@ -7,6 +7,7 @@ #include "aot_emit_exception.h" #include "aot_emit_control.h" #include "../aot/aot_runtime.h" +#include "../aot/aot_intrinsic.h" #include @@ -138,6 +139,7 @@ /* Call llvm constrained floating-point intrinsic */ static LLVMValueRef call_llvm_float_experimental_constrained_intrinsic(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, bool is_f32, const char *intrinsic, ...) @@ -145,14 +147,18 @@ call_llvm_float_experimental_constrained_intrinsic(AOTCompContext *comp_ctx, va_list param_value_list; LLVMValueRef ret; LLVMTypeRef param_types[4], ret_type = is_f32 ? F32_TYPE : F64_TYPE; + int param_count = ((comp_ctx->disable_llvm_intrinsics == false) + || aot_intrinsic_check_capability(comp_ctx, intrinsic)) + ? 4 : 2; param_types[0] = param_types[1] = ret_type; param_types[2] = param_types[3] = MD_TYPE; va_start(param_value_list, intrinsic); - ret = aot_call_llvm_intrinsic_v(comp_ctx, intrinsic, ret_type, param_types, - 4, param_value_list); + ret = + aot_call_llvm_intrinsic_v(comp_ctx, func_ctx, intrinsic, ret_type, + param_types, param_count, param_value_list); va_end(param_value_list); @@ -162,6 +168,7 @@ call_llvm_float_experimental_constrained_intrinsic(AOTCompContext *comp_ctx, /* Call llvm constrained libm-equivalent intrinsic */ static LLVMValueRef call_llvm_libm_experimental_constrained_intrinsic(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, bool is_f32, const char *intrinsic, ...) @@ -175,7 +182,7 @@ call_llvm_libm_experimental_constrained_intrinsic(AOTCompContext *comp_ctx, va_start(param_value_list, intrinsic); - ret = aot_call_llvm_intrinsic_v(comp_ctx, intrinsic, ret_type, param_types, + ret = aot_call_llvm_intrinsic_v(comp_ctx, func_ctx, intrinsic, ret_type, param_types, 3, param_value_list); va_end(param_value_list); @@ -185,6 +192,7 @@ call_llvm_libm_experimental_constrained_intrinsic(AOTCompContext *comp_ctx, static LLVMValueRef compile_op_float_min_max(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, bool is_f32, LLVMValueRef left, LLVMValueRef right, @@ -230,8 +238,9 @@ compile_op_float_min_max(AOTCompContext *comp_ctx, return NULL; } - if (!(cmp = aot_call_llvm_intrinsic(comp_ctx, intrinsic, ret_type, - param_types, 2, left, right))) + if (!(cmp = + aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic, ret_type, + param_types, 2, left, right))) return NULL; if (!(cmp = LLVMBuildSelect(comp_ctx->builder, @@ -266,13 +275,14 @@ typedef enum BitCountType { POP_CNT64 } BitCountType; -static char *bit_cnt_llvm_intrinsic[] = { "llvm.ctlz.i32", - "llvm.ctlz.i64", - "llvm.cttz.i32", - "llvm.cttz.i64", - "llvm.ctpop.i32", - "llvm.ctpop.i64", - }; +static char *bit_cnt_llvm_intrinsic[] = { + "llvm.ctlz.i32", + "llvm.ctlz.i64", + "llvm.cttz.i32", + "llvm.cttz.i64", + "llvm.ctpop.i32", + "llvm.ctpop.i64", +}; static bool aot_compile_int_bit_count(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, @@ -290,6 +300,7 @@ aot_compile_int_bit_count(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Call the LLVM intrinsic function */ if (type < POP_CNT32) DEF_INT_UNARY_OP(aot_call_llvm_intrinsic(comp_ctx, + func_ctx, bit_cnt_llvm_intrinsic[type], ret_type, param_types, @@ -299,6 +310,7 @@ aot_compile_int_bit_count(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, NULL); else DEF_INT_UNARY_OP(aot_call_llvm_intrinsic(comp_ctx, + func_ctx, bit_cnt_llvm_intrinsic[type], ret_type, param_types, @@ -823,6 +835,7 @@ compile_op_float_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, else DEF_FP_BINARY_OP(call_llvm_float_experimental_constrained_intrinsic( comp_ctx, + func_ctx, is_f32, (is_f32 ? "llvm.experimental.constrained.fadd.f32" @@ -840,6 +853,7 @@ compile_op_float_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, else DEF_FP_BINARY_OP(call_llvm_float_experimental_constrained_intrinsic( comp_ctx, + func_ctx, is_f32, (is_f32 ? "llvm.experimental.constrained.fsub.f32" @@ -857,6 +871,7 @@ compile_op_float_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, else DEF_FP_BINARY_OP(call_llvm_float_experimental_constrained_intrinsic( comp_ctx, + func_ctx, is_f32, (is_f32 ? "llvm.experimental.constrained.fmul.f32" @@ -874,6 +889,7 @@ compile_op_float_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, else DEF_FP_BINARY_OP(call_llvm_float_experimental_constrained_intrinsic( comp_ctx, + func_ctx, is_f32, (is_f32 ? "llvm.experimental.constrained.fdiv.f32" @@ -886,6 +902,7 @@ compile_op_float_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return true; case FLOAT_MIN: DEF_FP_BINARY_OP(compile_op_float_min_max(comp_ctx, + func_ctx, is_f32, left, right, @@ -894,6 +911,7 @@ compile_op_float_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return true; case FLOAT_MAX: DEF_FP_BINARY_OP(compile_op_float_min_max(comp_ctx, + func_ctx, is_f32, left, right, @@ -912,6 +930,7 @@ fail: static LLVMValueRef call_llvm_float_math_intrinsic(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, bool is_f32, const char *intrinsic, ...) @@ -924,8 +943,8 @@ call_llvm_float_math_intrinsic(AOTCompContext *comp_ctx, va_start(param_value_list, intrinsic); - ret = aot_call_llvm_intrinsic_v(comp_ctx, intrinsic, ret_type, ¶m_type, - 1, param_value_list); + ret = aot_call_llvm_intrinsic_v(comp_ctx, func_ctx, intrinsic, ret_type, + ¶m_type, 1, param_value_list); va_end(param_value_list); @@ -939,6 +958,7 @@ compile_op_float_math(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, switch (math_op) { case FLOAT_ABS: DEF_FP_UNARY_OP(call_llvm_float_math_intrinsic(comp_ctx, + func_ctx, is_f32, is_f32 ? "llvm.fabs.f32" : "llvm.fabs.f64", @@ -952,6 +972,7 @@ compile_op_float_math(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, case FLOAT_CEIL: DEF_FP_UNARY_OP(call_llvm_float_math_intrinsic(comp_ctx, + func_ctx, is_f32, is_f32 ? "llvm.ceil.f32" : "llvm.ceil.f64", @@ -960,6 +981,7 @@ compile_op_float_math(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return true; case FLOAT_FLOOR: DEF_FP_UNARY_OP(call_llvm_float_math_intrinsic(comp_ctx, + func_ctx, is_f32, is_f32 ? "llvm.floor.f32": "llvm.floor.f64", @@ -968,6 +990,7 @@ compile_op_float_math(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return true; case FLOAT_TRUNC: DEF_FP_UNARY_OP(call_llvm_float_math_intrinsic(comp_ctx, + func_ctx, is_f32, is_f32 ? "llvm.trunc.f32" : "llvm.trunc.f64", @@ -976,6 +999,7 @@ compile_op_float_math(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return true; case FLOAT_NEAREST: DEF_FP_UNARY_OP(call_llvm_float_math_intrinsic(comp_ctx, + func_ctx, is_f32, is_f32 ? "llvm.rint.f32" : "llvm.rint.f64", @@ -983,8 +1007,10 @@ compile_op_float_math(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, NULL); return true; case FLOAT_SQRT: - if (is_targeting_soft_float(comp_ctx, is_f32)) + if (is_targeting_soft_float(comp_ctx, is_f32) + || comp_ctx->disable_llvm_intrinsics) DEF_FP_UNARY_OP(call_llvm_float_math_intrinsic(comp_ctx, + func_ctx, is_f32, is_f32 ? "llvm.sqrt.f32" : "llvm.sqrt.f64", @@ -993,6 +1019,7 @@ compile_op_float_math(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, else DEF_FP_UNARY_OP(call_llvm_libm_experimental_constrained_intrinsic( comp_ctx, + func_ctx, is_f32, (is_f32 ? "llvm.experimental.constrained.sqrt.f32" @@ -1022,6 +1049,7 @@ compile_float_copysign(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, param_types[0] = param_types[1] = ret_type = is_f32 ? F32_TYPE : F64_TYPE; DEF_FP_BINARY_OP(aot_call_llvm_intrinsic(comp_ctx, + func_ctx, is_f32 ? "llvm.copysign.f32" : "llvm.copysign.f64", ret_type, diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 86945f471..1275a21be 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -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; +} diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index 0ed1c33d5..2eade1a00 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -116,6 +116,7 @@ typedef struct AOTMemInfo { typedef struct AOTFuncContext { AOTFunc *aot_func; LLVMValueRef func; + LLVMTypeRef func_type; AOTBlockStack block_stack; LLVMValueRef exec_env; @@ -124,6 +125,7 @@ typedef struct AOTFuncContext { LLVMValueRef native_stack_bound; LLVMValueRef aux_stack_bound; LLVMValueRef aux_stack_bottom; + LLVMValueRef native_symbol; LLVMValueRef last_alloca; LLVMValueRef func_ptrs; @@ -221,10 +223,17 @@ typedef struct AOTCompContext { char target_arch[16]; unsigned pointer_size; + /* Hardware intrinsic compability flags */ + uint64 flags[8]; + /* LLVM execution engine required by JIT */ LLVMExecutionEngineRef exec_engine; bool is_jit_mode; + /* AOT indirect mode flag & symbol list */ + bool is_indirect_mode; + bh_list native_symbols; + /* Bulk memory feature */ bool enable_bulk_memory; @@ -249,6 +258,9 @@ typedef struct AOTCompContext { /* Reference Types */ bool enable_ref_types; + /* Disable LLVM built-in intrinsics */ + bool disable_llvm_intrinsics; + /* Whether optimize the JITed code */ bool optimize; @@ -283,10 +295,12 @@ enum { typedef struct AOTCompOption{ bool is_jit_mode; + bool is_indirect_mode; char *target_arch; char *target_abi; char *target_cpu; char *cpu_features; + bool is_sgx_platform; bool enable_bulk_memory; bool enable_thread_mgr; bool enable_tail_call; @@ -294,7 +308,7 @@ typedef struct AOTCompOption{ bool enable_ref_types; bool enable_aux_stack_check; bool enable_aux_stack_frame; - bool is_sgx_platform; + bool disable_llvm_intrinsics; uint32 opt_level; uint32 size_level; uint32 output_format; @@ -308,6 +322,9 @@ aot_create_comp_context(AOTCompData *comp_data, void aot_destroy_comp_context(AOTCompContext *comp_ctx); +int32 +aot_get_native_symbol_index(AOTCompContext *comp_ctx, const char *symbol); + bool aot_compile_wasm(AOTCompContext *comp_ctx); @@ -361,6 +378,7 @@ aot_build_zero_function_ret(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, @@ -369,12 +387,19 @@ 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, int param_count, va_list param_value_list); +LLVMValueRef +aot_get_func_from_table(const AOTCompContext *comp_ctx, + LLVMValueRef base, + LLVMTypeRef func_type, + int32 index); + bool aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str); diff --git a/core/iwasm/compilation/simd/simd_access_lanes.c b/core/iwasm/compilation/simd/simd_access_lanes.c index 8f1489c84..1db75a838 100644 --- a/core/iwasm/compilation/simd/simd_access_lanes.c +++ b/core/iwasm/compilation/simd/simd_access_lanes.c @@ -138,7 +138,7 @@ aot_compile_simd_swizzle_x86(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) param_types[0] = V128_i8x16_TYPE; param_types[1] = V128_i8x16_TYPE; if (!(result = aot_call_llvm_intrinsic( - comp_ctx, "llvm.x86.ssse3.pshuf.b.128", V128_i8x16_TYPE, + comp_ctx, func_ctx, "llvm.x86.ssse3.pshuf.b.128", V128_i8x16_TYPE, param_types, 2, vector, mask))) { HANDLE_FAILURE("LLVMBuildCall"); goto fail; diff --git a/core/iwasm/compilation/simd/simd_bitmask_extracts.c b/core/iwasm/compilation/simd/simd_bitmask_extracts.c index 79565cfc2..4e0534e06 100644 --- a/core/iwasm/compilation/simd/simd_bitmask_extracts.c +++ b/core/iwasm/compilation/simd/simd_bitmask_extracts.c @@ -69,7 +69,7 @@ simd_build_bitmask(const AOTCompContext *comp_ctx, } param_types[0] = vector_ext_type; - if (!(result = aot_call_llvm_intrinsic(comp_ctx, intrinsic, I32_TYPE, + if (!(result = aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic, I32_TYPE, param_types, 1, result))) { HANDLE_FAILURE("LLVMBuildCall"); goto fail; diff --git a/core/iwasm/compilation/simd/simd_bool_reductions.c b/core/iwasm/compilation/simd/simd_bool_reductions.c index c2abb3027..503f3ebef 100644 --- a/core/iwasm/compilation/simd/simd_bool_reductions.c +++ b/core/iwasm/compilation/simd/simd_bool_reductions.c @@ -41,7 +41,7 @@ simd_any_true(AOTCompContext *comp_ctx, goto fail; } - if (!(result = aot_call_llvm_intrinsic(comp_ctx, intrinsic, element_type, + if (!(result = aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic, element_type, &vector_type, 1, non_zero))) { HANDLE_FAILURE("LLVMBuildCall"); goto fail; @@ -128,7 +128,7 @@ simd_all_true(AOTCompContext *comp_ctx, goto fail; } - if (!(result = aot_call_llvm_intrinsic(comp_ctx, intrinsic, element_type, + if (!(result = aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic, element_type, &vector_type, 1, is_zero))) { HANDLE_FAILURE("LLVMBuildCall"); goto fail; diff --git a/core/iwasm/compilation/simd/simd_conversions.c b/core/iwasm/compilation/simd/simd_conversions.c index d330c38a3..67500d017 100644 --- a/core/iwasm/compilation/simd/simd_conversions.c +++ b/core/iwasm/compilation/simd/simd_conversions.c @@ -38,7 +38,7 @@ simd_integer_narrow(AOTCompContext *comp_ctx, } if (!(result = - aot_call_llvm_intrinsic(comp_ctx, instrinsic, out_vector_type, + aot_call_llvm_intrinsic(comp_ctx, func_ctx, instrinsic, out_vector_type, param_types, 2, vector1, vector2))) { HANDLE_FAILURE("LLVMBuildCall"); goto fail; diff --git a/core/iwasm/compilation/simd/simd_floating_point.c b/core/iwasm/compilation/simd/simd_floating_point.c index e26b3a518..1a819c9fd 100644 --- a/core/iwasm/compilation/simd/simd_floating_point.c +++ b/core/iwasm/compilation/simd/simd_floating_point.c @@ -191,7 +191,7 @@ simd_v128_float_intrinsic(AOTCompContext *comp_ctx, goto fail; } - if (!(result = aot_call_llvm_intrinsic(comp_ctx, intrinsic, vector_type, + if (!(result = aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic, vector_type, param_types, 1, number))) { HANDLE_FAILURE("LLVMBuildCall"); goto fail; diff --git a/core/iwasm/compilation/simd/simd_sat_int_arith.c b/core/iwasm/compilation/simd/simd_sat_int_arith.c index d8f85da76..1f2b5b353 100644 --- a/core/iwasm/compilation/simd/simd_sat_int_arith.c +++ b/core/iwasm/compilation/simd/simd_sat_int_arith.c @@ -32,7 +32,7 @@ simd_v128_integer_arith(AOTCompContext *comp_ctx, param_types[1] = vector_type; if (!(result = aot_call_llvm_intrinsic( - comp_ctx, is_signed ? intrinsics_s_u[0] : intrinsics_s_u[1], + comp_ctx, func_ctx, is_signed ? intrinsics_s_u[0] : intrinsics_s_u[1], vector_type, param_types, 2, lhs, rhs))) { HANDLE_FAILURE("LLVMBuildCall"); goto fail; diff --git a/core/iwasm/include/aot_export.h b/core/iwasm/include/aot_export.h index eb0aba05c..cc7355dc2 100644 --- a/core/iwasm/include/aot_export.h +++ b/core/iwasm/include/aot_export.h @@ -35,10 +35,12 @@ enum { typedef struct AOTCompOption{ bool is_jit_mode; + bool is_indirect_mode; char *target_arch; char *target_abi; char *target_cpu; char *cpu_features; + bool is_sgx_platform; bool enable_bulk_memory; bool enable_thread_mgr; bool enable_tail_call; @@ -46,7 +48,7 @@ typedef struct AOTCompOption{ bool enable_ref_types; bool enable_aux_stack_check; bool enable_aux_stack_frame; - bool is_sgx_platform; + bool disable_llvm_intrinsics; uint32_t opt_level; uint32_t size_level; uint32_t output_format; diff --git a/core/shared/platform/common/math/math.c b/core/shared/platform/common/math/math.c index 4f6a7ce7c..53fcafed4 100644 --- a/core/shared/platform/common/math/math.c +++ b/core/shared/platform/common/math/math.c @@ -132,76 +132,110 @@ static union { /* Get two 32 bit ints from a double. */ -#define EXTRACT_WORDS_L(ix0,ix1,d) \ - do { \ - ieee_double_shape_type_little ew_u; \ - ew_u.value = (d); \ - (ix0) = ew_u.parts.msw; \ - (ix1) = ew_u.parts.lsw; \ +#define EXTRACT_WORDS_L(ix0,ix1,d) \ + do { \ + ieee_double_shape_type_little ew_u; \ + ew_u.value = (d); \ + (ix0) = ew_u.parts.msw; \ + (ix1) = ew_u.parts.lsw; \ } while (0) /* Set a double from two 32 bit ints. */ -#define INSERT_WORDS_L(d,ix0,ix1) \ - do { \ - ieee_double_shape_type_little iw_u; \ - iw_u.parts.msw = (ix0); \ - iw_u.parts.lsw = (ix1); \ - (d) = iw_u.value; \ +#define INSERT_WORDS_L(d,ix0,ix1) \ + do { \ + ieee_double_shape_type_little iw_u; \ + iw_u.parts.msw = (ix0); \ + iw_u.parts.lsw = (ix1); \ + (d) = iw_u.value; \ } while (0) /* Get two 32 bit ints from a double. */ -#define EXTRACT_WORDS_B(ix0,ix1,d) \ - do { \ - ieee_double_shape_type_big ew_u; \ - ew_u.value = (d); \ - (ix0) = ew_u.parts.msw; \ - (ix1) = ew_u.parts.lsw; \ +#define EXTRACT_WORDS_B(ix0,ix1,d) \ + do { \ + ieee_double_shape_type_big ew_u; \ + ew_u.value = (d); \ + (ix0) = ew_u.parts.msw; \ + (ix1) = ew_u.parts.lsw; \ } while (0) /* Set a double from two 32 bit ints. */ -#define INSERT_WORDS_B(d,ix0,ix1) \ - do { \ - ieee_double_shape_type_big iw_u; \ - iw_u.parts.msw = (ix0); \ - iw_u.parts.lsw = (ix1); \ - (d) = iw_u.value; \ +#define INSERT_WORDS_B(d,ix0,ix1) \ + do { \ + ieee_double_shape_type_big iw_u; \ + iw_u.parts.msw = (ix0); \ + iw_u.parts.lsw = (ix1); \ + (d) = iw_u.value; \ } while (0) /* Get the more significant 32 bit int from a double. */ -#define GET_HIGH_WORD_L(i,d) \ - do { \ - ieee_double_shape_type_little gh_u; \ - gh_u.value = (d); \ - (i) = gh_u.parts.msw; \ +#define GET_HIGH_WORD_L(i,d) \ + do { \ + ieee_double_shape_type_little gh_u; \ + gh_u.value = (d); \ + (i) = gh_u.parts.msw; \ } while (0) /* Get the more significant 32 bit int from a double. */ -#define GET_HIGH_WORD_B(i,d) \ - do { \ - ieee_double_shape_type_big gh_u; \ - gh_u.value = (d); \ - (i) = gh_u.parts.msw; \ +#define GET_HIGH_WORD_B(i,d) \ + do { \ + ieee_double_shape_type_big gh_u; \ + gh_u.value = (d); \ + (i) = gh_u.parts.msw; \ } while (0) /* Set the more significant 32 bits of a double from an int. */ -#define SET_HIGH_WORD_L(d,v) \ - do { \ - ieee_double_shape_type_little sh_u; \ - sh_u.value = (d); \ - sh_u.parts.msw = (v); \ - (d) = sh_u.value; \ +#define SET_HIGH_WORD_L(d,v) \ + do { \ + ieee_double_shape_type_little sh_u; \ + sh_u.value = (d); \ + sh_u.parts.msw = (v); \ + (d) = sh_u.value; \ } while (0) /* Set the more significant 32 bits of a double from an int. */ -#define SET_HIGH_WORD_B(d,v) \ - do { \ - ieee_double_shape_type_big sh_u; \ - sh_u.value = (d); \ - sh_u.parts.msw = (v); \ - (d) = sh_u.value; \ +#define SET_HIGH_WORD_B(d,v) \ + do { \ + ieee_double_shape_type_big sh_u; \ + sh_u.value = (d); \ + sh_u.parts.msw = (v); \ + (d) = sh_u.value; \ + } while (0) + +/* Set the less significant 32 bits of a double from an int. */ +#define SET_LOW_WORD_L(d,v) \ + do { \ + ieee_double_shape_type_little sh_u; \ + sh_u.value = (d); \ + sh_u.parts.lsw = (v); \ + (d) = sh_u.value; \ + } while (0) + +/* Set the more significant 32 bits of a double from an int. */ +#define SET_LOW_WORD_B(d,v) \ + do { \ + ieee_double_shape_type_big sh_u; \ + sh_u.value = (d); \ + sh_u.parts.lsw = (v); \ + (d) = sh_u.value; \ + } while (0) + +/* Get the less significant 32 bit int from a double. */ +#define GET_LOW_WORD_L(i,d) \ + do { \ + ieee_double_shape_type_little gl_u; \ + gl_u.value = (d); \ + (i) = gl_u.parts.lsw; \ + } while (0) + +/* Get the less significant 32 bit int from a double. */ +#define GET_LOW_WORD_B(i,d) \ + do { \ + ieee_double_shape_type_big gl_u; \ + gl_u.value = (d); \ + (i) = gl_u.parts.lsw; \ } while (0) /* @@ -262,6 +296,22 @@ typedef union SET_HIGH_WORD_B(d,v); \ } while (0) +#define GET_LOW_WORD(d,v) \ + do { \ + if (is_little_endian()) \ + GET_LOW_WORD_L(d,v); \ + else \ + GET_LOW_WORD_B(d,v); \ + } while (0) + +#define SET_LOW_WORD(d,v) \ + do { \ + if (is_little_endian()) \ + SET_LOW_WORD_L(d,v); \ + else \ + SET_LOW_WORD_B(d,v); \ + } while (0) + #define __HI(x) (is_little_endian() ? __HIL(x) : __HIB(x)) #define __LO(x) (is_little_endian() ? __LOL(x) : __LOB(x)) @@ -314,12 +364,219 @@ TWO52[2]={ -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */ }; +#ifdef __STDC__ +static const double +#else +static double +#endif +atanhi[] = { + 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ + 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ + 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */ + 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */ +}; + +#ifdef __STDC__ +static const double +#else +static double +#endif +atanlo[] = { + 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */ + 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */ + 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */ + 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */ +}; + +#ifdef __STDC__ +static const double +#else +static double +#endif +aT[] = { + 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */ + -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */ + 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */ + -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */ + 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */ + -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */ + 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */ + -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */ + 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */ + -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */ + 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ +}; + +#ifdef __STDC__ +static const double +#else +static double +#endif +zero = 0.0, +pi_o_4 = 7.8539816339744827900E-01, /* 0x3FE921FB, 0x54442D18 */ +pi_o_2 = 1.5707963267948965580E+00, /* 0x3FF921FB, 0x54442D18 */ +pi = 3.1415926535897931160E+00, /* 0x400921FB, 0x54442D18 */ +pi_lo = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ + +#ifdef __STDC__ +static const double +#else +static double +#endif +bp[] = {1.0, 1.5,}, +dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */ +dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */ +two = 2.0, +two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */ +two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */ +twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */ + /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ +L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */ +L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */ +L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */ +L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */ +L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */ +L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */ +P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ +P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ +P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ +P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ +P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */ +lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ +lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */ +lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */ +ovt = 8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */ +cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */ +cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */ +cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/ +ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */ +ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/ +ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/ + static double freebsd_sqrt(double x); static double freebsd_floor(double x); static double freebsd_ceil(double x); static double freebsd_fabs(double x); static double freebsd_rint(double x); static int freebsd_isnan(double x); +static double freebsd_atan(double x); +static double freebsd_atan2(double y, double x); + + +static double freebsd_atan(double x) +{ + double w,s1,s2,z; + int32_t ix,hx,id; + + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x44100000) { /* if |x| >= 2^66 */ + u_int32_t low; + GET_LOW_WORD(low,x); + if(ix>0x7ff00000|| + (ix==0x7ff00000&&(low!=0))) + return x+x; /* NaN */ + if(hx>0) return atanhi[3]+*(volatile double *)&atanlo[3]; + else return -atanhi[3]-*(volatile double *)&atanlo[3]; + } if (ix < 0x3fdc0000) { /* |x| < 0.4375 */ + if (ix < 0x3e400000) { /* |x| < 2^-27 */ + if(huge+x>one) return x; /* raise inexact */ + } + id = -1; + } else { + x = freebsd_fabs(x); + if (ix < 0x3ff30000) { /* |x| < 1.1875 */ + if (ix < 0x3fe60000) { /* 7/16 <=|x|<11/16 */ + id = 0; x = (2.0*x-one)/(2.0+x); + } else { /* 11/16<=|x|< 19/16 */ + id = 1; x = (x-one)/(x+one); + } + } else { + if (ix < 0x40038000) { /* |x| < 2.4375 */ + id = 2; x = (x-1.5)/(one+1.5*x); + } else { /* 2.4375 <= |x| < 2^66 */ + id = 3; x = -1.0/x; + } + }} + /* end of argument reduction */ + z = x*x; + w = z*z; + /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ + s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10]))))); + s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9])))); + if (id<0) return x - x*(s1+s2); + else { + z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x); + return (hx<0)? -z:z; + } +} + + +static double freebsd_atan2(double y, double x) +{ + double z; + int32_t k,m,hx,hy,ix,iy; + u_int32_t lx,ly; + + EXTRACT_WORDS(hx,lx,x); + ix = hx&0x7fffffff; + EXTRACT_WORDS(hy,ly,y); + iy = hy&0x7fffffff; + if(((ix|((lx|-lx)>>31))>0x7ff00000)|| + ((iy|((ly|-ly)>>31))>0x7ff00000)) /* x or y is NaN */ + return x+y; + if(hx==0x3ff00000&&lx==0) return freebsd_atan(y); /* x=1.0 */ + m = ((hy>>31)&1)|((hx>>30)&2); /* 2*sign(x)+sign(y) */ + + /* when y = 0 */ + if((iy|ly)==0) { + switch(m) { + case 0: + case 1: return y; /* atan(+-0,+anything)=+-0 */ + case 2: return pi+tiny;/* atan(+0,-anything) = pi */ + case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */ + } + } + /* when x = 0 */ + if((ix|lx)==0) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny; + + /* when x is INF */ + if(ix==0x7ff00000) { + if(iy==0x7ff00000) { + switch(m) { + case 0: return pi_o_4+tiny;/* atan(+INF,+INF) */ + case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */ + case 2: return 3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/ + case 3: return -3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/ + } + } else { + switch(m) { + case 0: return zero ; /* atan(+...,+INF) */ + case 1: return -zero ; /* atan(-...,+INF) */ + case 2: return pi+tiny ; /* atan(+...,-INF) */ + case 3: return -pi-tiny ; /* atan(-...,-INF) */ + } + } + } + /* when y is INF */ + if(iy==0x7ff00000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny; + + /* compute y/x */ + k = (iy-ix)>>20; + if(k > 60) { /* |y/x| > 2**60 */ + z=pi_o_2+0.5*pi_lo; + m&=1; + } + else if(hx<0&&k<-60) z=0.0; /* 0 > |y|/x > -2**-60 */ + else z=freebsd_atan(fabs(y/x)); /* safe to do y/x */ + switch (m) { + case 0: return z ; /* atan(+,+) */ + case 1: return -z ; /* atan(-,+) */ + case 2: return pi-(z-pi_lo);/* atan(+,-) */ + default: /* case 3 */ + return (z-pi_lo)-pi;/* atan(-,-) */ + } +} static double freebsd_sqrt(double x) /* wrapper sqrt */ { @@ -777,6 +1034,271 @@ freebsd_fmaxf(float x, float y) return (x > y ? x : y); } +static double +freebsd_copysign(double x, double y) +{ + u_int32_t hx,hy; + GET_HIGH_WORD(hx,x); + GET_HIGH_WORD(hy,y); + SET_HIGH_WORD(x,(hx&0x7fffffff)|(hy&0x80000000)); + return x; +} + +static double +freebsd_scalbn(double x, int n) +{ + int32_t k,hx,lx; + EXTRACT_WORDS(hx,lx,x); + k = (hx&0x7ff00000)>>20; /* extract exponent */ + if (k==0) { /* 0 or subnormal x */ + if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */ + x *= two54; + GET_HIGH_WORD(hx,x); + k = ((hx&0x7ff00000)>>20) - 54; + if (n< -50000) return tiny*x; /*underflow*/ + } + if (k==0x7ff) return x+x; /* NaN or Inf */ + k = k+n; + if (k > 0x7fe) return huge*freebsd_copysign(huge,x); /* overflow */ + if (k > 0) /* normal result */ + {SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); return x;} + if (k <= -54) { + if (n > 50000) /* in case integer overflow in n+k */ + return huge*freebsd_copysign(huge,x); /*overflow*/ + else return tiny*freebsd_copysign(tiny,x); /*underflow*/ + } + k += 54; /* subnormal result */ + SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); + return x*twom54; +} + +static double +freebsd_pow(double x, double y) +{ + double z,ax,z_h,z_l,p_h,p_l; + double y1,t1,t2,r,s,t,u,v,w; + int32_t i,j,k,yisint,n; + int32_t hx,hy,ix,iy; + u_int32_t lx,ly; + + EXTRACT_WORDS(hx,lx,x); + EXTRACT_WORDS(hy,ly,y); + ix = hx&0x7fffffff; iy = hy&0x7fffffff; + + /* y==zero: x**0 = 1 */ + if((iy|ly)==0) return one; + + /* x==1: 1**y = 1, even if y is NaN */ + if (hx==0x3ff00000 && lx == 0) return one; + + /* y!=zero: result is NaN if either arg is NaN */ + if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) || + iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0))) + return (x+0.0)+(y+0.0); + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if(hx<0) { + if(iy>=0x43400000) yisint = 2; /* even integer y */ + else if(iy>=0x3ff00000) { + k = (iy>>20)-0x3ff; /* exponent */ + if(k>20) { + j = ly>>(52-k); + if((j<<(52-k))==ly) yisint = 2-(j&1); + } else if(ly==0) { + j = iy>>(20-k); + if((j<<(20-k))==iy) yisint = 2-(j&1); + } + } + } + + /* special value of y */ + if(ly==0) { + if (iy==0x7ff00000) { /* y is +-inf */ + if(((ix-0x3ff00000)|lx)==0) + return one; /* (-1)**+-inf is NaN */ + else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */ + return (hy>=0)? y: zero; + else /* (|x|<1)**-,+inf = inf,0 */ + return (hy<0)?-y: zero; + } + if(iy==0x3ff00000) { /* y is +-1 */ + if(hy<0) return one/x; else return x; + } + if(hy==0x40000000) return x*x; /* y is 2 */ + if(hy==0x40080000) return x*x*x; /* y is 3 */ + if(hy==0x40100000) { /* y is 4 */ + u = x*x; + return u*u; + } + if(hy==0x3fe00000) { /* y is 0.5 */ + if(hx>=0) /* x >= +0 */ + return sqrt(x); + } + } + + ax = fabs(x); + /* special value of x */ + if(lx==0) { + if(ix==0x7ff00000||ix==0||ix==0x3ff00000){ + z = ax; /*x is +-0,+-inf,+-1*/ + if(hy<0) z = one/z; /* z = (1/|x|) */ + if(hx<0) { + if(((ix-0x3ff00000)|yisint)==0) { + z = (z-z)/(z-z); /* (-1)**non-int is NaN */ + } else if(yisint==1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + } + + /* CYGNUS LOCAL + fdlibm-5.3 fix: This used to be + n = (hx>>31)+1; + but ANSI C says a right shift of a signed negative quantity is + implementation defined. */ + n = ((u_int32_t)hx>>31)-1; + + /* (x<0)**(non-int) is NaN */ + if((n|yisint)==0) return (x-x)/(x-x); + + s = one; /* s (sign of result -ve**odd) = -1 else = 1 */ + if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */ + + /* |y| is huge */ + if(iy>0x41e00000) { /* if |y| > 2**31 */ + if(iy>0x43f00000){ /* if |y| > 2**64, must o/uflow */ + if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny; + if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny; + } + /* over/underflow if x is not close to one */ + if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny; + if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny; + /* now |1-x| is tiny <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax-one; /* t has 20 trailing zeros */ + w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25)); + u = ivln2_h*t; /* ivln2_h has 21 sig. bits */ + v = t*ivln2_l-w*ivln2; + t1 = u+v; + SET_LOW_WORD(t1,0); + t2 = v-(t1-u); + } else { + double ss,s2,s_h,s_l,t_h,t_l; + n = 0; + /* take care subnormal number */ + if(ix<0x00100000) + {ax *= two53; n -= 53; GET_HIGH_WORD(ix,ax); } + n += ((ix)>>20)-0x3ff; + j = ix&0x000fffff; + /* determine interval */ + ix = j|0x3ff00000; /* normalize ix */ + if(j<=0x3988E) k=0; /* |x|>1)|0x20000000)+0x00080000+(k<<18)); + t_l = ax - (t_h-bp[k]); + s_l = v*((u-s_h*t_h)-s_h*t_l); + /* compute log(ax) */ + s2 = ss*ss; + r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); + r += s_l*(s_h+ss); + s2 = s_h*s_h; + t_h = 3.0+s2+r; + SET_LOW_WORD(t_h,0); + t_l = r-((t_h-3.0)-s2); + /* u+v = ss*(1+...) */ + u = s_h*t_h; + v = s_l*t_h+t_l*ss; + /* 2/(3log2)*(ss+...) */ + p_h = u+v; + SET_LOW_WORD(p_h,0); + p_l = v-(p_h-u); + z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = cp_l*p_h+p_l*cp+dp_l[k]; + /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = (double)n; + t1 = (((z_h+z_l)+dp_h[k])+t); + SET_LOW_WORD(t1,0); + t2 = z_l-(((t1-t)-dp_h[k])-z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + y1 = y; + SET_LOW_WORD(y1,0); + p_l = (y-y1)*t1+y*t2; + p_h = y1*t1; + z = p_l+p_h; + EXTRACT_WORDS(j,i,z); + if (j>=0x40900000) { /* z >= 1024 */ + if(((j-0x40900000)|i)!=0) /* if z > 1024 */ + return s*huge*huge; /* overflow */ + else { + if(p_l+ovt>z-p_h) return s*huge*huge; /* overflow */ + } + } else if((j&0x7fffffff)>=0x4090cc00 ) { /* z <= -1075 */ + if(((j-0xc090cc00)|i)!=0) /* z < -1075 */ + return s*tiny*tiny; /* underflow */ + else { + if(p_l<=z-p_h) return s*tiny*tiny; /* underflow */ + } + } + /* + * compute 2**(p_h+p_l) + */ + i = j&0x7fffffff; + k = (i>>20)-0x3ff; + n = 0; + if(i>0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */ + n = j+(0x00100000>>(k+1)); + k = ((n&0x7fffffff)>>20)-0x3ff; /* new k for n */ + t = zero; + SET_HIGH_WORD(t,n&~(0x000fffff>>k)); + n = ((n&0x000fffff)|0x00100000)>>(20-k); + if(j<0) n = -n; + p_h -= t; + } + t = p_l+p_h; + SET_LOW_WORD(t,0); + u = t*lg2_h; + v = (p_l-(t-p_h))*lg2+t*lg2_l; + z = u+v; + w = v-(z-u); + t = z*z; + t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + r = (z*t1)/(t1-two)-(w+z*w); + z = one-(r-z); + GET_HIGH_WORD(j,z); + j += (n<<20); + if((j>>20)<=0) z = freebsd_scalbn(z,n); /* subnormal output */ + else SET_HIGH_WORD(z,j); + return s*z; +} + +double atan(double x) +{ + return freebsd_atan(x); +} + +double atan2(double y, double x) +{ + return freebsd_atan2(y, x); +} + double sqrt(double x) { return freebsd_sqrt(x); @@ -863,3 +1385,14 @@ fmaxf(float x, float y) return freebsd_fmaxf(x, y); } +double +pow(double x, double y) +{ + return freebsd_pow(x, y); +} + +double +scalbn(double x, int n) +{ + return freebsd_scalbn(x, n); +} diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index 1544dd200..3da44a690 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -305,7 +305,7 @@ uint8 *os_thread_get_stack_boundary() addr += guard_size; } (void)stack_size; -#elif defined(__APPLE__) +#elif defined(__APPLE__) || defined(__NuttX__) if ((addr = (uint8*)pthread_get_stackaddr_np(self))) { stack_size = pthread_get_stacksize_np(self); if (stack_size > max_stack_size) diff --git a/core/shared/platform/zephyr/platform_internal.h b/core/shared/platform/zephyr/platform_internal.h index 256d98de7..9de485f8f 100644 --- a/core/shared/platform/zephyr/platform_internal.h +++ b/core/shared/platform/zephyr/platform_internal.h @@ -67,6 +67,8 @@ size_t strspn(const char *s, const char *accept); size_t strcspn(const char *s, const char *reject); /* math functions which are not provided by os */ +double atan(double x); +double atan2(double y, double x); double sqrt(double x); double floor(double x); double ceil(double x); @@ -83,6 +85,8 @@ float rintf(float x); float truncf(float x); int signbit(double x); int isnan(double x); +double pow(double x, double y); +double scalbn(double x, int n); unsigned long long int strtoull(const char *nptr, char **endptr, int base); double strtod(const char *nptr, char **endptr); diff --git a/core/shared/platform/zephyr/zephyr_platform.c b/core/shared/platform/zephyr/zephyr_platform.c index 42a9d00aa..4ecc828d3 100644 --- a/core/shared/platform/zephyr/zephyr_platform.c +++ b/core/shared/platform/zephyr/zephyr_platform.c @@ -202,6 +202,11 @@ os_dcache_flush() key = irq_lock(); SCB_CleanDCache(); irq_unlock(key); +#elif defined(CONFIG_SOC_CVF_EM7D) && defined(CONFIG_ARC_MPU) \ + && defined (CONFIG_CACHE_FLUSHING) + __asm__ __volatile__("sync"); + z_arc_v2_aux_reg_write(_ARC_V2_DC_FLSH, BIT(0)); + __asm__ __volatile__("sync"); #endif } diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index 5fc77f5a1..081323dfc 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -35,11 +35,11 @@ endif WAMR_BUILD_PLATFORM := nuttx -ifeq (${WAMR_BUILD_TARGET}, X86_32) +ifeq ($(WAMR_BUILD_TARGET), X86_32) CFLAGS += -DBUILD_TARGET_X86_32 INVOKE_NATIVE := invokeNative_ia32.s AOT_RELOC := aot_reloc_x86_32.c -else ifeq (${WAMR_BUILD_TARGET}, X86_64) +else ifeq ($(WAMR_BUILD_TARGET), X86_64) CFLAGS += -DBUILD_TARGET_X86_64 INVOKE_NATIVE := invokeNative_em64.s AOT_RELOC := aot_reloc_x86_64.c @@ -96,17 +96,18 @@ else $(error Build target is unsupported) endif -ifeq (${CONFIG_INTERPRETERS_WAMR_LOG},y) +ifeq ($(CONFIG_INTERPRETERS_WAMR_LOG),y) CFLAGS += -DWASM_ENABLE_LOG=1 else CFLAGS += -DWASM_ENABLE_LOG=0 endif -ifeq (${CONFIG_INTERPRETERS_WAMR_AOT},y) -CFLAGS += -I${IWASM_ROOT}/aot +ifeq ($(CONFIG_INTERPRETERS_WAMR_AOT),y) +CFLAGS += -I$(IWASM_ROOT)/aot CFLAGS += -DWASM_ENABLE_AOT=1 CSRCS += aot_loader.c \ - ${AOT_RELOC} \ + $(AOT_RELOC) \ + aot_intrinsic.c \ aot_runtime.c else CFLAGS += -DWASM_ENABLE_AOT=0 @@ -115,7 +116,7 @@ endif CFLAGS += -DWASM_ENABLE_INTERP=1 CSRCS += wasm_runtime.c -ifeq (${CONFIG_INTERPRETERS_WAMR_FAST},y) +ifeq ($(CONFIG_INTERPRETERS_WAMR_FAST),y) CFLAGS += -DWASM_ENABLE_FAST_INTERP=1 CSRCS += wasm_interp_fast.c else @@ -137,7 +138,7 @@ endif ifeq ($(CONFIG_INTERPRETERS_WAMR_THREAD_MGR),y) CFLAGS += -DWASM_ENABLE_THREAD_MGR=1 CSRCS += thread_manager.c -VPATH += ${IWASM_ROOT}/libraries/thread-mgr +VPATH += $(IWASM_ROOT)/libraries/thread-mgr else CFLAGS += -DWASM_ENABLE_THREAD_MGR=0 endif @@ -191,9 +192,8 @@ CFLAGS += -I${CORE_ROOT} \ -I${SHARED_ROOT}/mem-alloc \ -I${SHARED_ROOT}/platform/nuttx - -ifeq (${WAMR_BUILD_INTERP}, 1) -CFLAGS += -I${IWASM_ROOT}/interpreter +ifeq ($(WAMR_BUILD_INTERP), 1) +CFLAGS += -I$(IWASM_ROOT)/interpreter endif CSRCS += nuttx_platform.c \ @@ -220,19 +220,19 @@ CSRCS += nuttx_platform.c \ wasm_memory.c \ wasm_c_api.c -ASRCS += ${INVOKE_NATIVE} +ASRCS += $(INVOKE_NATIVE) -VPATH += ${SHARED_ROOT}/platform/nuttx -VPATH += ${SHARED_ROOT}/platform/common/posix -VPATH += ${SHARED_ROOT}/mem-alloc -VPATH += ${SHARED_ROOT}/mem-alloc/ems -VPATH += ${SHARED_ROOT}/utils -VPATH += ${SHARED_ROOT}/utils/uncommon -VPATH += ${IWASM_ROOT}/common -VPATH += ${IWASM_ROOT}/interpreter -VPATH += ${IWASM_ROOT}/libraries -VPATH += ${IWASM_ROOT}/libraries/libc-builtin -VPATH += ${IWASM_ROOT}/libraries/lib-pthread -VPATH += ${IWASM_ROOT}/common/arch -VPATH += ${IWASM_ROOT}/aot -VPATH += ${IWASM_ROOT}/aot/arch +VPATH += $(SHARED_ROOT)/platform/nuttx +VPATH += $(SHARED_ROOT)/platform/common/posix +VPATH += $(SHARED_ROOT)/mem-alloc +VPATH += $(SHARED_ROOT)/mem-alloc/ems +VPATH += $(SHARED_ROOT)/utils +VPATH += $(SHARED_ROOT)/utils/uncommon +VPATH += $(IWASM_ROOT)/common +VPATH += $(IWASM_ROOT)/interpreter +VPATH += $(IWASM_ROOT)/libraries +VPATH += $(IWASM_ROOT)/libraries/libc-builtin +VPATH += $(IWASM_ROOT)/libraries/lib-pthread +VPATH += $(IWASM_ROOT)/common/arch +VPATH += $(IWASM_ROOT)/aot +VPATH += $(IWASM_ROOT)/aot/arch diff --git a/product-mini/platforms/posix/main.c b/product-mini/platforms/posix/main.c index 849d7cb22..ccc053c7b 100644 --- a/product-mini/platforms/posix/main.c +++ b/product-mini/platforms/posix/main.c @@ -32,7 +32,9 @@ print_help() printf(" --stack-size=n Set maximum stack size in bytes, default is 16 KB\n"); printf(" --heap-size=n Set maximum heap size in bytes, default is 16 KB\n"); printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n" - " that runs commands in the form of `FUNC ARG...`\n"); + " that runs commands in the form of \"FUNC ARG...\"\n"); + printf(" --xip Enable XIP (Execution In Place) mode to run AOT file\n" + " generated with \"--enable-indirect-mode\" flag\n"); #if WASM_ENABLE_LIBC_WASI != 0 printf(" --env= Pass wasi environment variables with \"key=value\"\n"); printf(" to the program, for example:\n"); @@ -232,6 +234,7 @@ main(int argc, char *argv[]) int log_verbose_level = 2; #endif bool is_repl_mode = false; + bool is_xip_mode = false; #if WASM_ENABLE_LIBC_WASI != 0 const char *dir_list[8] = { NULL }; uint32 dir_list_size = 0; @@ -259,6 +262,9 @@ main(int argc, char *argv[]) else if (!strcmp(argv[0], "--repl")) { is_repl_mode = true; } + else if (!strcmp(argv[0], "--xip")) { + is_xip_mode = true; + } else if (!strncmp(argv[0], "--stack-size=", 13)) { if (argv[0][13] == '\0') return print_help(); @@ -355,6 +361,24 @@ main(int argc, char *argv[]) (uint8 *)bh_read_file_to_buffer(wasm_file, &wasm_file_size))) goto fail1; + if (is_xip_mode) { + uint8 *wasm_file_mapped; + int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC; + int map_flags = MMAP_MAP_NONE; + + if (!(wasm_file_mapped = os_mmap(NULL, (uint32)wasm_file_size, + map_prot, map_flags))) { + printf("mmap memory failed\n"); + wasm_runtime_free(wasm_file_buf); + goto fail1; + } + + bh_memcpy_s(wasm_file_mapped, wasm_file_size, + wasm_file_buf, wasm_file_size); + wasm_runtime_free(wasm_file_buf); + wasm_file_buf = wasm_file_mapped; + } + #if WASM_ENABLE_MULTI_MODULE != 0 wasm_runtime_set_module_reader(module_reader_callback, moudle_destroyer); #endif @@ -395,7 +419,10 @@ fail3: fail2: /* free the file buffer */ - wasm_runtime_free(wasm_file_buf); + if (!is_xip_mode) + wasm_runtime_free(wasm_file_buf); + else + os_munmap(wasm_file_buf, wasm_file_size); fail1: /* destroy runtime environment */ diff --git a/product-mini/platforms/zephyr/simple/build_and_run.sh b/product-mini/platforms/zephyr/simple/build_and_run.sh index e928e4b13..b5d1b6177 100755 --- a/product-mini/platforms/zephyr/simple/build_and_run.sh +++ b/product-mini/platforms/zephyr/simple/build_and_run.sh @@ -10,11 +10,12 @@ QEMU_CORTEX_A53="qemu_cortex_a53" QEMU_XTENSA_TARGET="qemu_xtensa" QEMU_RISCV64_TARGET="qemu_riscv64" QEMU_RISCV32_TARGET="qemu_riscv32" +QEMU_ARC_TARGET="qemu_arc" usage () { echo "USAGE:" - echo "$0 $X86_TARGET|$STM32_TARGET|$ESP32_TARGET|$QEMU_CORTEX_A53|$QEMU_XTENSA_TARGET|$QEMU_RISCV64_TARGET|$QEMU_RISCV32_TARGET" + echo "$0 $X86_TARGET|$STM32_TARGET|$ESP32_TARGET|$QEMU_CORTEX_A53|$QEMU_XTENSA_TARGET|$QEMU_RISCV64_TARGET|$QEMU_RISCV32_TARGET|$QEMU_ARC_TARGET" echo "Example:" echo " $0 $X86_TARGET" echo " $0 $STM32_TARGET" @@ -88,6 +89,14 @@ case $TARGET in -DWAMR_BUILD_AOT=0 west build -t run ;; + $QEMU_ARC_TARGET) + west build -b qemu_arc_em \ + . -p always -- \ + -DCONF_FILE=prj_qemu_arc.conf \ + -DWAMR_BUILD_TARGET=ARC \ + -DWAMR_BUILD_AOT=0 + west build -t run + ;; *) echo "unsupported target: $TARGET" usage diff --git a/product-mini/platforms/zephyr/simple/prj_qemu_arc.conf b/product-mini/platforms/zephyr/simple/prj_qemu_arc.conf new file mode 100644 index 000000000..7f4a32832 --- /dev/null +++ b/product-mini/platforms/zephyr/simple/prj_qemu_arc.conf @@ -0,0 +1,6 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +CONFIG_STACK_SENTINEL=y +CONFIG_PRINTK=y +CONFIG_LOG=y diff --git a/product-mini/platforms/zephyr/simple/src/main.c b/product-mini/platforms/zephyr/simple/src/main.c index 14e6fad2f..f5b83e6df 100644 --- a/product-mini/platforms/zephyr/simple/src/main.c +++ b/product-mini/platforms/zephyr/simple/src/main.c @@ -64,10 +64,42 @@ static void* app_instance_main(wasm_module_inst_t module_inst) { const char *exception; + wasm_function_inst_t func; + wasm_exec_env_t exec_env; + unsigned argv[2] = { 0 }; + + if (wasm_runtime_lookup_function(module_inst, "main", NULL) + || wasm_runtime_lookup_function(module_inst, + "__main_argc_argv", NULL)) { + LOG_VERBOSE("Calling main funciton\n"); + wasm_application_execute_main(module_inst, app_argc, app_argv); + } + else if ((func = wasm_runtime_lookup_function(module_inst, + "app_main", NULL))) { + exec_env = wasm_runtime_create_exec_env(module_inst, + CONFIG_APP_HEAP_SIZE); + if (!exec_env) { + os_printf("Create exec env failed\n"); + return NULL; + } + + LOG_VERBOSE("Calling app_main funciton\n"); + wasm_runtime_call_wasm(exec_env, func, 0, argv); + + if (!wasm_runtime_get_exception(module_inst)) { + os_printf("result: 0x%x\n", argv[0]); + } + + wasm_runtime_destroy_exec_env(exec_env); + } + else { + os_printf("Failed to lookup function main or app_main to call\n"); + return NULL; + } - wasm_application_execute_main(module_inst, app_argc, app_argv); if ((exception = wasm_runtime_get_exception(module_inst))) - printf("%s\n", exception); + os_printf("%s\n", exception); + return NULL; } diff --git a/wamr-compiler/build_llvm_arc.sh b/wamr-compiler/build_llvm_arc.sh new file mode 100755 index 000000000..ddd933cd5 --- /dev/null +++ b/wamr-compiler/build_llvm_arc.sh @@ -0,0 +1,47 @@ +#!/bin/sh + +# Copyright (C) 2020 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +DEPS_DIR=${PWD}/../core/deps + +cd ${DEPS_DIR} +if [ ! -d "llvm" ]; then + echo "Clone llvm to core/deps/ .." + git clone https://github.com/llvm/llvm-project.git llvm +fi + +cd llvm +mkdir -p build +cd build + +if [ ! -f bin/llvm-lto ]; then + + CORE_NUM=$(nproc --all) + if [ -z "${CORE_NUM}" ]; then + CORE_NUM=1 + fi + + echo "Build llvm with" ${CORE_NUM} "cores" + + cmake ../llvm \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -DCMAKE_BUILD_TYPE:STRING="Release" \ + -DLLVM_TARGETS_TO_BUILD:STRING="X86" \ + -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD:STRING="ARC" \ + -DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF \ + -DLLVM_OPTIMIZED_TABLEGEN:BOOL=ON \ + -DLLVM_ENABLE_ZLIB:BOOL=OFF \ + -DLLVM_INCLUDE_DOCS:BOOL=OFF \ + -DLLVM_INCLUDE_EXAMPLES:BOOL=OFF \ + -DLLVM_INCLUDE_TESTS:BOOL=OFF \ + -DLLVM_INCLUDE_BENCHMARKS:BOOL=OFF \ + -DLLVM_APPEND_VC_REV:BOOL=OFF + make -j ${CORE_NUM} + +else + echo "llvm has already been built" +fi + +cd ${PWD} + diff --git a/wamr-compiler/main.c b/wamr-compiler/main.c index 1f859704a..465151a21 100644 --- a/wamr-compiler/main.c +++ b/wamr-compiler/main.c @@ -60,6 +60,8 @@ print_help() printf(" --disable-aux-stack-check Disable auxiliary stack overflow/underflow check\n"); printf(" --enable-dump-call-stack Enable stack trace feature\n"); printf(" --enable-perf-profiling Enable function performance profiling\n"); + printf(" --enable-indirect-mode Enalbe call function through symbol table but not direct call\n"); + printf(" --disable-llvm-intrinsics Disable the LLVM built-in intrinsics\n"); printf(" -v=n Set log verbose level (0 to 5, default is 2), larger with more log\n"); printf("Examples: wamrc -o test.aot test.wasm\n"); printf(" wamrc --target=i386 -o test.aot test.wasm\n"); @@ -188,6 +190,12 @@ main(int argc, char *argv[]) else if (!strcmp(argv[0], "--enable-perf-profiling")) { option.enable_aux_stack_frame = true; } + else if (!strcmp(argv[0], "--enable-indirect-mode")) { + option.is_indirect_mode = true; + } + else if (!strcmp(argv[0], "--disable-llvm-intrinsics")) { + option.disable_llvm_intrinsics = true; + } else return print_help(); }