|
|
#!/usr/bin/env bash
|
|
|
set -euo pipefail
|
|
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
|
COMPILER="$ROOT_DIR/build/bin/compiler"
|
|
|
TMP_DIR="$ROOT_DIR/build/test_compiler"
|
|
|
TEST_DIRS=("$ROOT_DIR/test/test_case/functional" "$ROOT_DIR/test/test_case/performance")
|
|
|
|
|
|
if [[ ! -x "$COMPILER" ]]; then
|
|
|
echo "未找到编译器: $COMPILER"
|
|
|
echo "请先构建编译器,例如: mkdir -p build && cd build && cmake .. && make -j"
|
|
|
exit 1
|
|
|
fi
|
|
|
|
|
|
mkdir -p "$TMP_DIR"
|
|
|
|
|
|
ir_total=0
|
|
|
ir_pass=0
|
|
|
result_total=0
|
|
|
result_pass=0
|
|
|
|
|
|
ir_failures=()
|
|
|
result_failures=()
|
|
|
|
|
|
function normalize_file() {
|
|
|
sed 's/\r$//' "$1"
|
|
|
}
|
|
|
|
|
|
for test_dir in "${TEST_DIRS[@]}"; do
|
|
|
if [[ ! -d "$test_dir" ]]; then
|
|
|
echo "跳过不存在的测试目录: $test_dir"
|
|
|
continue
|
|
|
fi
|
|
|
|
|
|
shopt -s nullglob
|
|
|
for input in "$test_dir"/*.sy; do
|
|
|
ir_total=$((ir_total+1))
|
|
|
base=$(basename "$input")
|
|
|
stem=${base%.sy}
|
|
|
out_dir="$TMP_DIR/$(basename "$test_dir")"
|
|
|
mkdir -p "$out_dir"
|
|
|
ll_file="$out_dir/$stem.ll"
|
|
|
stdout_file="$out_dir/$stem.stdout"
|
|
|
expected_file="$test_dir/$stem.out"
|
|
|
stdin_file="$test_dir/$stem.in"
|
|
|
|
|
|
echo "[TEST] $input"
|
|
|
|
|
|
# 编译并捕获所有输出
|
|
|
compiler_status=0
|
|
|
compiler_output=""
|
|
|
compiler_output=$("$COMPILER" --emit-ir "$input" 2>&1) || compiler_status=$?
|
|
|
|
|
|
# 临时文件存储原始输出
|
|
|
raw_ll="$out_dir/$stem.raw.ll"
|
|
|
printf '%s\n' "$compiler_output" > "$raw_ll"
|
|
|
|
|
|
# 检查编译是否成功
|
|
|
if [[ $compiler_status -ne 0 ]]; then
|
|
|
echo " [IR] 编译失败: 返回码 $compiler_status"
|
|
|
ir_failures+=("$input: compiler failed ($compiler_status)")
|
|
|
# 失败:保留原始输出(包含所有调试信息)
|
|
|
cp "$raw_ll" "$ll_file"
|
|
|
rm -f "$raw_ll"
|
|
|
continue
|
|
|
fi
|
|
|
|
|
|
# 检查是否生成了有效的函数定义(在过滤后的内容中检查)
|
|
|
# 先过滤一下看看是否有define
|
|
|
filtered_content=$(sed -E '/^\[DEBUG\]|^SymbolTable::|^Check|^绑定|^保存|^dim_count:/d' "$raw_ll")
|
|
|
if ! echo "$filtered_content" | grep -qE '^define '; then
|
|
|
echo " [IR] 失败: 未生成有效函数定义"
|
|
|
ir_failures+=("$input: invalid IR output")
|
|
|
# 失败:保留原始输出
|
|
|
cp "$raw_ll" "$ll_file"
|
|
|
rm -f "$raw_ll"
|
|
|
continue
|
|
|
fi
|
|
|
|
|
|
# 编译成功:过滤掉所有调试输出,只保留IR
|
|
|
# 过滤规则:
|
|
|
# 1. 以 [DEBUG] 开头的行
|
|
|
# 2. SymbolTable:: 开头的行
|
|
|
# 3. CheckLValue: 开头的行
|
|
|
# 4. 绑定变量: 开头的行
|
|
|
# 5. dim_count: 开头的行
|
|
|
# 6. 空行(可选)
|
|
|
sed -E '/^(\[DEBUG|SymbolTable::|Check|绑定|保存|dim_)/d' "$raw_ll" > "$ll_file"
|
|
|
|
|
|
# 可选:删除多余的空行
|
|
|
sed -i '/^$/N;/\n$/D' "$ll_file"
|
|
|
|
|
|
rm -f "$raw_ll"
|
|
|
|
|
|
ir_pass=$((ir_pass+1))
|
|
|
echo " [IR] 生成成功 (IR已保存到: $ll_file)"
|
|
|
|
|
|
# 运行测试
|
|
|
if [[ -f "$expected_file" ]]; then
|
|
|
result_total=$((result_total+1))
|
|
|
|
|
|
# 运行LLVM IR
|
|
|
run_status=0
|
|
|
if [[ -f "$stdin_file" ]]; then
|
|
|
lli "$ll_file" < "$stdin_file" > "$stdout_file" 2>&1 || run_status=$?
|
|
|
else
|
|
|
lli "$ll_file" > "$stdout_file" 2>&1 || run_status=$?
|
|
|
fi
|
|
|
|
|
|
# 读取预期返回值
|
|
|
expected=$(normalize_file "$expected_file")
|
|
|
|
|
|
# 比较返回值
|
|
|
if [[ "$run_status" -eq "$expected" ]]; then
|
|
|
result_pass=$((result_pass+1))
|
|
|
echo " [RUN] 返回值匹配: $run_status"
|
|
|
# 成功:保留已清理的.ll文件,删除输出文件
|
|
|
rm -f "$stdout_file"
|
|
|
else
|
|
|
echo " [RUN] 返回值不匹配: got $run_status, expected $expected"
|
|
|
result_failures+=("$input: exit code mismatch (got $run_status, expected $expected)")
|
|
|
# 失败:.ll文件已经保留,输出文件也保留用于调试
|
|
|
fi
|
|
|
else
|
|
|
echo " [RUN] 未找到预期返回值文件 $expected_file,跳过结果验证"
|
|
|
fi
|
|
|
done
|
|
|
shopt -u nullglob
|
|
|
done
|
|
|
|
|
|
# 输出统计
|
|
|
cat <<EOF
|
|
|
测试完成。
|
|
|
IR 生成: $ir_pass / $ir_total
|
|
|
结果匹配: $result_pass / $result_total
|
|
|
EOF
|
|
|
|
|
|
# 输出失败列表
|
|
|
if [[ ${#ir_failures[@]} -gt 0 ]]; then
|
|
|
echo ""
|
|
|
echo "IR 失败列表:"
|
|
|
for item in "${ir_failures[@]}"; do
|
|
|
echo " $item"
|
|
|
done
|
|
|
fi
|
|
|
|
|
|
if [[ ${#result_failures[@]} -gt 0 ]]; then
|
|
|
echo ""
|
|
|
echo "结果失败列表:"
|
|
|
for item in "${result_failures[@]}"; do
|
|
|
echo " $item"
|
|
|
done
|
|
|
echo ""
|
|
|
echo "失败的测试文件已保留在: $TMP_DIR"
|
|
|
echo "可以查看对应的.ll文件进行调试"
|
|
|
fi |