|
|
#!/usr/bin/env bash
|
|
|
# 串行执行IR测试脚本,实时输出结果
|
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
PROJECT_ROOT=$(cd "$(dirname "$0")/.." ; pwd)
|
|
|
|
|
|
# 默认参数
|
|
|
TEST_CASE_DIR="${PROJECT_ROOT}/test/test_case"
|
|
|
TEST_RESULT_DIR="${PROJECT_ROOT}/test/test_result/ir"
|
|
|
RUN_EXEC=false
|
|
|
VERBOSE=false
|
|
|
OPT_FLAG="-O1" # 默认开启优化
|
|
|
|
|
|
# 解析命令行参数
|
|
|
while [[ $# -gt 0 ]]; do
|
|
|
case "$1" in
|
|
|
--run)
|
|
|
RUN_EXEC=true
|
|
|
;;
|
|
|
--verbose|-v)
|
|
|
VERBOSE=true
|
|
|
;;
|
|
|
--O0)
|
|
|
OPT_FLAG=""
|
|
|
;;
|
|
|
--O1)
|
|
|
OPT_FLAG="-O1"
|
|
|
;;
|
|
|
--test-dir=*)
|
|
|
TEST_CASE_DIR="${1#*=}"
|
|
|
;;
|
|
|
--result-dir=*)
|
|
|
TEST_RESULT_DIR="${1#*=}"
|
|
|
;;
|
|
|
*)
|
|
|
echo "未知参数: $1" >&2
|
|
|
echo "用法: $0 [--run] [--O0|--O1] [--verbose] [--test-dir=<dir>] [--result-dir=<dir>]" >&2
|
|
|
exit 1
|
|
|
;;
|
|
|
esac
|
|
|
shift
|
|
|
done
|
|
|
|
|
|
# 检查编译器是否存在
|
|
|
compiler="${PROJECT_ROOT}/build/bin/compiler"
|
|
|
if [[ ! -x "$compiler" ]]; then
|
|
|
echo "错误:未找到编译器 $compiler" >&2
|
|
|
echo "请先构建项目: mkdir -p build && cd build && cmake .. && make -j" >&2
|
|
|
exit 1
|
|
|
fi
|
|
|
|
|
|
# 创建输出目录
|
|
|
mkdir -p "$TEST_RESULT_DIR"
|
|
|
|
|
|
# 统计变量
|
|
|
total_tests=0
|
|
|
passed_tests=0
|
|
|
failed_tests=0
|
|
|
|
|
|
# 汇总日志文件
|
|
|
summary_log="${TEST_RESULT_DIR}/summary.log"
|
|
|
> "$summary_log"
|
|
|
|
|
|
# 失败测试列表
|
|
|
failed_list=""
|
|
|
|
|
|
echo "=== 开始IR测试 ==="
|
|
|
echo "测试目录: $TEST_CASE_DIR"
|
|
|
echo "结果目录: $TEST_RESULT_DIR"
|
|
|
echo "优化级别: ${OPT_FLAG:--O0}"
|
|
|
echo "运行可执行文件: $RUN_EXEC"
|
|
|
echo ""
|
|
|
|
|
|
# 串行遍历所有测试用例
|
|
|
while read -r test_file; do
|
|
|
total_tests=$((total_tests + 1))
|
|
|
|
|
|
# 计算相对路径
|
|
|
full_path=$(readlink -f "$test_file")
|
|
|
test_case_path=$(readlink -f "$TEST_CASE_DIR")
|
|
|
relative_path="${full_path#$test_case_path}"
|
|
|
# 确保路径以 / 开头
|
|
|
if [[ "${relative_path:0:1}" != "/" ]]; then
|
|
|
relative_path="/$relative_path"
|
|
|
fi
|
|
|
|
|
|
# 计算输出文件路径
|
|
|
base=$(basename "$test_file")
|
|
|
stem="${base%.sy}"
|
|
|
output_file="${TEST_RESULT_DIR}/${relative_path%.sy}.ll"
|
|
|
output_dir=$(dirname "$output_file")
|
|
|
|
|
|
# 创建输出目录
|
|
|
mkdir -p "$output_dir"
|
|
|
|
|
|
# 获取输入和预期输出文件路径
|
|
|
input_dir=$(dirname "$test_file")
|
|
|
stdin_file="${input_dir}/${stem}.in"
|
|
|
expected_file="${input_dir}/${stem}.out"
|
|
|
|
|
|
# 每个测试用例的详细日志文件
|
|
|
test_log="${output_dir}/${stem}.log"
|
|
|
> "$test_log"
|
|
|
|
|
|
echo "[$total_tests] 处理: $relative_path"
|
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 开始处理: $relative_path" >> "$test_log"
|
|
|
echo "输入文件: $test_file" >> "$test_log"
|
|
|
echo "输出目录: $output_dir" >> "$test_log"
|
|
|
|
|
|
# 生成IR
|
|
|
if $VERBOSE; then
|
|
|
echo " 生成IR..."
|
|
|
fi
|
|
|
echo "步骤1: 生成IR" >> "$test_log"
|
|
|
|
|
|
# 计时编译
|
|
|
compile_start=$(date +%s.%N)
|
|
|
set +e
|
|
|
"$compiler" "$test_file" -IR -o "$output_file" $OPT_FLAG 2>&1
|
|
|
ir_status=$?
|
|
|
set -e
|
|
|
compile_end=$(date +%s.%N)
|
|
|
compile_time=$(python3 -c "print(f'{float($compile_end)-float($compile_start):.3f}s')" 2>/dev/null || echo "-")
|
|
|
|
|
|
if [[ $ir_status -ne 0 ]]; then
|
|
|
echo " ✗ IR生成失败"
|
|
|
echo "结果: FAILED (IR生成失败)" >> "$test_log"
|
|
|
echo "错误信息:" >> "$test_log"
|
|
|
cat "$output_file" >> "$test_log"
|
|
|
failed_tests=$((failed_tests + 1))
|
|
|
failed_list="$failed_list\n[$total_tests] $relative_path - IR生成失败"
|
|
|
if $VERBOSE; then
|
|
|
cat "$output_file"
|
|
|
fi
|
|
|
echo ""
|
|
|
continue
|
|
|
fi
|
|
|
|
|
|
echo "IR文件: $output_file" >> "$test_log"
|
|
|
if $VERBOSE; then
|
|
|
echo " ✓ IR已生成: $output_file"
|
|
|
fi
|
|
|
|
|
|
# 如果需要运行可执行文件
|
|
|
if [[ "$RUN_EXEC" == true ]]; then
|
|
|
echo "步骤2: 编译和运行" >> "$test_log"
|
|
|
|
|
|
if ! command -v llc >/dev/null 2>&1; then
|
|
|
echo " 警告: 未找到 llc,跳过执行测试" >&2
|
|
|
echo "警告: 未找到 llc,跳过执行测试" >> "$test_log"
|
|
|
echo "结果: SKIPPED (缺少llc)" >> "$test_log"
|
|
|
passed_tests=$((passed_tests + 1))
|
|
|
echo ""
|
|
|
continue
|
|
|
fi
|
|
|
if ! command -v clang >/dev/null 2>&1; then
|
|
|
echo " 警告: 未找到 clang,跳过执行测试" >&2
|
|
|
echo "警告: 未找到 clang,跳过执行测试" >> "$test_log"
|
|
|
echo "结果: SKIPPED (缺少clang)" >> "$test_log"
|
|
|
passed_tests=$((passed_tests + 1))
|
|
|
echo ""
|
|
|
continue
|
|
|
fi
|
|
|
|
|
|
obj="${output_dir}/${stem}.o"
|
|
|
exe="${output_dir}/${stem}"
|
|
|
stdout_file="${output_dir}/${stem}.stdout"
|
|
|
actual_file="${output_dir}/${stem}.actual.out"
|
|
|
|
|
|
# 编译IR为目标文件
|
|
|
if $VERBOSE; then
|
|
|
echo " 编译IR..."
|
|
|
fi
|
|
|
echo "编译IR: llc -filetype=obj $output_file -o $obj" >> "$test_log"
|
|
|
llc -filetype=obj "$output_file" -o "$obj" 2>/dev/null
|
|
|
if [[ $? -ne 0 ]]; then
|
|
|
echo " ✗ IR编译失败"
|
|
|
echo "结果: FAILED (IR编译失败)" >> "$test_log"
|
|
|
failed_tests=$((failed_tests + 1))
|
|
|
failed_list="$failed_list\n[$total_tests] $relative_path - IR编译失败"
|
|
|
echo ""
|
|
|
continue
|
|
|
fi
|
|
|
echo "目标文件: $obj" >> "$test_log"
|
|
|
|
|
|
# 链接为可执行文件
|
|
|
echo "链接: clang $obj ${PROJECT_ROOT}/sylib/sylib.c -o $exe -lm" >> "$test_log"
|
|
|
clang "$obj" "${PROJECT_ROOT}/sylib/sylib.c" -o "$exe" -lm 2>/dev/null
|
|
|
if [[ $? -ne 0 ]]; then
|
|
|
echo " ✗ 链接失败"
|
|
|
echo "结果: FAILED (链接失败)" >> "$test_log"
|
|
|
failed_tests=$((failed_tests + 1))
|
|
|
failed_list="$failed_list\n[$total_tests] $relative_path - 链接失败"
|
|
|
echo ""
|
|
|
continue
|
|
|
fi
|
|
|
echo "可执行文件: $exe" >> "$test_log"
|
|
|
|
|
|
# 运行可执行文件
|
|
|
if $VERBOSE; then
|
|
|
echo " 运行..."
|
|
|
fi
|
|
|
echo "运行命令: $exe" >> "$test_log"
|
|
|
if [[ -f "$stdin_file" ]]; then
|
|
|
echo "标准输入: $stdin_file" >> "$test_log"
|
|
|
fi
|
|
|
run_start=$(date +%s.%N)
|
|
|
set +e
|
|
|
if [[ -f "$stdin_file" ]]; then
|
|
|
(ulimit -s unlimited; "$exe" < "$stdin_file") > "$stdout_file"
|
|
|
else
|
|
|
(ulimit -s unlimited; "$exe") > "$stdout_file"
|
|
|
fi
|
|
|
status=$?
|
|
|
set -e
|
|
|
run_end=$(date +%s.%N)
|
|
|
run_time=$(python3 -c "print(f'{float($run_end)-float($run_start):.3f}s')" 2>/dev/null || echo "-")
|
|
|
echo "退出码: $status" >> "$test_log"
|
|
|
echo "标准输出:" >> "$test_log"
|
|
|
cat "$stdout_file" >> "$test_log"
|
|
|
|
|
|
# 保存实际输出(包含退出码)
|
|
|
{
|
|
|
cat "$stdout_file"
|
|
|
if [[ -s "$stdout_file" ]] && (( $(tail -c 1 "$stdout_file" | wc -l) == 0 )); then
|
|
|
printf '\n'
|
|
|
fi
|
|
|
printf '%s\n' "$status"
|
|
|
} > "$actual_file"
|
|
|
|
|
|
# 比对输出
|
|
|
echo "步骤3: 比对输出" >> "$test_log"
|
|
|
if [[ -f "$expected_file" ]]; then
|
|
|
echo "预期输出: $expected_file" >> "$test_log"
|
|
|
echo "实际输出: $actual_file" >> "$test_log"
|
|
|
|
|
|
if diff <(tr -d '\r' < "$expected_file" | sed -e '$a\') \
|
|
|
<(tr -d '\r' < "$actual_file" | sed -e '$a\') > /dev/null 2>&1; then
|
|
|
echo " ✓ 编译:${compile_time} 运行:${run_time}"
|
|
|
echo "结果: PASSED (输出匹配)" >> "$test_log"
|
|
|
passed_tests=$((passed_tests + 1))
|
|
|
else
|
|
|
echo " ✗ 输出不匹配"
|
|
|
echo "结果: FAILED (输出不匹配)" >> "$test_log"
|
|
|
echo "差异:" >> "$test_log"
|
|
|
diff <(tr -d '\r' < "$expected_file" | sed -e '$a\') \
|
|
|
<(tr -d '\r' < "$actual_file" | sed -e '$a\') >> "$test_log" 2>&1 || true
|
|
|
failed_tests=$((failed_tests + 1))
|
|
|
failed_list="$failed_list\n[$total_tests] $relative_path - 输出不匹配"
|
|
|
if $VERBOSE; then
|
|
|
echo " 预期:"
|
|
|
cat "$expected_file"
|
|
|
echo " 实际:"
|
|
|
cat "$actual_file"
|
|
|
fi
|
|
|
fi
|
|
|
else
|
|
|
echo " ? 无预期输出文件,跳过比对 (编译:${compile_time})"
|
|
|
echo "警告: 无预期输出文件,跳过比对" >> "$test_log"
|
|
|
echo "结果: SKIPPED (无预期输出)" >> "$test_log"
|
|
|
passed_tests=$((passed_tests + 1))
|
|
|
fi
|
|
|
else
|
|
|
echo "步骤2: 跳过执行测试 (--run未启用)" >> "$test_log"
|
|
|
echo "结果: PASSED (仅IR生成)" >> "$test_log"
|
|
|
passed_tests=$((passed_tests + 1))
|
|
|
echo " ✓ 编译:${compile_time}"
|
|
|
fi
|
|
|
|
|
|
echo ""
|
|
|
done < <(find "$TEST_CASE_DIR" -name "*.sy" | sort)
|
|
|
|
|
|
# 输出统计结果到终端
|
|
|
echo "=== 测试完成 ==="
|
|
|
echo "总测试数: $total_tests"
|
|
|
echo "通过: $passed_tests"
|
|
|
echo "失败: $failed_tests"
|
|
|
|
|
|
# 写入汇总日志
|
|
|
echo "=== IR测试汇总报告 ===" > "$summary_log"
|
|
|
echo "测试时间: $(date '+%Y-%m-%d %H:%M:%S')" >> "$summary_log"
|
|
|
echo "测试目录: $TEST_CASE_DIR" >> "$summary_log"
|
|
|
echo "结果目录: $TEST_RESULT_DIR" >> "$summary_log"
|
|
|
echo "运行可执行文件: $RUN_EXEC" >> "$summary_log"
|
|
|
echo "" >> "$summary_log"
|
|
|
echo "=== 统计结果 ===" >> "$summary_log"
|
|
|
echo "总测试数: $total_tests" >> "$summary_log"
|
|
|
echo "通过: $passed_tests" >> "$summary_log"
|
|
|
echo "失败: $failed_tests" >> "$summary_log"
|
|
|
echo "成功率: $((passed_tests * 100 / total_tests))%" >> "$summary_log"
|
|
|
echo "" >> "$summary_log"
|
|
|
|
|
|
if [[ $failed_tests -gt 0 ]]; then
|
|
|
echo "=== 失败测试列表 ===" >> "$summary_log"
|
|
|
echo -e "$failed_list" >> "$summary_log"
|
|
|
fi
|
|
|
|
|
|
echo "详细日志已保存到各测试用例目录"
|
|
|
echo "汇总日志: $summary_log"
|
|
|
|
|
|
if [[ $failed_tests -eq 0 ]]; then
|
|
|
echo "所有测试通过!"
|
|
|
exit 0
|
|
|
else
|
|
|
echo "有 $failed_tests 个测试失败"
|
|
|
exit 1
|
|
|
fi |