|
|
#!/usr/bin/env bash
|
|
|
# ./scripts/verify_ir.sh test/test_case/functional/simple_add.sy test/test_result/function/ir --run
|
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
if [[ $# -lt 1 ]]; then
|
|
|
echo "用法: $0 <input.sy> [output_dir] [--run] [-O]" >&2
|
|
|
exit 1
|
|
|
fi
|
|
|
|
|
|
out_dir="test/test_result/ir"
|
|
|
run_exec=false
|
|
|
optimize=false
|
|
|
input=""
|
|
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
|
case "$1" in
|
|
|
--run)
|
|
|
run_exec=true
|
|
|
;;
|
|
|
-O|--optimize)
|
|
|
optimize=true
|
|
|
;;
|
|
|
-*)
|
|
|
echo "未知选项: $1" >&2
|
|
|
exit 1
|
|
|
;;
|
|
|
*)
|
|
|
if [[ -z "$input" ]]; then
|
|
|
input="$1"
|
|
|
else
|
|
|
out_dir="$1"
|
|
|
fi
|
|
|
;;
|
|
|
esac
|
|
|
shift
|
|
|
done
|
|
|
|
|
|
if [[ -z "$input" ]]; then
|
|
|
echo "未指定输入文件" >&2
|
|
|
exit 1
|
|
|
fi
|
|
|
|
|
|
input_dir=$(dirname "$input")
|
|
|
|
|
|
if [[ ! -f "$input" ]]; then
|
|
|
echo "输入文件不存在: $input" >&2
|
|
|
exit 1
|
|
|
fi
|
|
|
|
|
|
compiler="./build/bin/compiler"
|
|
|
if [[ ! -x "$compiler" ]]; then
|
|
|
echo "未找到编译器: $compiler ,请先构建(如: mkdir -p build && cd build && cmake .. && make -j)" >&2
|
|
|
exit 1
|
|
|
fi
|
|
|
|
|
|
mkdir -p "$out_dir"
|
|
|
base=$(basename "$input")
|
|
|
stem=${base%.sy}
|
|
|
out_file="$out_dir/$stem.ll"
|
|
|
stdin_file="$input_dir/$stem.in"
|
|
|
expected_file="$input_dir/$stem.out"
|
|
|
|
|
|
# 记录编译开始时间
|
|
|
compile_start=$(date +%s%N)
|
|
|
|
|
|
if [[ "$optimize" == true ]]; then
|
|
|
"$compiler" -O --emit-ir "$input" > "$out_file"
|
|
|
else
|
|
|
"$compiler" --emit-ir "$input" > "$out_file"
|
|
|
fi
|
|
|
|
|
|
# 记录编译结束时间
|
|
|
compile_end=$(date +%s%N)
|
|
|
compile_time=$(( ($compile_end - $compile_start) / 1000000 ))
|
|
|
|
|
|
if [[ "$run_exec" == true ]]; then
|
|
|
if ! command -v llc >/dev/null 2>&1; then
|
|
|
echo "未找到 llc,无法运行 IR。请安装 LLVM。" >&2
|
|
|
exit 1
|
|
|
fi
|
|
|
if ! command -v clang >/dev/null 2>&1; then
|
|
|
echo "未找到 clang,无法链接可执行文件。请安装 LLVM/Clang。" >&2
|
|
|
exit 1
|
|
|
fi
|
|
|
|
|
|
obj="$out_dir/$stem.o"
|
|
|
exe="$out_dir/$stem"
|
|
|
stdout_file="$out_dir/$stem.stdout"
|
|
|
actual_file="$out_dir/$stem.actual.out"
|
|
|
sylib_obj="$out_dir/sylib.o"
|
|
|
|
|
|
# 记录链接开始时间
|
|
|
link_start=$(date +%s%N)
|
|
|
|
|
|
if [[ ! -f "$sylib_obj" ]]; then
|
|
|
gcc -c sylib/sylib.c -o "$sylib_obj"
|
|
|
fi
|
|
|
llc -O0 -filetype=obj "$out_file" -o "$obj"
|
|
|
clang "$obj" "$sylib_obj" -o "$exe"
|
|
|
|
|
|
# 记录链接结束时间
|
|
|
link_end=$(date +%s%N)
|
|
|
link_time=$(( ($link_end - $link_start) / 1000000 ))
|
|
|
|
|
|
# 记录执行开始时间
|
|
|
exec_start=$(date +%s%N)
|
|
|
|
|
|
set +e
|
|
|
if [[ -f "$stdin_file" ]]; then
|
|
|
(ulimit -s 65536 && "$exe" < "$stdin_file" > "$stdout_file")
|
|
|
else
|
|
|
(ulimit -s 65536 && "$exe" > "$stdout_file")
|
|
|
fi
|
|
|
status=$?
|
|
|
set -e
|
|
|
|
|
|
# 记录执行结束时间
|
|
|
exec_end=$(date +%s%N)
|
|
|
exec_time=$(( ($exec_end - $exec_start) / 1000000 ))
|
|
|
|
|
|
# 保存运行时间到文件(只保存执行时间,不包含编译和链接时间)
|
|
|
time_file="$out_dir/${stem}_time.txt"
|
|
|
echo "$exec_time" > "$time_file"
|
|
|
|
|
|
# 保存输出(用于比对)
|
|
|
{
|
|
|
cat "$stdout_file"
|
|
|
# 确保 stdout 以换行结尾
|
|
|
if [[ -s "$stdout_file" ]] && (( $(tail -c 1 "$stdout_file" | wc -l) == 0 )); then
|
|
|
printf '\n'
|
|
|
fi
|
|
|
printf '%s\n' "$status"
|
|
|
} > "$actual_file"
|
|
|
|
|
|
# 比对输出
|
|
|
if [[ -f "$expected_file" ]]; then
|
|
|
temp_expected="$out_dir/$stem.expected.tmp"
|
|
|
temp_actual="$out_dir/$stem.actual.tmp"
|
|
|
tr -d '\r' < "$expected_file" > "$temp_expected"
|
|
|
tr -d '\r' < "$actual_file" > "$temp_actual"
|
|
|
|
|
|
if [[ -s "$temp_expected" ]] && (( $(tail -c 1 "$temp_expected" | wc -l) == 0 )); then
|
|
|
if [[ -s "$temp_actual" ]] && (( $(tail -c 1 "$temp_actual" | wc -l) == 1 )); then
|
|
|
truncate -s -1 "$temp_actual"
|
|
|
fi
|
|
|
fi
|
|
|
|
|
|
if diff -u "$temp_expected" "$temp_actual" > /dev/null 2>&1; then
|
|
|
rm -f "$temp_expected" "$temp_actual"
|
|
|
else
|
|
|
echo "输出不匹配: $expected_file" >&2
|
|
|
rm -f "$temp_expected" "$temp_actual"
|
|
|
exit 1
|
|
|
fi
|
|
|
fi
|
|
|
fi |