From 958f81ccafcd5eb50c618d40f4b63977f1c7e112 Mon Sep 17 00:00:00 2001 From: Pedro Henrique Penna Date: Sat, 16 May 2026 14:37:46 -0700 Subject: [PATCH] [nanvix] Add GCC testsuite integration Introduce infrastructure to run GCC's built-in testsuite against the Nanvix cross-compiler, validating code generation for i686-nanvix and x86_64-nanvix targets. New files: - .nanvix/dejagnu/baseboards/nanvix-sim.exp: DejaGnu board file that configures target capabilities (no signals, no argv, status wrapper), linker flags for libposix.a/user.ld, and simulator invocation. - .nanvix/dejagnu/nanvix-sim-run: Wrapper adapting nanvixd.elf to the simulator interface DejaGnu expects. Logs nanvixd diagnostics to a separate file, passes test program stderr through, and emits a recognizable marker on timeout (--foreground -k 5). - .nanvix/dejagnu/site.exp.in: Template for DejaGnu site configuration that adds the custom board directory to the search path. Modified: - z: Add check_steps() function supporting compile, execute, and all test suites. Integrate into test_steps() as an opt-in step gated by Z_RUN_TORTURE=1 to avoid blocking routine developer test runs. Environment variables are scoped to the make child process. The sim wrapper install is guarded by a writability check. The .sum file is parsed for unexpected failures since make check-gcc always returns 0. Usage: Z_RUN_TORTURE=1 ./z test # smoke + integration + torture tests ./z test # smoke + integration only (default) --- .nanvix/dejagnu/baseboards/nanvix-sim.exp | 65 ++++++++++++ .nanvix/dejagnu/nanvix-sim-run | 65 ++++++++++++ .nanvix/dejagnu/site.exp.in | 11 ++ z | 123 ++++++++++++++++++++++ 4 files changed, 264 insertions(+) create mode 100644 .nanvix/dejagnu/baseboards/nanvix-sim.exp create mode 100755 .nanvix/dejagnu/nanvix-sim-run create mode 100644 .nanvix/dejagnu/site.exp.in diff --git a/.nanvix/dejagnu/baseboards/nanvix-sim.exp b/.nanvix/dejagnu/baseboards/nanvix-sim.exp new file mode 100644 index 00000000000..424ac5cb7ec --- /dev/null +++ b/.nanvix/dejagnu/baseboards/nanvix-sim.exp @@ -0,0 +1,65 @@ +# DejaGnu board file for Nanvix targets (i686-nanvix, x86_64-nanvix). +# +# This board enables running GCC's testsuite against the Nanvix cross-compiler. +# - Compile-only tests work without a simulator. +# - Execution tests use nanvixd.elf via the nanvix-sim-run wrapper script. +# +# Usage: +# make check-gcc RUNTESTFLAGS="--target_board=nanvix-sim" +# +# Environment variables: +# NANVIX_INSTALL_DIR - Path to the Nanvix toolchain install directory +# (default: /opt/nanvix) + +load_generic_config "sim" +load_base_board_description "basic-sim" + +process_multilib_options "" + +# Compiler is found automatically when testing GCC in-tree. +set_board_info compiler "[find_gcc]" + +# Resolve install directory from environment or use default. +if {[info exists ::env(NANVIX_INSTALL_DIR)]} { + set nanvix_install $::env(NANVIX_INSTALL_DIR) +} else { + set nanvix_install "/opt/nanvix" +} + +# Use newlib include/link flags from the build tree if available. +set_board_info cflags "[libgloss_include_flags] [newlib_include_flags]" + +# Link flags for execution tests. Compile-only tests (dg-do compile) never link, +# so these only apply to dg-do run/link tests. +# Note: This board is configured for a single target at a time (i686-nanvix OR +# x86_64-nanvix). The toolchain is built per-target, so the sysroot artifacts in +# ${nanvix_install}/lib/ match the configured target. Multilib is disabled +# (--disable-multilib in the GCC configure step). +set_board_info ldflags "[libgloss_link_flags] [newlib_link_flags] -T ${nanvix_install}/lib/user.ld -Wl,--start-group ${nanvix_install}/lib/libposix.a -lc -Wl,--end-group" + +# Simulator configuration: use the nanvix-sim-run wrapper. +# The wrapper script must be on PATH or specified as an absolute path. +if {[info exists ::env(NANVIX_SIM_RUN)]} { + set_board_info sim $::env(NANVIX_SIM_RUN) +} else { + set_board_info sim "${nanvix_install}/libexec/nanvixd/nanvix-sim-run" +} + +# Time limit for program execution (seconds). +set_board_info sim_time_limit 60 + +# Target capabilities and limitations. +set_board_info is_simulator 1 +set_board_info slow_simulator 1 +# No command-line argument support. +set_board_info noargs 1 +# No signal support. +set_board_info gcc,nosignals 1 +set_board_info gcc,signal_suppress 1 +# No file I/O support beyond stdout. +set_board_info gcc,no_abs 1 +# Compilation timeout (seconds). +set_board_info gcc,timeout 300 +# The simulator does not return exit status via the process exit code; +# DejaGnu must link a status wrapper that prints exit status to stdout. +set_board_info needs_status_wrapper 1 diff --git a/.nanvix/dejagnu/nanvix-sim-run b/.nanvix/dejagnu/nanvix-sim-run new file mode 100755 index 00000000000..5dae2e94987 --- /dev/null +++ b/.nanvix/dejagnu/nanvix-sim-run @@ -0,0 +1,65 @@ +#!/bin/bash +# +# nanvix-sim-run — DejaGnu simulator wrapper for Nanvix. +# +# This script adapts nanvixd.elf to the interface DejaGnu expects: +# nanvix-sim-run +# +# It runs the given ELF binary on nanvixd and passes through stdout/stderr. +# Exit code: 0 if nanvixd ran the program successfully, non-zero otherwise. +# +# Environment variables: +# NANVIX_INSTALL_DIR - Path to the Nanvix toolchain install (default: /opt/nanvix) +# NANVIX_SIM_TIMEOUT - Timeout in seconds (default: 30) +# NANVIX_SIM_LOG_DIR - Directory for nanvixd diagnostic logs (default: /tmp) + +set -euo pipefail + +NANVIX_INSTALL_DIR="${NANVIX_INSTALL_DIR:-/opt/nanvix}" +NANVIX_SIM_TIMEOUT="${NANVIX_SIM_TIMEOUT:-30}" +NANVIX_SIM_LOG_DIR="${NANVIX_SIM_LOG_DIR:-/tmp}" + +nanvixd="${NANVIX_INSTALL_DIR}/libexec/nanvixd/nanvixd.elf" +bin_dir="${NANVIX_INSTALL_DIR}/libexec/nanvixd" + +if [[ $# -lt 1 ]]; then + echo "Usage: nanvix-sim-run " >&2 + exit 1 +fi + +binary="$1" +shift + +if [[ ! -f "${binary}" ]]; then + echo "ERROR: Binary not found: ${binary}" >&2 + exit 1 +fi + +if [[ ! -x "${nanvixd}" ]]; then + echo "ERROR: nanvixd.elf not found at '${nanvixd}'." >&2 + exit 1 +fi + +if ! command -v timeout >/dev/null 2>&1; then + echo "ERROR: 'timeout' utility not available." >&2 + exit 1 +fi + +# Log nanvixd diagnostics to a separate file rather than discarding them; +# the test program's stderr is passed through so DejaGnu can inspect it. +nanvixd_log="${NANVIX_SIM_LOG_DIR}/nanvix-sim-run.$$.log" + +# Run the binary on nanvixd with a kill signal fallback. +# Use --foreground so nanvixd receives signals properly in a pipeline. +timeout --foreground -k 5 "${NANVIX_SIM_TIMEOUT}" \ + "${nanvixd}" \ + -bin-dir "${bin_dir}" \ + -console-file /dev/stdout \ + -- "${binary}" "${nanvixd_log}" +rc=$? + +if [[ $rc -eq 124 ]]; then + echo "NANVIX-SIM-TIMEOUT: Program exceeded ${NANVIX_SIM_TIMEOUT}s time limit." >&2 +fi + +exit $rc diff --git a/.nanvix/dejagnu/site.exp.in b/.nanvix/dejagnu/site.exp.in new file mode 100644 index 00000000000..5d578ca2c27 --- /dev/null +++ b/.nanvix/dejagnu/site.exp.in @@ -0,0 +1,11 @@ +# DejaGnu site configuration for Nanvix GCC testing. +# +# This file is sourced by DejaGnu via the DEJAGNU environment variable. +# It sets up the board search path so that the nanvix-sim board file is found. +# +# Usage: +# export DEJAGNU=/path/to/this/site.exp +# make check-gcc RUNTESTFLAGS="--target_board=nanvix-sim compile.exp" + +# Add the Nanvix board directory to the search path. +lappend boards_dir "@NANVIX_BOARDS_DIR@" diff --git a/z b/z index a1d5987dcac..da864cc5111 100755 --- a/z +++ b/z @@ -480,6 +480,16 @@ test_steps() { echo "Skipping integration test: /dev/kvm not available." fi + # Run GCC compile-only torture tests to validate code generation (opt-in). + if [[ "${Z_RUN_TORTURE:-0}" == "1" ]]; then + check_steps "compile" || { + print_error "GCC testsuite failed." + return 1 + } + else + echo "Skipping GCC torture tests (set Z_RUN_TORTURE=1 to enable)." + fi + return 0 } @@ -568,6 +578,119 @@ verify_steps() { return 0 } +# +# Description +# +# Runs GCC's built-in testsuite (compile-only torture tests) against the +# Nanvix cross-compiler to validate code generation. +# +# Parameters +# +# - $1 (optional): Test suite to run. One of: +# "compile" - compile-only torture tests (default) +# "execute" - execution tests via nanvixd (requires /dev/kvm) +# "all" - both compile and execute +# +# Return Value +# +# - On success, this function returns zero. +# - On failure, this function returns non-zero. +# +check_steps() { + local suite="${1:-compile}" + local build_dir="${PROJECT_DIR}/${Z_PROJECT_BUILD_DIR}" + local dejagnu_dir="${PROJECT_DIR}/.nanvix/dejagnu" + local install_location="${Z_INSTALL_LOCATION}" + + # Verify build directory exists. + if [[ ! -d "${build_dir}/gcc" ]]; then + print_error "Build directory not found. Run './z build' first." + return 1 + fi + + # Generate site.exp from template. + local site_exp="${build_dir}/nanvix-site.exp" + sed "s|@NANVIX_BOARDS_DIR@|${dejagnu_dir}/baseboards|g" \ + "${dejagnu_dir}/site.exp.in" > "${site_exp}" + + # Install the simulator wrapper if the target directory is writable. + local sim_run="${install_location}/libexec/nanvixd/nanvix-sim-run" + if [[ -d "${install_location}/libexec/nanvixd" ]]; then + if [[ -w "${install_location}/libexec/nanvixd" ]]; then + install -m 755 "${dejagnu_dir}/nanvix-sim-run" "${sim_run}" + else + print_warning "Cannot install sim wrapper to '${install_location}/libexec/nanvixd/' (permission denied). Using source copy." + sim_run="${dejagnu_dir}/nanvix-sim-run" + fi + fi + + local runtestflags="--target_board=nanvix-sim" + local -a make_targets=() + + case "${suite}" in + compile) + echo "Running GCC compile-only torture tests..." + runtestflags="${runtestflags} compile.exp" + make_targets=("check-gcc") + ;; + execute) + if [[ ! -w /dev/kvm ]]; then + print_error "/dev/kvm not available; execution tests require KVM." + return 1 + fi + echo "Running GCC execution tests via nanvixd..." + runtestflags="${runtestflags} execute.exp" + make_targets=("check-gcc") + ;; + all) + echo "Running GCC full testsuite (compile + execute)..." + make_targets=("check-gcc") + if [[ ! -w /dev/kvm ]]; then + print_error "/dev/kvm not available; execute suite cannot run." + return 1 + fi + ;; + *) + print_error "Unknown test suite '${suite}'. Use: compile, execute, or all." + return 1 + ;; + esac + + # Run from the build directory with scoped environment variables. + pushd "${build_dir}" > /dev/null + DEJAGNU="${site_exp}" NANVIX_INSTALL_DIR="${install_location}" NANVIX_SIM_RUN="${sim_run}" \ + make "${make_targets[@]}" RUNTESTFLAGS="${runtestflags}" || { + print_error "GCC testsuite failed." + popd > /dev/null + return 1 + } + popd > /dev/null + + # Print summary from the .sum file if available. + # Note: make check-gcc returns 0 even on test failures; we must parse + # the summary file for unexpected failures to detect regressions. + local sum_file="${build_dir}/gcc/testsuite/gcc/gcc.sum" + if [[ -f "${sum_file}" ]]; then + echo "" + echo "=== Test Summary ===" + grep -E "^# of (expected|unexpected)" "${sum_file}" || true + + # Fail if there are unexpected failures or errors. + local unexpected + unexpected=$(grep -c "^# of unexpected failures" "${sum_file}" 2>/dev/null || echo "0") + if [[ "$unexpected" -gt 0 ]]; then + local fail_count + fail_count=$(grep "^# of unexpected failures" "${sum_file}" | awk '{print $NF}') + if [[ "${fail_count:-0}" -gt 0 ]]; then + print_error "GCC testsuite reported ${fail_count} unexpected failure(s)." + return 1 + fi + fi + fi + + return 0 +} + #================================================================================================== # Main Script #==================================================================================================