#!/bin/bash PROJECT_ROOT=$(cd "$(dirname "$0")/.." ; pwd) COMPILER="$PROJECT_ROOT/build/bin/compiler" TEST_CASE_DIR="$PROJECT_ROOT/test/test_case" TEST_RESULT_DIR="$PROJECT_ROOT/test/test_result/ir" VERIFY_SCRIPT="$PROJECT_ROOT/scripts/verify_ir.sh" PARALLEL=${PARALLEL:-$(nproc)} LOG_FILE="$TEST_RESULT_DIR/verify.log" if [ ! -x "$COMPILER" ]; then echo "错误:编译器不存在或不可执行: $COMPILER" echo "请先构建项目:cmake --build build -j\$(nproc)" exit 1 fi mkdir -p "$TEST_RESULT_DIR" > "$LOG_FILE" # ── 阶段1:IR 生成(并行)──────────────────────────────────────────────────── echo "=== 阶段1:IR 生成 ===" | tee -a "$LOG_FILE" echo "" | tee -a "$LOG_FILE" GEN_TMPDIR=$(mktemp -d) gen_one() { test_file="$1" relative_path=$(realpath --relative-to="$TEST_CASE_DIR" "$test_file") output_file="$TEST_RESULT_DIR/${relative_path%.sy}.ll" mkdir -p "$(dirname "$output_file")" "$COMPILER" --emit-ir "$test_file" > "$output_file" 2>&1 exit_code=$? # Use a per-case tmp file to avoid concurrent write issues case_id=$(echo "$relative_path" | tr '/' '_') if [ $exit_code -eq 0 ] && [ -s "$output_file" ] && ! grep -q '\[error\]' "$output_file"; then echo "通过: $relative_path" > "$GEN_TMPDIR/pass_${case_id}" else echo "$relative_path" > "$GEN_TMPDIR/fail_${case_id}" echo "失败: $relative_path" > "$GEN_TMPDIR/line_fail_${case_id}" fi } export -f gen_one export COMPILER TEST_CASE_DIR TEST_RESULT_DIR GEN_TMPDIR find "$TEST_CASE_DIR" -name "*.sy" -not -path '*/*performance*/*' | sort | \ xargs -P "$PARALLEL" -I{} bash -c 'gen_one "$@"' _ {} # Collect results in sorted order failed_cases=() for f in $(find "$TEST_CASE_DIR" -name "*.sy" | sort); do relative_path=$(realpath --relative-to="$TEST_CASE_DIR" "$f") case_id=$(echo "$relative_path" | tr '/' '_') if [ -f "$GEN_TMPDIR/pass_${case_id}" ]; then cat "$GEN_TMPDIR/pass_${case_id}" | tee -a "$LOG_FILE" elif [ -f "$GEN_TMPDIR/fail_${case_id}" ]; then cat "$GEN_TMPDIR/line_fail_${case_id}" | tee -a "$LOG_FILE" failed_cases+=("$relative_path") fi done pass_count=$(ls "$GEN_TMPDIR"/pass_* 2>/dev/null | wc -l) fail_count=${#failed_cases[@]} rm -rf "$GEN_TMPDIR" echo "" | tee -a "$LOG_FILE" echo "--- 生成完成: 通过 $pass_count / 失败 $fail_count ---" | tee -a "$LOG_FILE" # ── 阶段2:IR 运行验证(并行,需要 llc + clang)────────────────────────────── if ! command -v llc >/dev/null 2>&1 || ! command -v clang >/dev/null 2>&1; then echo "" | tee -a "$LOG_FILE" echo "=== 跳过阶段2:未找到 llc 或 clang,无法运行 IR ===" | tee -a "$LOG_FILE" else echo "" | tee -a "$LOG_FILE" echo "=== 阶段2:IR 运行验证 ===" | tee -a "$LOG_FILE" echo "" | tee -a "$LOG_FILE" VRF_TMPDIR=$(mktemp -d) verify_one() { test_file="$1" relative_path=$(realpath --relative-to="$TEST_CASE_DIR" "$test_file") relative_dir=$(dirname "$relative_path") out_dir="$TEST_RESULT_DIR/$relative_dir" stem=$(basename "${test_file%.sy}") case_log="$out_dir/$stem.verify.log" case_id=$(echo "$relative_path" | tr '/' '_') if bash "$VERIFY_SCRIPT" "$test_file" "$out_dir" --run > "$case_log" 2>&1; then echo "通过: $relative_path" > "$VRF_TMPDIR/pass_${case_id}" else extra=$(grep -E '(退出码|输出不匹配|错误)' "$case_log" | head -3 | sed 's/^/ /' || true) { echo "失败: $relative_path"; [ -n "$extra" ] && echo "$extra"; } > "$VRF_TMPDIR/fail_${case_id}" echo "$relative_path" > "$VRF_TMPDIR/failname_${case_id}" fi } export -f verify_one export TEST_CASE_DIR TEST_RESULT_DIR VERIFY_SCRIPT VRF_TMPDIR find "$TEST_CASE_DIR" -name "*.sy" -not -path '*/*performance*/*' | sort | \ xargs -P "$PARALLEL" -I{} bash -c 'verify_one "$@"' _ {} # Collect results in sorted order verify_failed_cases=() for f in $(find "$TEST_CASE_DIR" -name "*.sy" | sort); do relative_path=$(realpath --relative-to="$TEST_CASE_DIR" "$f") case_id=$(echo "$relative_path" | tr '/' '_') if [ -f "$VRF_TMPDIR/pass_${case_id}" ]; then cat "$VRF_TMPDIR/pass_${case_id}" | tee -a "$LOG_FILE" elif [ -f "$VRF_TMPDIR/fail_${case_id}" ]; then cat "$VRF_TMPDIR/fail_${case_id}" | tee -a "$LOG_FILE" verify_failed_cases+=("$relative_path") fi done verify_pass=$(ls "$VRF_TMPDIR"/pass_* 2>/dev/null | wc -l) verify_fail=${#verify_failed_cases[@]} rm -rf "$VRF_TMPDIR" echo "" | tee -a "$LOG_FILE" echo "--- 验证完成: 通过 $verify_pass / 失败 $verify_fail ---" | tee -a "$LOG_FILE" if [ ${#verify_failed_cases[@]} -gt 0 ]; then echo "" | tee -a "$LOG_FILE" echo "=== 验证失败的用例 ===" | tee -a "$LOG_FILE" for f in "${verify_failed_cases[@]}"; do [ -n "$f" ] && echo " - $f" | tee -a "$LOG_FILE" done fi fi # ── 汇总 ───────────────────────────────────────────────────────────────────── echo "" | tee -a "$LOG_FILE" echo "=== 测试完成 ===" | tee -a "$LOG_FILE" echo "IR生成 通过: $pass_count 失败: $fail_count" | tee -a "$LOG_FILE" echo "结果保存在: $TEST_RESULT_DIR" | tee -a "$LOG_FILE" echo "日志保存在: $LOG_FILE" | tee -a "$LOG_FILE" if [ ${#failed_cases[@]} -gt 0 ]; then echo "" | tee -a "$LOG_FILE" echo "=== IR生成失败的用例 ===" | tee -a "$LOG_FILE" for f in "${failed_cases[@]}"; do [ -n "$f" ] && echo " - $f" | tee -a "$LOG_FILE" done exit 1 fi