This commit is contained in:
Brian Cain 2026-05-07 19:41:27 +00:00 committed by GitHub
commit bb31c85ac8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 1505 additions and 98 deletions

View File

@ -0,0 +1,204 @@
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
name: compilation on hexagon (qemu user-mode)
on:
pull_request:
types:
- opened
- synchronize
paths:
- ".github/workflows/build_llvm_libraries.yml"
- ".github/workflows/compilation_on_hexagon.yml"
- "build-scripts/**"
- "core/**"
- "!core/deps/**"
- "product-mini/**"
- "tests/wamr-test-suites/**"
- "wamr-compiler/**"
push:
branches:
- main
- "dev/**"
paths:
- ".github/workflows/build_llvm_libraries.yml"
- ".github/workflows/compilation_on_hexagon.yml"
- "build-scripts/**"
- "core/**"
- "!core/deps/**"
- "product-mini/**"
- "tests/wamr-test-suites/**"
- "wamr-compiler/**"
workflow_dispatch:
# Cancel any in-flight jobs for the same PR/branch so there's only one active
# at a time
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
build_llvm_libraries:
permissions:
contents: read
actions: write
uses: ./.github/workflows/build_llvm_libraries.yml
with:
os: "ubuntu-22.04"
arch: "X86 Hexagon"
build_wamrc:
needs: [build_llvm_libraries]
runs-on: ubuntu-22.04
steps:
- name: checkout
uses: actions/checkout@v6.0.2
- name: Get LLVM libraries
id: retrieve_llvm_libs
uses: actions/cache@v5
with:
path: |
./core/deps/llvm/build/bin
./core/deps/llvm/build/include
./core/deps/llvm/build/lib
./core/deps/llvm/build/libexec
./core/deps/llvm/build/share
key: ${{ needs.build_llvm_libraries.outputs.cache_key }}
- name: Quit if cache miss
if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true'
run: echo "::error::can not get prebuilt llvm libraries" && exit 1
- name: Build wamrc
run: |
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
cmake --build . --config Release --parallel $(nproc)
working-directory: wamr-compiler
- name: Upload wamrc
uses: actions/upload-artifact@v7.0.1
with:
name: wamrc-hexagon
path: wamr-compiler/build/wamrc
build_iwasm:
runs-on: ubuntu-22.04
steps:
- name: checkout
uses: actions/checkout@v6.0.2
- name: Install QEMU user-mode
run: sudo apt-get update && sudo apt-get install -y qemu-user
- name: Install clang-22 and lld-22
run: |
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
echo "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-22 main" | sudo tee /etc/apt/sources.list.d/llvm-22.list
sudo apt-get update
sudo apt-get install -y clang-22 lld-22
- name: Install CodeLinaro Hexagon toolchain
run: |
wget -q https://artifacts.codelinaro.org/artifactory/codelinaro-toolchain-for-hexagon/22.1.4_/hexagon-debs-22.1.4_.tar.gz
mkdir hexagon-debs
tar xf hexagon-debs-22.1.4_.tar.gz -C hexagon-debs
sudo dpkg -i hexagon-debs/*.deb
- name: Cross-compile iwasm for Hexagon
run: |
cmake -S product-mini/platforms/hexagon \
-B build-hexagon \
-DCMAKE_TOOLCHAIN_FILE=${GITHUB_WORKSPACE}/build-scripts/toolchains/hexagon_linux_musl.cmake \
-DCMAKE_BUILD_TYPE=Release \
-DWAMR_DISABLE_HW_BOUND_CHECK=1 \
-DWAMR_BUILD_SHRUNK_MEMORY=0 \
-DWAMR_BUILD_SPEC_TEST=1 \
-DWAMR_BUILD_LIBC_WASI=0
cmake --build build-hexagon --parallel $(nproc)
- name: Verify iwasm binary
run: |
file build-hexagon/iwasm
qemu-hexagon -cpu v67 build-hexagon/iwasm --version
- name: Upload iwasm
uses: actions/upload-artifact@v7.0.1
with:
name: iwasm-hexagon
path: build-hexagon/iwasm
spec_test:
needs: [build_iwasm, build_wamrc]
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
test_option:
- "-s spec -b -P"
- "-s spec -b -S -P"
running_mode:
- "classic-interp"
- "fast-interp"
- "aot"
exclude:
# SIMD AOT needs further validation
- test_option: "-s spec -b -S -P"
running_mode: "aot"
steps:
- name: checkout
uses: actions/checkout@v6.0.2
- name: Install QEMU user-mode
run: sudo apt-get update && sudo apt-get install -y qemu-user
- name: Download iwasm artifact
uses: actions/download-artifact@v4.2.0
with:
name: iwasm-hexagon
path: ./
- name: Download wamrc artifact
if: matrix.running_mode == 'aot'
uses: actions/download-artifact@v4.2.0
with:
name: wamrc-hexagon
path: ./
- name: Set up iwasm wrapper
run: |
chmod +x ./iwasm
# Place the real Hexagon binary at a known path
mv ./iwasm ./iwasm-hexagon-real
# Create a wrapper that invokes iwasm via qemu-hexagon user-mode.
# Use the linux platform path since Hexagon runs Linux and this
# avoids needing to teach every host-tool lookup about "hexagon".
mkdir -p product-mini/platforms/linux/build
printf '#!/bin/sh\nexec qemu-hexagon -cpu v67 %s/iwasm-hexagon-real "$@"\n' \
"${GITHUB_WORKSPACE}" > product-mini/platforms/linux/build/iwasm
chmod +x product-mini/platforms/linux/build/iwasm
# Verify it works
product-mini/platforms/linux/build/iwasm --version
- name: Set up wamrc
if: matrix.running_mode == 'aot'
run: |
chmod +x ./wamrc
mkdir -p wamr-compiler/build
cp ./wamrc wamr-compiler/build/wamrc
- name: Run spec tests
timeout-minutes: 60
run: |
./test_wamr.sh ${{ matrix.test_option }} \
-m HEXAGON \
-t ${{ matrix.running_mode }} \
-j linux \
-Q \
${{ matrix.running_mode == 'aot' && format('-A {0}/wamr-compiler/build/wamrc', github.workspace) || '' }}
working-directory: ./tests/wamr-test-suites

View File

@ -45,6 +45,8 @@ elseif (WAMR_BUILD_TARGET STREQUAL "RISCV32_ILP32")
add_definitions(-DBUILD_TARGET_RISCV32_ILP32)
elseif (WAMR_BUILD_TARGET STREQUAL "ARC")
add_definitions(-DBUILD_TARGET_ARC)
elseif (WAMR_BUILD_TARGET STREQUAL "HEXAGON")
add_definitions(-DBUILD_TARGET_HEXAGON)
else ()
message (FATAL_ERROR "-- WAMR build target isn't set")
endif ()

View File

@ -0,0 +1,22 @@
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
# CMake toolchain file for cross-compiling to Hexagon Linux (musl)
# Requires CodeLinaro hexagon-unknown-linux-musl toolchain and clang-22/lld-22.
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR hexagon)
set(CMAKE_C_COMPILER hexagon-unknown-linux-musl-clang)
set(CMAKE_CXX_COMPILER hexagon-unknown-linux-musl-clang++)
set(CMAKE_ASM_COMPILER hexagon-unknown-linux-musl-clang)
set(CMAKE_AR llvm-ar-22)
set(CMAKE_RANLIB llvm-ranlib-22)
set(CMAKE_C_FLAGS_INIT "-mv68 -G0")
set(CMAKE_CXX_FLAGS_INIT "-mv68 -G0")
set(CMAKE_EXE_LINKER_FLAGS_INIT "-static")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

View File

@ -22,7 +22,8 @@
&& !defined(BUILD_TARGET_RISCV32_ILP32D) \
&& !defined(BUILD_TARGET_RISCV32_ILP32F) \
&& !defined(BUILD_TARGET_RISCV32_ILP32) \
&& !defined(BUILD_TARGET_ARC)
&& !defined(BUILD_TARGET_ARC) \
&& !defined(BUILD_TARGET_HEXAGON)
/* clang-format on */
#if defined(__x86_64__) || defined(__x86_64)
#define BUILD_TARGET_X86_64
@ -52,6 +53,8 @@
#define BUILD_TARGET_RISCV32_ILP32D
#elif defined(__arc__)
#define BUILD_TARGET_ARC
#elif defined(__hexagon__)
#define BUILD_TARGET_HEXAGON
#else
#error "Build target isn't set"
#endif
@ -276,6 +279,19 @@
#endif
#endif
/* Whether the CPU supports unaligned SIMD/vector memory access.
* Some architectures have dedicated unaligned-load vector instructions,
* allowing V128 access at any alignment even when scalar loads require
* natural alignment. */
#ifndef WASM_CPU_SUPPORTS_UNALIGNED_SIMD_ACCESS
#if defined(BUILD_TARGET_X86_32) || defined(BUILD_TARGET_X86_64) \
|| defined(BUILD_TARGET_AARCH64) || defined(BUILD_TARGET_HEXAGON)
#define WASM_CPU_SUPPORTS_UNALIGNED_SIMD_ACCESS 1
#else
#define WASM_CPU_SUPPORTS_UNALIGNED_SIMD_ACCESS 0
#endif
#endif
/* WASM Interpreter labels-as-values feature */
#ifndef WASM_ENABLE_LABELS_AS_VALUES
#ifdef __GNUC__

View File

@ -275,6 +275,7 @@ GET_U16_FROM_ADDR(const uint8 *p)
#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_HEXAGON 164 /* Qualcomm Hexagon */
#define E_MACHINE_RISCV 243 /* RISC-V 32/64 */
#define E_MACHINE_WIN_I386 0x14c /* Windows i386 architecture */
#define E_MACHINE_WIN_X86_64 0x8664 /* Windows x86-64 architecture */
@ -432,6 +433,9 @@ get_aot_file_target(AOTTargetInfo *target_info, char *target_buf,
case E_MACHINE_ARC_COMPACT2:
machine_type = "arc";
break;
case E_MACHINE_HEXAGON:
machine_type = "hexagon";
break;
default:
set_error_buf_v(error_buf, error_buf_size,
"unknown machine type %d", target_info->e_machine);

View File

@ -0,0 +1,739 @@
/*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "aot_reloc.h"
/*
* Hexagon ELF relocation types.
* Reference: "Qualcomm Hexagon Application Binary Interface User Guide"
* https://docs.qualcomm.com/doc/80-N2040-23/80-N2040-23_REV_K_Qualcomm_Hexagon_Application_Binary_Interface_User_Guide.pdf
*/
#define R_HEX_NONE 0
#define R_HEX_B22_PCREL 1
#define R_HEX_B15_PCREL 2
#define R_HEX_B7_PCREL 3
#define R_HEX_LO16 4
#define R_HEX_HI16 5
#define R_HEX_32 6
#define R_HEX_16 7
#define R_HEX_8 8
#define R_HEX_GPREL16_0 9
#define R_HEX_GPREL16_1 10
#define R_HEX_GPREL16_2 11
#define R_HEX_GPREL16_3 12
#define R_HEX_B13_PCREL 14
#define R_HEX_B9_PCREL 15
#define R_HEX_B32_PCREL_X 16
#define R_HEX_32_6_X 17
#define R_HEX_B22_PCREL_X 18
#define R_HEX_B15_PCREL_X 19
#define R_HEX_B13_PCREL_X 20
#define R_HEX_B9_PCREL_X 21
#define R_HEX_B7_PCREL_X 22
#define R_HEX_16_X 23
#define R_HEX_12_X 24
#define R_HEX_11_X 25
#define R_HEX_10_X 26
#define R_HEX_9_X 27
#define R_HEX_8_X 28
#define R_HEX_7_X 29
#define R_HEX_6_X 30
#define R_HEX_32_PCREL 31
#define R_HEX_6_PCREL_X 65
/* Instruction bit-field masks for relocations. */
#define MASK_B22 0x01ff3ffe
#define MASK_B15 0x00df20fe
#define MASK_B13 0x00202ffe
#define MASK_B9 0x003000fe
#define MASK_B7 0x00001f18
#define MASK_LO16 0x00c03fff
#define MASK_X26 0x0fff3fff
/* Compiler runtime helpers required by AOT modules. */
/* clang-format off */
void __hexagon_divsi3(void);
void __hexagon_modsi3(void);
void __hexagon_udivsi3(void);
void __hexagon_umodsi3(void);
void __hexagon_divdi3(void);
void __hexagon_moddi3(void);
void __hexagon_udivdi3(void);
void __hexagon_umoddi3(void);
void __hexagon_udivmodsi4(void);
void __hexagon_udivmoddi4(void);
void __hexagon_divsf3(void);
void __hexagon_divdf3(void);
void __hexagon_adddf3(void);
void __hexagon_subdf3(void);
void __hexagon_muldf3(void);
void __hexagon_sqrtf(void);
void __hexagon_sqrtdf2(void);
void __hexagon_fmadf4(void);
void __hexagon_fmadf5(void);
void __hexagon_memcpy_likely_aligned_min32bytes_mult8bytes(void);
/* clang-format on */
/* clang-format off */
static SymbolMap target_sym_map[] = {
REG_COMMON_SYMBOLS
/* Integer division/modulo helpers */
REG_SYM(__hexagon_divsi3),
REG_SYM(__hexagon_modsi3),
REG_SYM(__hexagon_udivsi3),
REG_SYM(__hexagon_umodsi3),
REG_SYM(__hexagon_divdi3),
REG_SYM(__hexagon_moddi3),
REG_SYM(__hexagon_udivdi3),
REG_SYM(__hexagon_umoddi3),
REG_SYM(__hexagon_udivmodsi4),
REG_SYM(__hexagon_udivmoddi4),
/* Floating-point helpers */
REG_SYM(__hexagon_divsf3),
REG_SYM(__hexagon_divdf3),
REG_SYM(__hexagon_adddf3),
REG_SYM(__hexagon_subdf3),
REG_SYM(__hexagon_muldf3),
REG_SYM(__hexagon_sqrtf),
REG_SYM(__hexagon_sqrtdf2),
REG_SYM(__hexagon_fmadf4),
REG_SYM(__hexagon_fmadf5),
/* Optimized memory operations */
REG_SYM(__hexagon_memcpy_likely_aligned_min32bytes_mult8bytes),
};
/* clang-format on */
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, "hexagon");
}
#define INST_PARSE_PACKET_END 0x0000c000
static bool
is_duplex(uint32 insn)
{
return (INST_PARSE_PACKET_END & insn) == 0;
}
/* Instruction opcode → relocation mask table for R_HEX_6_X */
/* clang-format off */
static const struct { uint32 cmp_mask; uint32 reloc_mask; } r6_masks[] = {
{ 0x38000000, 0x0000201f }, { 0x39000000, 0x0000201f },
{ 0x3e000000, 0x00001f80 }, { 0x3f000000, 0x00001f80 },
{ 0x40000000, 0x000020f8 }, { 0x41000000, 0x000007e0 },
{ 0x42000000, 0x000020f8 }, { 0x43000000, 0x000007e0 },
{ 0x44000000, 0x000020f8 }, { 0x45000000, 0x000007e0 },
{ 0x46000000, 0x000020f8 }, { 0x47000000, 0x000007e0 },
{ 0x6a000000, 0x00001f80 }, { 0x7c000000, 0x001f2000 },
{ 0x9a000000, 0x00000f60 }, { 0x9b000000, 0x00000f60 },
{ 0x9c000000, 0x00000f60 }, { 0x9d000000, 0x00000f60 },
{ 0x9f000000, 0x001f0100 }, { 0xab000000, 0x0000003f },
{ 0xad000000, 0x0000003f }, { 0xaf000000, 0x00030078 },
{ 0xd7000000, 0x006020e0 }, { 0xd8000000, 0x006020e0 },
{ 0xdb000000, 0x006020e0 }, { 0xdf000000, 0x006020e0 },
};
/* clang-format on */
static uint32
get_mask_r6(uint32 insn, char *error_buf, uint32 error_buf_size)
{
uint32 i;
if (is_duplex(insn))
return 0x03f00000;
for (i = 0; i < sizeof(r6_masks) / sizeof(r6_masks[0]); i++) {
if ((insn & 0xff000000) == r6_masks[i].cmp_mask)
return r6_masks[i].reloc_mask;
}
set_error_buf(error_buf, error_buf_size,
"AOT module load failed: "
"unrecognized instruction for 6_X relocation.");
return 0;
}
static uint32
get_mask_r8(uint32 insn)
{
if ((0xff000000 & insn) == 0xde000000)
return 0x00e020e8;
if ((0xff000000 & insn) == 0x3c000000)
return 0x0000207f;
return 0x00001fe0;
}
static uint32
get_mask_r11(uint32 insn)
{
if (is_duplex(insn))
return 0x03f00000;
if ((0xff000000 & insn) == 0xa1000000)
return 0x060020ff;
return 0x06003fe0;
}
static uint32
get_mask_r16(uint32 insn, char *error_buf, uint32 error_buf_size)
{
uint32 i;
if (is_duplex(insn))
return 0x03f00000;
/* Clear end-packet-parse bits for matching */
insn = insn & ~INST_PARSE_PACKET_END;
if ((0xff000000 & insn) == 0x48000000)
return 0x061f20ff;
if ((0xff000000 & insn) == 0x49000000)
return 0x061f3fe0;
if ((0xff000000 & insn) == 0x78000000)
return 0x00df3fe0;
if ((0xff000000 & insn) == 0xb0000000)
return 0x0fe03fe0;
if ((0xff802000 & insn) == 0x74000000)
return 0x00001fe0;
if ((0xff802000 & insn) == 0x74002000)
return 0x00001fe0;
if ((0xff802000 & insn) == 0x74800000)
return 0x00001fe0;
if ((0xff802000 & insn) == 0x74802000)
return 0x00001fe0;
/* Fall back to r6 table */
for (i = 0; i < sizeof(r6_masks) / sizeof(r6_masks[0]); i++) {
if ((insn & 0xff000000) == r6_masks[i].cmp_mask)
return r6_masks[i].reloc_mask;
}
set_error_buf(error_buf, error_buf_size,
"AOT module load failed: "
"unrecognized instruction for 16_X relocation.");
return 0;
}
/* Scatter bits from 'data' into positions indicated by set bits in 'mask'. */
static uint32
apply_mask(uint32 mask, uint32 data)
{
uint32 result = 0;
uint32 off = 0;
uint32 bit;
for (bit = 0; bit < 32; bit++) {
uint32 val_bit = (data >> off) & 1;
uint32 mask_bit = (mask >> bit) & 1;
if (mask_bit) {
result |= (val_bit << bit);
off++;
}
}
return result;
}
#define PLT_ITEM_SIZE 12
/* Instruction templates with address = 0 */
#define PLT_IMMEXT_TEMPLATE 0x00004000
#define PLT_R28_TEMPLATE 0x7800c01c
#define PLT_JUMPR_R28 0x529cc000
#define MASK_R28_IMM 0x00df3fe0
uint32
get_plt_item_size(void)
{
return PLT_ITEM_SIZE;
}
uint32
get_plt_table_size(void)
{
return get_plt_item_size() * (sizeof(target_sym_map) / sizeof(SymbolMap));
}
void
init_plt_table(uint8 *plt)
{
uint32 i, num = sizeof(target_sym_map) / sizeof(SymbolMap);
for (i = 0; i < num; i++) {
uint32 addr = (uint32)(uintptr_t)target_sym_map[i].symbol_addr;
uint32 *p = (uint32 *)plt;
p[0] = PLT_IMMEXT_TEMPLATE | apply_mask(MASK_X26, addr >> 6);
p[1] = PLT_R28_TEMPLATE | apply_mask(MASK_R28_IMM, addr & 0x3F);
p[2] = PLT_JUMPR_R28;
plt += PLT_ITEM_SIZE;
}
}
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;
}
bool
apply_relocation(AOTModule *module, uint8 *target_section_addr,
uint32 target_section_size, uint64 reloc_offset,
int64 reloc_addend, uint32 reloc_type, void *symbol_addr,
int32 symbol_index, char *error_buf, uint32 error_buf_size)
{
switch (reloc_type) {
case R_HEX_32:
{
/* Direct 32-bit relocation: S + A */
uint32 val;
CHECK_RELOC_OFFSET(sizeof(uint32));
val = (uint32)(uintptr_t)symbol_addr + (int32)reloc_addend;
*(uint32 *)(target_section_addr + reloc_offset) = val;
break;
}
case R_HEX_32_PCREL:
{
/* 32-bit PC-relative: S + A - P */
int32 val;
CHECK_RELOC_OFFSET(sizeof(uint32));
val = (int32)((intptr_t)symbol_addr + (intptr_t)reloc_addend
- (intptr_t)(target_section_addr + reloc_offset));
*(int32 *)(target_section_addr + reloc_offset) = val;
break;
}
case R_HEX_B22_PCREL:
{
/*
* 22-bit PC-relative branch: (S + A - P) >> 2
* 22-bit signed field, word-aligned: +-8MB byte range.
* For external symbols (symbol_index >= 0), use PLT
* trampoline if direct branch is out of range.
*/
intptr_t result;
CHECK_RELOC_OFFSET(sizeof(uint32));
if (symbol_index >= 0) {
/* External symbol: redirect through PLT */
uint8 *plt = (uint8 *)module->code + module->code_size
- get_plt_table_size()
+ get_plt_item_size() * symbol_index;
result = (intptr_t)((uintptr_t)plt + (intptr_t)reloc_addend
- (uintptr_t)(target_section_addr
+ reloc_offset));
}
else {
result =
(intptr_t)((uintptr_t)symbol_addr + (intptr_t)reloc_addend
- (uintptr_t)(target_section_addr
+ reloc_offset));
}
if (result >= (8 * BH_MB) || result < -(8 * BH_MB)) {
set_error_buf(error_buf, error_buf_size,
"AOT module load failed: "
"B22_PCREL target out of range.");
return false;
}
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(MASK_B22, (uint32)(result >> 2));
break;
}
case R_HEX_B15_PCREL:
{
/* 15-bit PC-relative branch: (S + A - P) >> 2, +-64KB range */
intptr_t result;
CHECK_RELOC_OFFSET(sizeof(uint32));
result =
(intptr_t)((uintptr_t)symbol_addr + (intptr_t)reloc_addend
- (uintptr_t)(target_section_addr + reloc_offset));
if (result >= 0x10000 || result < -0x10000) {
set_error_buf(error_buf, error_buf_size,
"AOT module load failed: "
"B15_PCREL target out of range.");
return false;
}
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(MASK_B15, (uint32)(result >> 2));
break;
}
case R_HEX_B13_PCREL:
{
/* 13-bit PC-relative branch: (S + A - P) >> 2, +-16KB range */
intptr_t result;
CHECK_RELOC_OFFSET(sizeof(uint32));
result =
(intptr_t)((uintptr_t)symbol_addr + (intptr_t)reloc_addend
- (uintptr_t)(target_section_addr + reloc_offset));
if (result >= 0x4000 || result < -0x4000) {
set_error_buf(error_buf, error_buf_size,
"AOT module load failed: "
"B13_PCREL target out of range.");
return false;
}
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(MASK_B13, (uint32)(result >> 2));
break;
}
case R_HEX_B9_PCREL:
{
/* 9-bit PC-relative branch: (S + A - P) >> 2, +-1KB range */
intptr_t result;
CHECK_RELOC_OFFSET(sizeof(uint32));
result =
(intptr_t)((uintptr_t)symbol_addr + (intptr_t)reloc_addend
- (uintptr_t)(target_section_addr + reloc_offset));
if (result >= 0x400 || result < -0x400) {
set_error_buf(error_buf, error_buf_size,
"AOT module load failed: "
"B9_PCREL target out of range.");
return false;
}
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(MASK_B9, (uint32)(result >> 2));
break;
}
case R_HEX_B7_PCREL:
{
/* 7-bit PC-relative branch: (S + A - P) >> 2, +-256B range */
intptr_t result;
CHECK_RELOC_OFFSET(sizeof(uint32));
result =
(intptr_t)((uintptr_t)symbol_addr + (intptr_t)reloc_addend
- (uintptr_t)(target_section_addr + reloc_offset));
if (result >= 0x100 || result < -0x100) {
set_error_buf(error_buf, error_buf_size,
"AOT module load failed: "
"B7_PCREL target out of range.");
return false;
}
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(MASK_B7, (uint32)(result >> 2));
break;
}
case R_HEX_LO16:
{
/* Low 16 bits of absolute address: (S + A) & 0xFFFF */
uint32 val;
CHECK_RELOC_OFFSET(sizeof(uint32));
val = (uint32)(uintptr_t)symbol_addr + (int32)reloc_addend;
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(MASK_LO16, val & 0xFFFF);
break;
}
case R_HEX_HI16:
{
/* High 16 bits of absolute address: (S + A) >> 16 */
uint32 val;
CHECK_RELOC_OFFSET(sizeof(uint32));
val = (uint32)(uintptr_t)symbol_addr + (int32)reloc_addend;
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(MASK_LO16, val >> 16);
break;
}
case R_HEX_B32_PCREL_X:
{
/*
* Extended 32-bit PC-relative for constant extender.
* Upper 26 bits: (S + A - P) >> 6
*/
intptr_t result;
CHECK_RELOC_OFFSET(sizeof(uint32));
result =
(intptr_t)((uintptr_t)symbol_addr + (intptr_t)reloc_addend
- (uintptr_t)(target_section_addr + reloc_offset));
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(MASK_X26, (uint32)(result >> 6));
break;
}
case R_HEX_32_6_X:
{
/*
* Extended 32-bit absolute for constant extender.
* Upper 26 bits: (S + A) >> 6
*/
uint32 val;
CHECK_RELOC_OFFSET(sizeof(uint32));
val = (uint32)(uintptr_t)symbol_addr + (int32)reloc_addend;
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(MASK_X26, val >> 6);
break;
}
case R_HEX_B22_PCREL_X:
{
/*
* Extended 22-bit PC-relative: low 6 bits of (S + A - P).
* Paired with R_HEX_B32_PCREL_X on the constant extender.
*/
intptr_t result;
CHECK_RELOC_OFFSET(sizeof(uint32));
result =
(intptr_t)((uintptr_t)symbol_addr + (intptr_t)reloc_addend
- (uintptr_t)(target_section_addr + reloc_offset));
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(MASK_B22, (uint32)result & 0x3F);
break;
}
case R_HEX_B15_PCREL_X:
{
/*
* Extended 15-bit PC-relative: low 6 bits of (S + A - P).
* Paired with R_HEX_B32_PCREL_X on the constant extender.
*/
intptr_t result;
CHECK_RELOC_OFFSET(sizeof(uint32));
result =
(intptr_t)((uintptr_t)symbol_addr + (intptr_t)reloc_addend
- (uintptr_t)(target_section_addr + reloc_offset));
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(MASK_B15, (uint32)result & 0x3F);
break;
}
case R_HEX_B13_PCREL_X:
{
/*
* Extended 13-bit PC-relative: low 6 bits of (S + A - P).
* Paired with R_HEX_B32_PCREL_X on the constant extender.
*/
intptr_t result;
CHECK_RELOC_OFFSET(sizeof(uint32));
result =
(intptr_t)((uintptr_t)symbol_addr + (intptr_t)reloc_addend
- (uintptr_t)(target_section_addr + reloc_offset));
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(MASK_B13, (uint32)result & 0x3F);
break;
}
case R_HEX_B9_PCREL_X:
{
/*
* Extended 9-bit PC-relative: low 6 bits of (S + A - P).
* Paired with R_HEX_B32_PCREL_X on the constant extender.
*/
intptr_t result;
CHECK_RELOC_OFFSET(sizeof(uint32));
result =
(intptr_t)((uintptr_t)symbol_addr + (intptr_t)reloc_addend
- (uintptr_t)(target_section_addr + reloc_offset));
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(MASK_B9, (uint32)result & 0x3F);
break;
}
case R_HEX_B7_PCREL_X:
{
/*
* Extended 7-bit PC-relative: low 6 bits of (S + A - P).
* Paired with R_HEX_B32_PCREL_X on the constant extender.
*/
intptr_t result;
CHECK_RELOC_OFFSET(sizeof(uint32));
result =
(intptr_t)((uintptr_t)symbol_addr + (intptr_t)reloc_addend
- (uintptr_t)(target_section_addr + reloc_offset));
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(MASK_B7, (uint32)result & 0x3F);
break;
}
case R_HEX_6_X:
{
/* Low 6 bits for constant-extended absolute */
uint32 val, insn, mask_r6;
CHECK_RELOC_OFFSET(sizeof(uint32));
insn = *(uint32 *)(target_section_addr + reloc_offset);
mask_r6 = get_mask_r6(insn, error_buf, error_buf_size);
if (!mask_r6)
return false;
val = (uint32)(uintptr_t)symbol_addr + (int32)reloc_addend;
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(mask_r6, val & 0x3F);
break;
}
case R_HEX_6_PCREL_X:
{
/* Low 6 bits for constant-extended PC-relative */
intptr_t result;
uint32 insn, mask_r6;
CHECK_RELOC_OFFSET(sizeof(uint32));
insn = *(uint32 *)(target_section_addr + reloc_offset);
mask_r6 = get_mask_r6(insn, error_buf, error_buf_size);
if (!mask_r6)
return false;
result =
(intptr_t)((uintptr_t)symbol_addr + (intptr_t)reloc_addend
- (uintptr_t)(target_section_addr + reloc_offset));
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(mask_r6, (uint32)result & 0x3F);
break;
}
case R_HEX_16_X:
{
uint32 val, insn, mask_r16;
CHECK_RELOC_OFFSET(sizeof(uint32));
insn = *(uint32 *)(target_section_addr + reloc_offset);
mask_r16 = get_mask_r16(insn, error_buf, error_buf_size);
if (!mask_r16)
return false;
val = (uint32)(uintptr_t)symbol_addr + (int32)reloc_addend;
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(mask_r16, val & 0x3F);
break;
}
case R_HEX_12_X:
{
/* Extended 12-bit absolute: (S + A) with fixed mask */
uint32 val;
CHECK_RELOC_OFFSET(sizeof(uint32));
val = (uint32)(uintptr_t)symbol_addr + (int32)reloc_addend;
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(0x000007e0, val);
break;
}
case R_HEX_11_X:
{
/* Extended 11-bit absolute: low 6 bits of (S + A) */
uint32 val, insn;
CHECK_RELOC_OFFSET(sizeof(uint32));
insn = *(uint32 *)(target_section_addr + reloc_offset);
val = (uint32)(uintptr_t)symbol_addr + (int32)reloc_addend;
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(get_mask_r11(insn), val & 0x3F);
break;
}
case R_HEX_10_X:
{
/* Extended 10-bit absolute: low 6 bits of (S + A) */
uint32 val;
CHECK_RELOC_OFFSET(sizeof(uint32));
val = (uint32)(uintptr_t)symbol_addr + (int32)reloc_addend;
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(0x00203fe0, val & 0x3F);
break;
}
case R_HEX_9_X:
{
/* Extended 9-bit absolute: low 6 bits of (S + A) */
uint32 val;
CHECK_RELOC_OFFSET(sizeof(uint32));
val = (uint32)(uintptr_t)symbol_addr + (int32)reloc_addend;
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(0x00003fe0, val & 0x3F);
break;
}
case R_HEX_8_X:
{
/* Extended 8-bit absolute: (S + A) */
uint32 val, insn;
CHECK_RELOC_OFFSET(sizeof(uint32));
insn = *(uint32 *)(target_section_addr + reloc_offset);
val = (uint32)(uintptr_t)symbol_addr + (int32)reloc_addend;
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(get_mask_r8(insn), val);
break;
}
case R_HEX_7_X:
{
/* Extended 7-bit absolute: low 7 bits of (S + A) */
uint32 val;
CHECK_RELOC_OFFSET(sizeof(uint32));
val = (uint32)(uintptr_t)symbol_addr + (int32)reloc_addend;
*(uint32 *)(target_section_addr + reloc_offset) |=
apply_mask(0x00001f18, val & 0x7F);
break;
}
case R_HEX_16:
{
/* Direct 16-bit relocation */
uint16 val;
CHECK_RELOC_OFFSET(sizeof(uint16));
val = (uint16)((uintptr_t)symbol_addr + (int32)reloc_addend);
*(uint16 *)(target_section_addr + reloc_offset) = val;
break;
}
case R_HEX_8:
{
/* Direct 8-bit relocation: (S + A) truncated to 8 bits */
uint8 val;
CHECK_RELOC_OFFSET(sizeof(uint8));
val = (uint8)((uintptr_t)symbol_addr + (int32)reloc_addend);
*(uint8 *)(target_section_addr + reloc_offset) = val;
break;
}
case R_HEX_NONE:
break;
default:
if (error_buf != NULL)
snprintf(error_buf, error_buf_size,
"Load relocation section failed: "
"invalid relocation type %" PRIu32 ".",
reloc_type);
return false;
}
return true;
}

View File

@ -49,6 +49,8 @@ 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)
elseif (WAMR_BUILD_TARGET STREQUAL "HEXAGON")
set (arch_source ${IWASM_AOT_DIR}/arch/aot_reloc_hexagon.c)
else ()
message (FATAL_ERROR "Build target isn't set")
endif ()

View File

@ -0,0 +1,137 @@
/*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
.text
.align 2
.globl invokeNative
.type invokeNative, @function
/*
* void invokeNative(void (*native_code)(), uint32 argv[], uint32 argc)
*
* r0 = native_code, r1 = argv, r2 = argc
* Loads up to 6 words into r0-r5; remaining args are pushed to stack.
*/
invokeNative:
{
allocframe(#16)
}
{
memd(r29+#0) = r17:16
}
{
memd(r29+#8) = r19:18
}
// Save arguments to callee-saved registers
{
r16 = r0 // r16 = function_ptr
r17 = r1 // r17 = argv
}
{
r18 = r2 // r18 = argc
p0 = cmp.gt(r2, #0)
}
{
if (!p0) jump .Lcall // argc == 0: skip arg loading
}
// Load register arguments from argv (up to 6 words in r0-r5)
{
r0 = memw(r17+#0) // r0 = argv[0] (exec_env)
p0 = cmp.gt(r18, #1)
}
{ if (!p0) jump .Lcall }
{
r1 = memw(r17+#4) // r1 = argv[1]
p0 = cmp.gt(r18, #2)
}
{ if (!p0) jump .Lcall }
{
r2 = memw(r17+#8) // r2 = argv[2]
p0 = cmp.gt(r18, #3)
}
{ if (!p0) jump .Lcall }
{
r3 = memw(r17+#12) // r3 = argv[3]
p0 = cmp.gt(r18, #4)
}
{ if (!p0) jump .Lcall }
{
r4 = memw(r17+#16) // r4 = argv[4]
p0 = cmp.gt(r18, #5)
}
{ if (!p0) jump .Lcall }
{
r5 = memw(r17+#20) // r5 = argv[5]
p0 = cmp.gt(r18, #6)
}
{ if (!p0) jump .Lcall }
// Stack arguments: argc > 6.
// Copy argv[6..argc-1] to the stack, maintaining 8-byte alignment.
{
r19 = add(r18, #-6) // r19 = number of stack args
}
{
r7 = asl(r19, #2) // r7 = stack_args * 4 (bytes)
}
{
r7 = add(r7, #7) // round up to 8-byte alignment
}
{
r7 = and(r7, #-8)
}
{
r29 = sub(r29, r7) // allocate aligned stack space
}
{
r6 = add(r17, #24) // r6 = &argv[6] (source)
r8 = r29 // r8 = stack destination
}
.Lcopy_loop:
{
r9 = memw(r6++#4) // load next arg from argv
}
{
memw(r8++#4) = r9 // store to stack
r19 = add(r19, #-1) // decrement counter
}
{
p0 = cmp.gt(r19, #0)
if (p0.new) jump:t .Lcopy_loop
}
.Lcall:
{
callr r16 // call native function
}
.Lreturn:
{
r17:16 = memd(r30+#-16)
}
{
r19:18 = memd(r30+#-8)
}
{
deallocframe
}
{
jumpr r31
}
.size invokeNative, .-invokeNative
#if defined(__linux__) && defined(__ELF__)
.section .note.GNU-stack,"",%progbits
#endif

View File

@ -155,6 +155,8 @@ 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)
elseif (WAMR_BUILD_TARGET STREQUAL "HEXAGON")
set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_hexagon.s)
else ()
message (FATAL_ERROR "Build target isn't set")
endif ()

View File

@ -5715,7 +5715,7 @@ fail:
#if defined(BUILD_TARGET_X86_32) || defined(BUILD_TARGET_ARM) \
|| defined(BUILD_TARGET_THUMB) || defined(BUILD_TARGET_MIPS) \
|| defined(BUILD_TARGET_XTENSA)
|| defined(BUILD_TARGET_XTENSA) || defined(BUILD_TARGET_HEXAGON)
typedef void (*GenericFunctionPointer)(void);
void
invokeNative(GenericFunctionPointer f, uint32 *args, uint32 sz);

View File

@ -272,93 +272,10 @@ STORE_U16(void *addr, uint16_t value)
((uint8_t *)(addr))[1] = u.u8[1];
}
static inline void
STORE_V128(void *addr, V128 value)
{
uintptr_t addr_ = (uintptr_t)(addr);
union {
V128 val;
uint64 u64[2];
uint32 u32[4];
uint16 u16[8];
uint8 u8[16];
} u;
if ((addr_ & (uintptr_t)15) == 0) {
*(V128 *)addr = value;
}
else if ((addr_ & (uintptr_t)7) == 0) {
u.val = value;
((uint64 *)(addr))[0] = u.u64[0];
((uint64 *)(addr))[1] = u.u64[1];
}
else if ((addr_ & (uintptr_t)3) == 0) {
u.val = value;
((uint32 *)addr)[0] = u.u32[0];
((uint32 *)addr)[1] = u.u32[1];
((uint32 *)addr)[2] = u.u32[2];
((uint32 *)addr)[3] = u.u32[3];
}
else if ((addr_ & (uintptr_t)1) == 0) {
u.val = value;
((uint16 *)addr)[0] = u.u16[0];
((uint16 *)addr)[1] = u.u16[1];
((uint16 *)addr)[2] = u.u16[2];
((uint16 *)addr)[3] = u.u16[3];
((uint16 *)addr)[4] = u.u16[4];
((uint16 *)addr)[5] = u.u16[5];
((uint16 *)addr)[6] = u.u16[6];
((uint16 *)addr)[7] = u.u16[7];
}
else {
u.val = value;
for (int i = 0; i < 16; i++)
((uint8 *)addr)[i] = u.u8[i];
}
}
/* STORE_V128 / LOAD_V128 are defined separately below, guarded by
* WASM_CPU_SUPPORTS_UNALIGNED_SIMD_ACCESS (see Block after line 474). */
/* For LOAD opcodes */
static inline V128
LOAD_V128(void *addr)
{
uintptr_t addr1 = (uintptr_t)addr;
union {
V128 val;
uint64 u64[2];
uint32 u32[4];
uint16 u16[8];
uint8 u8[16];
} u;
if ((addr1 & (uintptr_t)15) == 0)
return *(V128 *)addr;
if ((addr1 & (uintptr_t)7) == 0) {
u.u64[0] = ((uint64 *)addr)[0];
u.u64[1] = ((uint64 *)addr)[1];
}
else if ((addr1 & (uintptr_t)3) == 0) {
u.u32[0] = ((uint32 *)addr)[0];
u.u32[1] = ((uint32 *)addr)[1];
u.u32[2] = ((uint32 *)addr)[2];
u.u32[3] = ((uint32 *)addr)[3];
}
else if ((addr1 & (uintptr_t)1) == 0) {
u.u16[0] = ((uint16 *)addr)[0];
u.u16[1] = ((uint16 *)addr)[1];
u.u16[2] = ((uint16 *)addr)[2];
u.u16[3] = ((uint16 *)addr)[3];
u.u16[4] = ((uint16 *)addr)[4];
u.u16[5] = ((uint16 *)addr)[5];
u.u16[6] = ((uint16 *)addr)[6];
u.u16[7] = ((uint16 *)addr)[7];
}
else {
for (int i = 0; i < 16; i++)
u.u8[i] = ((uint8 *)addr)[i];
}
return u.val;
}
static inline int64
LOAD_I64(void *addr)
{
@ -473,6 +390,133 @@ LOAD_I16(void *addr)
#endif /* WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 */
/*
* LOAD_V128 / STORE_V128 WASM linear memory V128 access.
*
* These are guarded by WASM_CPU_SUPPORTS_UNALIGNED_SIMD_ACCESS rather than
* WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS because some architectures have
* different alignment rules for scalar vs vector memory operations.
*
* PUT_V128_TO_ADDR / GET_V128_FROM_ADDR (frame-local access) remain
* guarded by the scalar flag above since frame locals are accessed via
* scalar C operations, not vector instructions.
*/
#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
/* Already defined: LOAD_V128, STORE_V128 as direct pointer casts */
#elif WASM_CPU_SUPPORTS_UNALIGNED_SIMD_ACCESS != 0
/* The target's SIMD unit supports unaligned vector access, but scalar loads
* require natural alignment. Use memcpy which is safe at any alignment and
* allows the compiler to select the best instruction sequence for the
* target. */
static inline V128
LOAD_V128(void *addr)
{
V128 v;
memcpy(&v, addr, sizeof(V128));
return v;
}
static inline void
STORE_V128(void *addr, V128 value)
{
memcpy(addr, &value, sizeof(V128));
}
#else /* !UNALIGNED_ADDR_ACCESS && !UNALIGNED_SIMD_ACCESS */
/* Neither scalar nor vector unaligned access is supported.
* Check alignment at runtime and use the widest safe access. */
static inline void
STORE_V128(void *addr, V128 value)
{
uintptr_t addr_ = (uintptr_t)(addr);
union {
V128 val;
uint64 u64[2];
uint32 u32[4];
uint16 u16[8];
uint8 u8[16];
} u;
if ((addr_ & (uintptr_t)15) == 0) {
*(V128 *)addr = value;
}
else if ((addr_ & (uintptr_t)7) == 0) {
u.val = value;
((uint64 *)(addr))[0] = u.u64[0];
((uint64 *)(addr))[1] = u.u64[1];
}
else if ((addr_ & (uintptr_t)3) == 0) {
u.val = value;
((uint32 *)addr)[0] = u.u32[0];
((uint32 *)addr)[1] = u.u32[1];
((uint32 *)addr)[2] = u.u32[2];
((uint32 *)addr)[3] = u.u32[3];
}
else if ((addr_ & (uintptr_t)1) == 0) {
u.val = value;
((uint16 *)addr)[0] = u.u16[0];
((uint16 *)addr)[1] = u.u16[1];
((uint16 *)addr)[2] = u.u16[2];
((uint16 *)addr)[3] = u.u16[3];
((uint16 *)addr)[4] = u.u16[4];
((uint16 *)addr)[5] = u.u16[5];
((uint16 *)addr)[6] = u.u16[6];
((uint16 *)addr)[7] = u.u16[7];
}
else {
u.val = value;
for (int i = 0; i < 16; i++)
((uint8 *)addr)[i] = u.u8[i];
}
}
static inline V128
LOAD_V128(void *addr)
{
uintptr_t addr1 = (uintptr_t)addr;
union {
V128 val;
uint64 u64[2];
uint32 u32[4];
uint16 u16[8];
uint8 u8[16];
} u;
if ((addr1 & (uintptr_t)15) == 0)
return *(V128 *)addr;
if ((addr1 & (uintptr_t)7) == 0) {
u.u64[0] = ((uint64 *)addr)[0];
u.u64[1] = ((uint64 *)addr)[1];
}
else if ((addr1 & (uintptr_t)3) == 0) {
u.u32[0] = ((uint32 *)addr)[0];
u.u32[1] = ((uint32 *)addr)[1];
u.u32[2] = ((uint32 *)addr)[2];
u.u32[3] = ((uint32 *)addr)[3];
}
else if ((addr1 & (uintptr_t)1) == 0) {
u.u16[0] = ((uint16 *)addr)[0];
u.u16[1] = ((uint16 *)addr)[1];
u.u16[2] = ((uint16 *)addr)[2];
u.u16[3] = ((uint16 *)addr)[3];
u.u16[4] = ((uint16 *)addr)[4];
u.u16[5] = ((uint16 *)addr)[5];
u.u16[6] = ((uint16 *)addr)[6];
u.u16[7] = ((uint16 *)addr)[7];
}
else {
for (int i = 0; i < 16; i++)
u.u8[i] = ((uint8 *)addr)[i];
}
return u.val;
}
#endif /* WASM_CPU_SUPPORTS_UNALIGNED_SIMD_ACCESS */
#if WASM_ENABLE_SHARED_MEMORY != 0
#define SHARED_MEMORY_LOCK(memory) shared_memory_lock(memory)
#define SHARED_MEMORY_UNLOCK(memory) shared_memory_unlock(memory)

View File

@ -191,7 +191,7 @@ aot_target_precheck_can_use_musttail(const AOTCompContext *comp_ctx)
return false;
}
/*
* x86-64/i386: true
* x86-64/i386/hexagon: true
*
* others: assume true for now
*/
@ -2286,7 +2286,8 @@ static ArchItem valid_archs[] = {
{ "thumbv8.1m.main", true },
{ "riscv32", true },
{ "riscv64", true },
{ "arc", true }
{ "arc", true },
{ "hexagon", false }
};
static const char *valid_abis[] = {
@ -3169,6 +3170,29 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
}
#endif
/* Hexagon: disable small-data addressing; AOT code has no GP
* register set up so GP-relative relocations cannot be resolved. */
{
bool is_hexagon = false;
if (arch && !strcmp(arch, "hexagon"))
is_hexagon = true;
else if (triple_norm && strstr(triple_norm, "hexagon"))
is_hexagon = true;
if (is_hexagon) {
if (features[0] != '\0') {
if (!strstr(features, "-small-data")) {
snprintf(features_buf, sizeof(features_buf),
"%s,-small-data", features);
features = features_buf;
}
}
else {
features = "-small-data";
}
}
}
/* Get target with triple, note that LLVMGetTargetFromTriple()
return 0 when success, but not true. */
if (LLVMGetTargetFromTriple(triple_norm, &target, &err) != 0) {
@ -3386,7 +3410,8 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
if (option->enable_simd && strcmp(comp_ctx->target_arch, "x86_64") != 0
&& strncmp(comp_ctx->target_arch, "aarch64", 7) != 0
&& strcmp(comp_ctx->target_arch, "arc") != 0) {
&& strcmp(comp_ctx->target_arch, "arc") != 0
&& strcmp(comp_ctx->target_arch, "hexagon") != 0) {
/* Disable simd if it isn't supported by target arch */
option->enable_simd = false;
}
@ -3413,6 +3438,14 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
}
}
/* Determine whether the target's SIMD/vector unit supports unaligned
* memory access. This informs alignment annotations emitted for SIMD
* load/store IR. */
comp_ctx->target_supports_unaligned_simd =
!strcmp(comp_ctx->target_arch, "x86_64")
|| !strncmp(comp_ctx->target_arch, "aarch64", 7)
|| !strcmp(comp_ctx->target_arch, "hexagon");
if (!(target_data_ref =
LLVMCreateTargetDataLayout(comp_ctx->target_machine))) {
aot_set_last_error("create LLVM target data layout failed.");

View File

@ -494,6 +494,11 @@ typedef struct AOTCompContext {
bool enable_segue_f64_store;
bool enable_segue_v128_store;
/* Whether the target's SIMD/vector unit supports unaligned access.
* When true, SIMD load/store IR can use align 1 without the backend
* decomposing to byte-by-byte access. */
bool target_supports_unaligned_simd;
/* Whether optimize the JITed code */
bool optimize;

View File

@ -35,7 +35,15 @@ simd_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 align,
return NULL;
}
LLVMSetAlignment(data, 1);
/* WASM SIMD does not guarantee alignment for v128 loads.
* On targets whose SIMD unit handles unaligned access natively,
* align 1 is safe and the backend will select the right instruction.
* On other targets, use the WASM alignment hint so the backend
* can generate wider (aligned) loads instead of byte-by-byte. */
if (comp_ctx->target_supports_unaligned_simd)
LLVMSetAlignment(data, 1);
else
LLVMSetAlignment(data, 1 << align);
return data;
}
@ -301,7 +309,12 @@ simd_store(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 align,
return false;
}
LLVMSetAlignment(result, 1);
/* Mirror the alignment logic in simd_load: targets with native
* unaligned SIMD support use align 1, others use the WASM hint. */
if (comp_ctx->target_supports_unaligned_simd)
LLVMSetAlignment(result, 1);
else
LLVMSetAlignment(result, 1 << align);
return true;
}

View File

@ -0,0 +1,144 @@
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
cmake_minimum_required (VERSION 3.14)
include(CheckPIESupported)
project (iwasm)
option(BUILD_SHARED_LIBS "Build using shared libraries" OFF)
set (CMAKE_VERBOSE_MAKEFILE OFF)
# Hexagon uses the Linux kernel
set (WAMR_BUILD_PLATFORM "linux")
set (WAMR_BUILD_TARGET "HEXAGON")
# Reset default linker flags
set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
set (CMAKE_C_STANDARD 99)
set (CMAKE_CXX_STANDARD 17)
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif ()
if (NOT DEFINED WAMR_BUILD_INTERP)
# Enable Interpreter by default
set (WAMR_BUILD_INTERP 1)
endif ()
if (NOT DEFINED WAMR_BUILD_AOT)
# Enable AOT by default
set (WAMR_BUILD_AOT 1)
endif ()
if (NOT DEFINED WAMR_BUILD_JIT)
# Disable JIT by default
set (WAMR_BUILD_JIT 0)
endif ()
if (NOT DEFINED WAMR_BUILD_FAST_JIT)
# Fast JIT not supported on Hexagon
set (WAMR_BUILD_FAST_JIT 0)
endif ()
if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN)
set (WAMR_BUILD_LIBC_BUILTIN 1)
endif ()
if (NOT DEFINED WAMR_BUILD_LIBC_WASI)
set (WAMR_BUILD_LIBC_WASI 1)
endif ()
if (NOT DEFINED WAMR_BUILD_FAST_INTERP)
set (WAMR_BUILD_FAST_INTERP 1)
endif ()
if (NOT DEFINED WAMR_BUILD_MULTI_MODULE)
set (WAMR_BUILD_MULTI_MODULE 0)
endif ()
if (NOT DEFINED WAMR_BUILD_LIB_PTHREAD)
set (WAMR_BUILD_LIB_PTHREAD 0)
endif ()
if (NOT DEFINED WAMR_BUILD_LIB_WASI_THREADS)
set (WAMR_BUILD_LIB_WASI_THREADS 0)
endif()
if (NOT DEFINED WAMR_BUILD_MINI_LOADER)
set (WAMR_BUILD_MINI_LOADER 0)
endif ()
if (NOT DEFINED WAMR_BUILD_SIMD)
set (WAMR_BUILD_SIMD 1)
endif ()
if (NOT DEFINED WAMR_BUILD_REF_TYPES)
set (WAMR_BUILD_REF_TYPES 1)
endif ()
if (NOT DEFINED WAMR_BUILD_DEBUG_INTERP)
set (WAMR_BUILD_DEBUG_INTERP 0)
endif ()
if (WAMR_BUILD_DEBUG_INTERP EQUAL 1)
set (WAMR_BUILD_FAST_INTERP 0)
set (WAMR_BUILD_MINI_LOADER 0)
set (WAMR_BUILD_SIMD 0)
endif ()
set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
check_pie_supported()
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake)
# Share main.c with Linux platform since Hexagon runs Linux kernel
add_executable (iwasm
${CMAKE_CURRENT_SOURCE_DIR}/../linux/main.c
${UNCOMMON_SHARED_SOURCE}
)
set_version_info (iwasm)
target_link_libraries(iwasm vmlib)
install (TARGETS iwasm DESTINATION bin)
add_library (vmlib ${WAMR_RUNTIME_LIB_SOURCE})
set_version_info (vmlib)
target_include_directories(vmlib INTERFACE
$<INSTALL_INTERFACE:include>
)
set (WAMR_PUBLIC_HEADERS
${WAMR_ROOT_DIR}/core/iwasm/include/wasm_c_api.h
${WAMR_ROOT_DIR}/core/iwasm/include/wasm_export.h
${WAMR_ROOT_DIR}/core/iwasm/include/lib_export.h
)
set_target_properties (vmlib PROPERTIES
OUTPUT_NAME iwasm
PUBLIC_HEADER "${WAMR_PUBLIC_HEADERS}"
)
target_link_libraries (vmlib ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -lpthread)
install (TARGETS vmlib
EXPORT iwasmTargets
DESTINATION lib
PUBLIC_HEADER DESTINATION include
)
install_iwasm_package ()

View File

@ -58,6 +58,7 @@ AVAILABLE_TARGETS = [
"AARCH64_VFP",
"ARMV7",
"ARMV7_VFP",
"HEXAGON",
"RISCV32",
"RISCV32_ILP32F",
"RISCV32_ILP32D",
@ -95,6 +96,19 @@ def ignore_the_case(
if "i386" == target and case_name in ["float_exprs", "conversions"]:
return True
# TODO: investigate Hexagon-specific failures:
# - float_exprs/conversions: Hexagon does not canonicalize NaN payloads
# (sNaN propagation differs from spec expectations)
# - i32/i64: Hexagon asl/asr instructions use signed shift amounts,
# causing clang to miscompile rotl/rotr when upper bits are set
# - simd_*: NaN propagation in pmin/pmax and lane/splat edge cases
if "hexagon" == target and case_name in [
"float_exprs", "conversions", "f32_bitwise", "i32", "i64",
"simd_f32x4_pmin_pmax", "simd_f64x2_pmin_pmax",
"simd_lane", "simd_splat",
]:
return True
# esp32s3 qemu doesn't have PSRAM emulation
if qemu_flag and target == 'xtensa' and case_name in ["memory_size"]:
return True
@ -186,9 +200,13 @@ def test_case(
CMD.append("--interpreter")
if sgx_flag:
CMD.append(IWASM_SGX_CMD)
elif qemu_flag:
elif qemu_flag and qemu_firmware:
# System-emulation (e.g. NuttX): iwasm is a built-in command inside
# the emulated OS, so use the bare name.
CMD.append(IWASM_QEMU_CMD)
else:
# Host execution or QEMU user-mode: use the host path to the iwasm
# binary (which may be a qemu-hexagon wrapper).
CMD.append(IWASM_CMD)
if no_pty:
CMD.append("--no-pty")
@ -220,9 +238,15 @@ def test_case(
CMD.append("--eh")
if qemu_flag:
CMD.append("--qemu")
CMD.append("--qemu-firmware")
CMD.append(qemu_firmware)
if qemu_firmware:
CMD.append("--qemu")
CMD.append("--qemu-firmware")
CMD.append(qemu_firmware)
# Increase timeouts for QEMU emulation (default: 30s start, 20s test)
CMD.append("--start-timeout")
CMD.append("120")
CMD.append("--test-timeout")
CMD.append("120")
if not clean_up_flag:
CMD.append("--no_cleanup")
@ -598,9 +622,20 @@ def main():
)
parser.add_argument('--no-pty', action='store_true',
help="Use direct pipes instead of pseudo-tty")
parser.add_argument(
"--interpreter",
default="",
dest="interpreter",
help="Specify the iwasm interpreter path (overrides the default)",
)
options = parser.parse_args()
# Override global IWASM_CMD if --interpreter is specified
global IWASM_CMD
if options.interpreter:
IWASM_CMD = options.interpreter
# Convert target to lower case for internal use, e.g. X86_64 -> x86_64
# target is always exist, so no need to check it
options.target = options.target.lower()

View File

@ -62,6 +62,7 @@ aot_target_options_map = {
"riscv64_lp64f": ["--target=riscv64", "--target-abi=lp64f", "--cpu=generic-rv64", "--cpu-features=+m,+a,+c,+f", "--size-level=1"],
"riscv64_lp64d": ["--target=riscv64", "--target-abi=lp64d", "--cpu=generic-rv64", "--cpu-features=+m,+a,+c,+f,+d", "--size-level=1"],
"xtensa": ["--target=xtensa"],
"hexagon": ["--target=hexagon"],
}
# AOT compilation options mapping for XIP mode
@ -267,7 +268,7 @@ def assert_prompt(runner, prompts, timeout, is_need_execute_result):
log("Started with:\n%s" % header)
else:
log("Did not one of following prompt(s): %s" % repr(prompts))
log(" Got : %s" % repr(r.buf))
log(" Got : %s" % repr(runner.buf))
raise Exception("Did not one of following prompt(s)")
@ -780,6 +781,8 @@ def is_result_match_expected(out, expected):
def test_assert(r, opts, mode, cmd, expected):
log("Testing(%s) %s = %s" % (mode, cmd, expected))
out = invoke(r, opts, cmd)
if out is None:
raise Exception("Timed out waiting for response to: %s" % cmd)
if '\n' in out or ' ' in out:
outs = [''] + out.split('\n')[1:]
out = outs[-1]

View File

@ -634,7 +634,9 @@ function spec_test()
if [[ ${ENABLE_QEMU} == 1 ]]; then
ARGS_FOR_SPEC_TEST+="--qemu "
ARGS_FOR_SPEC_TEST+="--qemu-firmware ${QEMU_FIRMWARE} "
if [[ -n ${QEMU_FIRMWARE} ]]; then
ARGS_FOR_SPEC_TEST+="--qemu-firmware ${QEMU_FIRMWARE} "
fi
fi
if [[ ${PLATFORM} == "windows" ]]; then