You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nudt-compiler-cpp/scripts/verify_asm.sh

236 lines
5.7 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/usr/bin/env bash
set -euo pipefail
if [[ $# -lt 1 ]]; then
echo "用法: $0 <input.sy> [output_dir] [--run] [-O]" >&2
exit 1
fi
input=$1
out_dir="test/test_result/asm"
run_exec=false
optimize=false
input_dir=$(dirname "$input")
shift
while [[ $# -gt 0 ]]; do
case "$1" in
--run)
run_exec=true
;;
-O|--optimize)
optimize=true
;;
*)
out_dir="$1"
;;
esac
shift
done
if [[ ! -f "$input" ]]; then
echo "输入文件不存在: $input" >&2
exit 1
fi
compiler="./build/bin/compiler"
if [[ ! -x "$compiler" ]]; then
echo "未找到编译器: $compiler ,请先构建。" >&2
exit 1
fi
if ! command -v aarch64-linux-gnu-gcc >/dev/null 2>&1; then
echo "未找到 aarch64-linux-gnu-gcc无法汇编/链接。" >&2
exit 1
fi
if ! command -v qemu-aarch64 >/dev/null 2>&1 && [[ "$run_exec" == true ]]; then
echo "未找到 qemu-aarch64无法运行生成的可执行文件。" >&2
exit 1
fi
find_runtime() {
if [[ -n "${SYSY_RUNTIME:-}" ]]; then
if [[ -f "$SYSY_RUNTIME" ]]; then
printf '%s\n' "$SYSY_RUNTIME"
return 0
fi
echo "环境变量 SYSY_RUNTIME 指向的文件不存在: $SYSY_RUNTIME" >&2
return 1
fi
local candidates=(
"./sylib/sylib.c"
"./sylib.c"
"./runtime/sylib.c"
"./lib/sylib.c"
)
local candidate
for candidate in "${candidates[@]}"; do
if [[ -f "$candidate" ]]; then
printf '%s\n' "$candidate"
return 0
fi
done
local found=""
found=$(find . \
-path './build' -prune -o \
-path './.git' -prune -o \
-type f -name 'sylib.c' -print | head -n 1)
if [[ -n "$found" ]]; then
printf '%s\n' "$found"
return 0
fi
return 1
}
# 获取当前时间戳(毫秒级)
get_timestamp_ms() {
if [[ "$OSTYPE" == "darwin"* ]]; then
if command -v gdate >/dev/null 2>&1; then
gdate +%s%3N
else
perl -MTime::HiRes -e 'printf "%d\n", Time::HiRes::time() * 1000' 2>/dev/null || date +%s%3N
fi
else
date +%s%3N 2>/dev/null || date +%s000
fi
}
runtime_src="$(find_runtime || true)"
if [[ -z "$runtime_src" ]]; then
echo "未找到运行时库源码 sylib.c" >&2
echo "可以显式指定SYSY_RUNTIME=/你的路径/sylib.c $0 <input.sy> [output_dir] [--run]" >&2
exit 1
fi
runtime_cache_dir="./build/test_runtime"
runtime_obj="$runtime_cache_dir/sylib.o"
mkdir -p "$runtime_cache_dir"
# 编译运行时库(如果需要)
if [[ ! -f "$runtime_obj" || "$runtime_src" -nt "$runtime_obj" ]]; then
aarch64-linux-gnu-gcc -O2 -c "$runtime_src" -o "$runtime_obj"
fi
mkdir -p "$out_dir"
base=$(basename "$input")
stem=${base%.sy}
asm_file="$out_dir/$stem.s"
exe="$out_dir/$stem"
stdin_file="$input_dir/$stem.in"
expected_file="$input_dir/$stem.out"
# 记录编译(生成汇编)开始时间
compile_start=$(get_timestamp_ms)
if [[ "$optimize" == true ]]; then
"$compiler" -O --emit-asm "$input" > "$asm_file"
else
"$compiler" --emit-asm "$input" > "$asm_file"
fi
# 记录编译结束时间
compile_end=$(get_timestamp_ms)
compile_time=$((compile_end - compile_start))
# 记录汇编+链接开始时间
assemble_start=$(get_timestamp_ms)
aarch64-linux-gnu-gcc "$asm_file" "$runtime_obj" -o "$exe"
# 记录汇编+链接结束时间
assemble_end=$(get_timestamp_ms)
assemble_time=$((assemble_end - assemble_start))
if [[ "$run_exec" == true ]]; then
stdout_file="$out_dir/$stem.stdout"
actual_file="$out_dir/$stem.actual.out"
set +e
# 记录执行开始时间
exec_start=$(get_timestamp_ms)
if [[ -f "$stdin_file" ]]; then
qemu-aarch64 -L /usr/aarch64-linux-gnu -s 104857600 "$exe" < "$stdin_file" > "$stdout_file"
else
qemu-aarch64 -L /usr/aarch64-linux-gnu -s 104857600 "$exe" > "$stdout_file"
fi
status=$?
# 记录执行结束时间
exec_end=$(get_timestamp_ms)
exec_time=$((exec_end - exec_start))
set -e
# 计算总时间
total_time=$((compile_time + assemble_time + exec_time))
# 保存运行时间到文件(只保存时间数值)
time_file="$out_dir/${stem}_time.txt"
echo "$total_time" > "$time_file"
# 保存输出(用于比对)
{
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"
# 比对输出
if [[ -f "$expected_file" ]]; then
temp_expected="$out_dir/$stem.expected.tmp"
temp_actual="$out_dir/$stem.actual.tmp"
if command -v python3 >/dev/null 2>&1; then
if python3 - "$expected_file" "$actual_file" <<'PY'
import sys
from pathlib import Path
def canon(path: str) -> bytes:
data = Path(path).read_bytes()
data = data.replace(b'\r\n', b'\n')
while data.endswith(b'\n'):
data = data[:-1]
lines = data.split(b'\n')
lines = [line.rstrip() for line in lines]
return b'\n'.join(lines)
sys.exit(0 if canon(sys.argv[1]) == canon(sys.argv[2]) else 1)
PY
then
rm -f "$temp_expected" "$temp_actual" 2>/dev/null
else
echo "输出不匹配: $expected_file" >&2
rm -f "$temp_expected" "$temp_actual" 2>/dev/null
exit 1
fi
else
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
fi