bytecodealliance / wasm-micro-runtime

WebAssembly Micro Runtime (WAMR)
Apache License 2.0
4.68k stars 583 forks source link

AoT Compiler introduces bugs at opt level > 0 #2397

Open I-mikan-I opened 11 months ago

I-mikan-I commented 11 months ago

Commit Hash: f69ff7058783bc5dcaaa81c9d6c88c0d534881fc

Issue Description

When i compile certain WASM modules using an opt-level > 0, its execution fails with a division by zero error. opt-level 0 and the fast interpreter do not raise any errors.

Environment Description

Input file: wikisort.tar.gz

Compilation settings:
wamrc --target=thumbv7 --cpu=cortex-m4 --cpu-features=vfp4d16sp --opt-level=3 --size-level=3

Target hardware: STM32L4R9-DISCO

WAMR Build Configuration:

set (WAMR_BUILD_TARGET "THUMBV7_VFP")
set (WAMR_BUILD_INTERP 1)
set (WAMR_BUILD_FAST_INTERP 1)
set (WAMR_BUILD_LIBC_BUILTIN 1)
set (WAMR_BUILD_LIBC_WASI 0)
set (WAMR_BUILD_LIB_PTHREAD 0)
set (WAMR_DISABLE_HW_BOUND_CHECK 0)
set (WAMR_BUILD_AOT 1)
set (WAMR_DISABLE_STACK_HW_BOUND_CHECK 0)

WAMR Runtime Settings:

RuntimeInitArgs runtime_args = {
    .mem_alloc_type = Alloc_With_System_Allocator,
    .running_mode = Mode_Interp,
};

Instructions for Recreation

Run the _initialize function followed by _run of the AoT compiled module, both with no arguments. the WASM module is compiled as a reactor.

TianlongLiang commented 11 months ago

I have an STM32F4291-DISC1 board on my hand, I will try your program and see what I can do.

TianlongLiang commented 11 months ago

Hi, I am getting a little rusty with how to run the program on an embedding device, could you please tell me how you run the program on that device? It would be helpful if you tell me which framework(RTOS) you are using and how you run your program.

Were you using Zephyr/simple with test_wasm.h replaced with binary content of AOT file?

I-mikan-I commented 11 months ago

Hi!

My setup takes a bit of configuration to reproduce:

I use libopencm3 to setup the C runtime and execute WAMR from plain C. libopencm3 is gnu make based but you can include it in a CMake project as follows: (note: this is for the l4, not f4)

add_custom_command(OUTPUT ${OPENCMDIR}/lib/libopencm3_stm32l4.a
                    COMMAND make TARGETS='stm32/l4 CC=$ARMGCC/arm-none-eabi-gcc'
                    WORKING_DIRECTORY ${OPENCMDIR})

target_sources(wamr PRIVATE ${OPENCMDIR}/lib/libopencm3_stm32l4.a)
target_link_libraries(wamr PUBLIC ${OPENCMDIR}/lib/libopencm3_stm32l4.a)
target_link_options(wamr PUBLIC -T ${CMAKE_CURRENT_LIST_DIR}/device.ld)
target_compile_options(wamr PUBLIC -DSTM32L4=1)

You can debug the program using JLink/ST-link. If you need printf output you have to manually set it up using arm hardware registers and implement newlib stub _write. In my case this is done as follows but the f4 may have different clocks/registers:

static void clock_setup(void)
{
    rcc_clock_setup_pll(&rcc_hsi16_configs[RCC_CLOCK_VRANGE1_80MHZ]);

    rcc_periph_reset_pulse(RCC_AHB1RSTR);
    rcc_periph_reset_pulse(RCC_AHB2RSTR);
    rcc_periph_clock_enable(RCC_AHB1ENR);
    rcc_periph_clock_enable(RCC_AHB2ENR);

    /* Enable GPIOA clock for LED & USARTs. */
    rcc_periph_clock_enable(RCC_GPIOA);

    /* Enable clocks for USART2. */
    rcc_periph_clock_enable(RCC_USART2);

    systick_set_reload(UINT32_MAX);
    // systick_set_frequency(1000, 80000000);
    systick_set_frequency(1000, 80000000);

    systick_interrupt_enable();
    systick_counter_enable();

    return;
}

static void usart_setup(void)
{
    /* Setup USART2 parameters. */
    usart_set_baudrate(USART2, 115200);
    usart_set_databits(USART2, 8);
    usart_set_stopbits(USART2, USART_STOPBITS_1);
    usart_set_mode(USART2, USART_MODE_TX);
    usart_set_parity(USART2, USART_PARITY_NONE);
    usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE);

    /* Finally enable the USART. */
    usart_enable(USART2);
}

static void gpio_setup(void)
{
    /* Setup GPIO pins for USART2 transmit. */
    gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO1 | GPIO2);

    /* Setup USART2 TX pin as alternate function. */
    gpio_set_af(GPIOA, GPIO_AF7, GPIO1 | GPIO2);
}

int init(void)
{
    int i, j = 0, c = 0;

    clock_setup();
    gpio_setup();
    usart_setup();

    return 0;
}

You can find examples on the libopencm3 github repository, I pieced together my startup code from there 😅.

TianlongLiang commented 11 months ago

Thanks! I will try to set up the config(wish me luck for it's been a while since the embedding course from college) and reproduce the bug. I will keep you updated!

I-mikan-I commented 11 months ago

You might be able to reproduce the issue with any framework. WAMR reported the division by zero error/exception, and my board did not panic/trap.