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