forked from NUDT-compiler/nudt-compiler-cpp
Compare commits
17 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
23c274eab6 | 5 days ago |
|
|
99826566e6 | 5 days ago |
|
|
19928c4945 | 5 days ago |
|
|
827558938b | 5 days ago |
|
|
c7e8b28d29 | 5 days ago |
|
|
e3de2c59af | 5 days ago |
|
|
3c6ffe8e3e | 3 weeks ago |
|
|
de126b93d6 | 3 weeks ago |
|
|
310c7c3697 | 3 weeks ago |
|
|
248db05cf4 | 3 weeks ago |
|
|
feaba9abd4 | 3 weeks ago |
|
|
1ff1b543d1 | 3 weeks ago |
|
|
80c46cee7e | 1 month ago |
|
|
19ef82738f | 1 month ago |
|
|
4693253459 | 1 month ago |
|
|
fd45b74e2e | 1 month ago |
|
|
74bcb45776 | 1 month ago |
@ -0,0 +1,3 @@
|
||||
bash scripts/run_ir_test.sh --run # 优化模式,计时
|
||||
bash scripts/run_ir_test.sh --run --O0 # 无优化,计时
|
||||
bash scripts/bench_ir.sh # 同时对比 O0 vs O1
|
||||
@ -0,0 +1,309 @@
|
||||
.text
|
||||
.global main
|
||||
.type main, @function
|
||||
main:
|
||||
addi sp, sp, -272
|
||||
sw ra, 264(sp)
|
||||
sw s0, 256(sp)
|
||||
addi a0, sp, -4
|
||||
li a1, 0
|
||||
li a2, 32
|
||||
call
|
||||
addi a0, sp, -8
|
||||
li a1, 0
|
||||
li a2, 32
|
||||
call
|
||||
li t2, 1
|
||||
addi t0, sp, -8
|
||||
li t1, 0
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 2
|
||||
addi t0, sp, -8
|
||||
li t1, 1
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 3
|
||||
addi t0, sp, -8
|
||||
li t1, 2
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 4
|
||||
addi t0, sp, -8
|
||||
li t1, 3
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 5
|
||||
addi t0, sp, -8
|
||||
li t1, 4
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 6
|
||||
addi t0, sp, -8
|
||||
li t1, 5
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 7
|
||||
addi t0, sp, -8
|
||||
li t1, 6
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 8
|
||||
addi t0, sp, -8
|
||||
li t1, 7
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
addi a0, sp, -44
|
||||
li a1, 0
|
||||
li a2, 32
|
||||
call
|
||||
li t2, 1
|
||||
addi t0, sp, -44
|
||||
li t1, 0
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 2
|
||||
addi t0, sp, -44
|
||||
li t1, 1
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 3
|
||||
addi t0, sp, -44
|
||||
li t1, 2
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 4
|
||||
addi t0, sp, -44
|
||||
li t1, 3
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 5
|
||||
addi t0, sp, -44
|
||||
li t1, 4
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 6
|
||||
addi t0, sp, -44
|
||||
li t1, 5
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 7
|
||||
addi t0, sp, -44
|
||||
li t1, 6
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 8
|
||||
addi t0, sp, -44
|
||||
li t1, 7
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
addi a0, sp, -80
|
||||
li a1, 0
|
||||
li a2, 32
|
||||
call
|
||||
li t2, 1
|
||||
addi t0, sp, -80
|
||||
li t1, 0
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 2
|
||||
addi t0, sp, -80
|
||||
li t1, 1
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 3
|
||||
addi t0, sp, -80
|
||||
li t1, 2
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 5
|
||||
addi t0, sp, -80
|
||||
li t1, 4
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 7
|
||||
addi t0, sp, -80
|
||||
li t1, 6
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 8
|
||||
addi t0, sp, -80
|
||||
li t1, 7
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t0, 2
|
||||
li t1, 2
|
||||
mul t0, t0, t1
|
||||
sw t0, -112(sp)
|
||||
li t0, 1
|
||||
lw t1, -112(sp)
|
||||
add t0, t0, t1
|
||||
sw t0, -116(sp)
|
||||
addi t0, sp, -80
|
||||
lw t1, -116(sp)
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
lw t0, 0(t0)
|
||||
sw t0, -124(sp)
|
||||
li t0, 2
|
||||
li t1, 2
|
||||
mul t0, t0, t1
|
||||
sw t0, -128(sp)
|
||||
li t0, 1
|
||||
lw t1, -128(sp)
|
||||
add t0, t0, t1
|
||||
sw t0, -132(sp)
|
||||
addi t0, sp, -44
|
||||
lw t1, -132(sp)
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
lw t0, 0(t0)
|
||||
sw t0, -140(sp)
|
||||
addi a0, sp, -108
|
||||
li a1, 0
|
||||
li a2, 32
|
||||
call
|
||||
lw t2, -124(sp)
|
||||
addi t0, sp, -108
|
||||
li t1, 0
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
lw t2, -140(sp)
|
||||
addi t0, sp, -108
|
||||
li t1, 1
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 3
|
||||
addi t0, sp, -108
|
||||
li t1, 2
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 4
|
||||
addi t0, sp, -108
|
||||
li t1, 3
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 5
|
||||
addi t0, sp, -108
|
||||
li t1, 4
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 6
|
||||
addi t0, sp, -108
|
||||
li t1, 5
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 7
|
||||
addi t0, sp, -108
|
||||
li t1, 6
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t2, 8
|
||||
addi t0, sp, -108
|
||||
li t1, 7
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
sw t2, 0(t0)
|
||||
li t0, 3
|
||||
li t1, 2
|
||||
mul t0, t0, t1
|
||||
sw t0, -176(sp)
|
||||
li t0, 1
|
||||
lw t1, -176(sp)
|
||||
add t0, t0, t1
|
||||
sw t0, -180(sp)
|
||||
addi t0, sp, -108
|
||||
lw t1, -180(sp)
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
lw t0, 0(t0)
|
||||
sw t0, -188(sp)
|
||||
li t0, 0
|
||||
li t1, 2
|
||||
mul t0, t0, t1
|
||||
sw t0, -192(sp)
|
||||
li t0, 0
|
||||
lw t1, -192(sp)
|
||||
add t0, t0, t1
|
||||
sw t0, -196(sp)
|
||||
addi t0, sp, -108
|
||||
lw t1, -196(sp)
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
lw t0, 0(t0)
|
||||
sw t0, -204(sp)
|
||||
lw t0, -188(sp)
|
||||
lw t1, -204(sp)
|
||||
add t0, t0, t1
|
||||
sw t0, -208(sp)
|
||||
li t0, 0
|
||||
li t1, 2
|
||||
mul t0, t0, t1
|
||||
sw t0, -212(sp)
|
||||
li t0, 1
|
||||
lw t1, -212(sp)
|
||||
add t0, t0, t1
|
||||
sw t0, -216(sp)
|
||||
addi t0, sp, -108
|
||||
lw t1, -216(sp)
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
lw t0, 0(t0)
|
||||
sw t0, -224(sp)
|
||||
lw t0, -208(sp)
|
||||
lw t1, -224(sp)
|
||||
add t0, t0, t1
|
||||
sw t0, -228(sp)
|
||||
li t0, 2
|
||||
li t1, 2
|
||||
mul t0, t0, t1
|
||||
sw t0, -232(sp)
|
||||
li t0, 0
|
||||
lw t1, -232(sp)
|
||||
add t0, t0, t1
|
||||
sw t0, -236(sp)
|
||||
addi t0, sp, -4
|
||||
lw t1, -236(sp)
|
||||
slli t1, t1, 2
|
||||
add t0, t0, t1
|
||||
lw t0, 0(t0)
|
||||
sw t0, -244(sp)
|
||||
lw t0, -228(sp)
|
||||
lw t1, -244(sp)
|
||||
add t0, t0, t1
|
||||
sw t0, -248(sp)
|
||||
lw a0, -248(sp)
|
||||
lw ra, 264(sp)
|
||||
lw s0, 256(sp)
|
||||
addi sp, sp, 272
|
||||
ret
|
||||
.size main, .-main
|
||||
@ -0,0 +1,147 @@
|
||||
#!/usr/bin/env bash
|
||||
# 优化效果对比:测量 O0 vs O1 的编译时间和运行时间
|
||||
# 用法: bash scripts/bench_ir.sh [--test-dir=<dir>] [--result-dir=<dir>]
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
PROJECT_ROOT=$(cd "$(dirname "$0")/.." ; pwd)
|
||||
TEST_CASE_DIR="${PROJECT_ROOT}/test/test_case"
|
||||
RESULT_DIR="${PROJECT_ROOT}/test/test_result/bench"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--test-dir=*) TEST_CASE_DIR="${1#*=}" ;;
|
||||
--result-dir=*) RESULT_DIR="${1#*=}" ;;
|
||||
*) echo "未知参数: $1" >&2; exit 1 ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
compiler="${PROJECT_ROOT}/build/bin/compiler"
|
||||
[[ -x "$compiler" ]] || { echo "错误:未找到编译器 $compiler" >&2; exit 1; }
|
||||
command -v llc >/dev/null 2>&1 || { echo "错误:未找到 llc" >&2; exit 1; }
|
||||
command -v clang >/dev/null 2>&1 || { echo "错误:未找到 clang" >&2; exit 1; }
|
||||
|
||||
mkdir -p "$RESULT_DIR"
|
||||
|
||||
# 时间测量:使用 date +%s.%N
|
||||
now() { date +%s.%N; }
|
||||
elapsed() { python3 -c "print(f'{float($2)-float($1):.4f}')" 2>/dev/null || awk "BEGIN{printf \"%.4f\\n\",$2-$1}"; }
|
||||
|
||||
summary_file="${RESULT_DIR}/summary.csv"
|
||||
echo "test,opt,compile_s,exec_s,compile+exec_s" > "$summary_file"
|
||||
|
||||
total=0
|
||||
o0_ct_total=0; o1_ct_total=0
|
||||
o0_et_total=0; o1_et_total=0
|
||||
|
||||
echo "=== 优化效果对比 O0 vs O1 ==="
|
||||
echo ""
|
||||
|
||||
while read -r test_file; do
|
||||
full_path=$(readlink -f "$test_file")
|
||||
tcdir=$(readlink -f "$TEST_CASE_DIR")
|
||||
rel="${full_path#$tcdir}"
|
||||
[[ "${rel:0:1}" != "/" ]] && rel="/$rel"
|
||||
|
||||
base=$(basename "$test_file")
|
||||
stem="${base%.sy}"
|
||||
idir=$(dirname "$test_file")
|
||||
stdin="${idir}/${stem}.in"
|
||||
expected="${idir}/${stem}.out"
|
||||
|
||||
total=$((total+1))
|
||||
printf "[%4d] %s" "$total" "$rel"
|
||||
|
||||
o0_ll="${RESULT_DIR}/O0/${rel%.sy}.ll"
|
||||
o1_ll="${RESULT_DIR}/O1/${rel%.sy}.ll"
|
||||
mkdir -p "$(dirname "$o0_ll")" "$(dirname "$o1_ll")"
|
||||
|
||||
# --- 编译 O0 ---
|
||||
t1=$(now)
|
||||
"$compiler" "$test_file" -IR -o "$o0_ll" 2>/dev/null; rc0=$?
|
||||
t2=$(now)
|
||||
if [[ $rc0 -ne 0 ]]; then
|
||||
echo " | O0编译失败"
|
||||
echo "$stem,O0,-,-,-" >> "$summary_file"
|
||||
echo "$stem,O1,-,-,-" >> "$summary_file"
|
||||
continue
|
||||
fi
|
||||
o0_ct=$(elapsed "$t1" "$t2")
|
||||
|
||||
# --- 编译 O1 ---
|
||||
t1=$(now)
|
||||
"$compiler" "$test_file" -IR -o "$o1_ll" -O1 2>/dev/null; rc1=$?
|
||||
t2=$(now)
|
||||
if [[ $rc1 -ne 0 ]]; then
|
||||
echo " | O1编译失败"
|
||||
echo "$stem,O0,$o0_ct,-,-" >> "$summary_file"
|
||||
echo "$stem,O1,-,-,-" >> "$summary_file"
|
||||
continue
|
||||
fi
|
||||
o1_ct=$(elapsed "$t1" "$t2")
|
||||
|
||||
# --- llc + clang O0 ---
|
||||
o0_obj="${RESULT_DIR}/O0/${stem}.o"
|
||||
o1_obj="${RESULT_DIR}/O1/${stem}.o"
|
||||
o0_exe="${RESULT_DIR}/O0/${stem}.exe"
|
||||
o1_exe="${RESULT_DIR}/O1/${stem}.exe"
|
||||
|
||||
llc -filetype=obj "$o0_ll" -o "$o0_obj" 2>/dev/null
|
||||
llc -filetype=obj "$o1_ll" -o "$o1_obj" 2>/dev/null
|
||||
clang "$o0_obj" "${PROJECT_ROOT}/sylib/sylib.c" -o "$o0_exe" -lm 2>/dev/null
|
||||
clang "$o1_obj" "${PROJECT_ROOT}/sylib/sylib.c" -o "$o1_exe" -lm 2>/dev/null
|
||||
|
||||
# --- 运行 O0 ---
|
||||
t1=$(now)
|
||||
sr0=0
|
||||
if [[ -f "$stdin" ]]; then
|
||||
(ulimit -s unlimited; "$o0_exe" < "$stdin") > /dev/null 2>&1 || sr0=$?
|
||||
else
|
||||
(ulimit -s unlimited; "$o0_exe") > /dev/null 2>&1 || sr0=$?
|
||||
fi
|
||||
t2=$(now)
|
||||
o0_et=$(elapsed "$t1" "$t2")
|
||||
|
||||
# --- 运行 O1 ---
|
||||
t1=$(now)
|
||||
sr1=0
|
||||
if [[ -f "$stdin" ]]; then
|
||||
(ulimit -s unlimited; "$o1_exe" < "$stdin") > /dev/null 2>&1 || sr1=$?
|
||||
else
|
||||
(ulimit -s unlimited; "$o1_exe") > /dev/null 2>&1 || sr1=$?
|
||||
fi
|
||||
t2=$(now)
|
||||
o1_et=$(elapsed "$t1" "$t2")
|
||||
|
||||
# 验证一致性
|
||||
flag=""
|
||||
if [[ $sr0 -ne $sr1 ]]; then
|
||||
flag=" EXIT:O0=$sr0 O1=$sr1"
|
||||
fi
|
||||
|
||||
# 累计 & 比率
|
||||
o0_ct_total=$(awk "BEGIN{printf \"%.4f\",$o0_ct_total+$o0_ct}")
|
||||
o1_ct_total=$(awk "BEGIN{printf \"%.4f\",$o1_ct_total+$o1_ct}")
|
||||
o0_et_total=$(awk "BEGIN{printf \"%.4f\",$o0_et_total+$o0_et}")
|
||||
o1_et_total=$(awk "BEGIN{printf \"%.4f\",$o1_et_total+$o1_et}")
|
||||
|
||||
cspd=$(awk "BEGIN{if($o1_ct>0)printf \"%.1fx\",$o0_ct/$o1_ct; else print \"-\"}")
|
||||
espd=$(awk "BEGIN{if($o1_et>0)printf \"%.1fx\",$o0_et/$o1_et; else print \"-\"}")
|
||||
|
||||
printf " | 编译 O0:%.4fs O1:%.4fs(%s) 运行 O0:%.4fs O1:%.4fs(%s)%s\n" \
|
||||
"$o0_ct" "$o1_ct" "$cspd" "$o0_et" "$o1_et" "$espd" "$flag"
|
||||
|
||||
echo "$stem,O0,$o0_ct,$o0_et,$(awk "BEGIN{printf \"%.4f\",$o0_ct+$o0_et}")" >> "$summary_file"
|
||||
echo "$stem,O1,$o1_ct,$o1_et,$(awk "BEGIN{printf \"%.4f\",$o1_ct+$o1_et}")" >> "$summary_file"
|
||||
|
||||
done < <(find "$TEST_CASE_DIR" -name "*.sy" | sort)
|
||||
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo "总用例: $total"
|
||||
echo "O0 编译总耗时: ${o0_ct_total}s"
|
||||
echo "O1 编译总耗时: ${o1_ct_total}s"
|
||||
echo "O0 运行总耗时: ${o0_et_total}s"
|
||||
echo "O1 运行总耗时: ${o1_et_total}s"
|
||||
echo "CSV: $summary_file"
|
||||
@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
|
||||
def read_file(filepath):
|
||||
"""读取文件内容,返回行列表"""
|
||||
try:
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
return f.readlines()
|
||||
except FileNotFoundError:
|
||||
print(f"错误:文件 '{filepath}' 不存在")
|
||||
sys.exit(1)
|
||||
|
||||
def get_context(line, pos, context_len=10):
|
||||
"""获取字符上下文"""
|
||||
start = max(0, pos - context_len)
|
||||
end = min(len(line), pos + context_len + 1)
|
||||
prefix = "..." if start > 0 else ""
|
||||
suffix = "..." if end < len(line) else ""
|
||||
return prefix + line[start:end] + suffix
|
||||
|
||||
def compare_files(file1, file2):
|
||||
"""比较两个文件,输出详细差异"""
|
||||
lines1 = read_file(file1)
|
||||
lines2 = read_file(file2)
|
||||
|
||||
print(f"比较文件: {file1} vs {file2}")
|
||||
print("=" * 80)
|
||||
|
||||
max_lines = max(len(lines1), len(lines2))
|
||||
differences = 0
|
||||
|
||||
for line_num in range(max_lines):
|
||||
line1 = lines1[line_num] if line_num < len(lines1) else None
|
||||
line2 = lines2[line_num] if line_num < len(lines2) else None
|
||||
|
||||
if line1 is None:
|
||||
print(f"\n[新增行] 第 {line_num + 1} 行")
|
||||
print(f" + {repr(line2)}")
|
||||
differences += 1
|
||||
continue
|
||||
|
||||
if line2 is None:
|
||||
print(f"\n[删除行] 第 {line_num + 1} 行")
|
||||
print(f" - {repr(line1)}")
|
||||
differences += 1
|
||||
continue
|
||||
|
||||
if line1 == line2:
|
||||
continue
|
||||
|
||||
# 行内容不同,逐字符比较
|
||||
print(f"\n[差异行] 第 {line_num + 1} 行")
|
||||
|
||||
max_chars = max(len(line1), len(line2))
|
||||
for char_pos in range(max_chars):
|
||||
char1 = line1[char_pos] if char_pos < len(line1) else None
|
||||
char2 = line2[char_pos] if char_pos < len(line2) else None
|
||||
|
||||
if char1 == char2:
|
||||
continue
|
||||
|
||||
# 找到差异字符
|
||||
context1 = get_context(line1, char_pos) if line1 else ""
|
||||
context2 = get_context(line2, char_pos) if line2 else ""
|
||||
|
||||
print(f" 字符位置 {char_pos + 1}:")
|
||||
if char1 is not None:
|
||||
print(f" - {repr(char1)} | 上下文: {repr(context1)}")
|
||||
else:
|
||||
print(f" - (缺失)")
|
||||
if char2 is not None:
|
||||
print(f" + {repr(char2)} | 上下文: {repr(context2)}")
|
||||
else:
|
||||
print(f" + (缺失)")
|
||||
differences += 1
|
||||
|
||||
# 跳过一些连续差异,避免输出过多
|
||||
while char_pos + 1 < max_chars:
|
||||
next_char1 = line1[char_pos + 1] if char_pos + 1 < len(line1) else None
|
||||
next_char2 = line2[char_pos + 1] if char_pos + 1 < len(line2) else None
|
||||
if next_char1 != next_char2:
|
||||
char_pos += 1
|
||||
else:
|
||||
break
|
||||
|
||||
print("\n" + "=" * 80)
|
||||
print(f"比较完成,共发现 {differences} 处差异")
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 3:
|
||||
print("用法: python diff.py <文件1> <文件2>")
|
||||
sys.exit(1)
|
||||
|
||||
file1 = sys.argv[1]
|
||||
file2 = sys.argv[2]
|
||||
|
||||
compare_files(file1, file2)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Binary file not shown.
@ -0,0 +1,65 @@
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
PROJECT_ROOT=$(cd "$(dirname "$0")/.." ; pwd)
|
||||
COMPILER="$PROJECT_ROOT/build/bin/compiler"
|
||||
TEST_DIR="$PROJECT_ROOT/test/test_case/basic"
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
NC='\033[0m'
|
||||
|
||||
if [ ! -f "$COMPILER" ]; then
|
||||
echo "错误: 编译器不存在: $COMPILER"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=========================================="
|
||||
echo "RISC-V 浮点转换测试"
|
||||
echo "=========================================="
|
||||
|
||||
TESTS="
|
||||
float_conv:3
|
||||
float_add:13
|
||||
float_mul:30
|
||||
"
|
||||
|
||||
PASS=0
|
||||
FAIL=0
|
||||
|
||||
for test in $TESTS; do
|
||||
name=$(echo $test | cut -d: -f1)
|
||||
expected=$(echo $test | cut -d: -f2)
|
||||
|
||||
echo -n "测试 $name (期望 $expected) ... "
|
||||
|
||||
"$COMPILER" "$TEST_DIR/$name.sy" --emit-asm > /tmp/test_$name.s 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}失败 (汇编错误)${NC}"
|
||||
cat /tmp/test_$name.s | head -3
|
||||
FAIL=$((FAIL + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
riscv64-linux-gnu-gcc -static /tmp/test_$name.s -o /tmp/test_$name -no-pie 2>/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}失败 (链接错误)${NC}"
|
||||
FAIL=$((FAIL + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
qemu-riscv64 /tmp/test_$name > /dev/null 2>&1
|
||||
exit_code=$?
|
||||
|
||||
if [ $exit_code -eq $expected ]; then
|
||||
echo -e "${GREEN}通过${NC}"
|
||||
PASS=$((PASS + 1))
|
||||
else
|
||||
echo -e "${RED}失败 (实际 $exit_code)${NC}"
|
||||
FAIL=$((FAIL + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
echo "=========================================="
|
||||
echo -e "测试结果: ${GREEN}通过 $PASS${NC} / ${RED}失败 $FAIL${NC}"
|
||||
echo "=========================================="
|
||||
@ -0,0 +1,85 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 获取项目根目录
|
||||
PROJECT_ROOT=$(cd "$(dirname "$0")/.." ; pwd)
|
||||
COMPILER="$PROJECT_ROOT/build/bin/compiler"
|
||||
TEST_DIR="$PROJECT_ROOT/test/test_case/basic"
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
NC='\033[0m'
|
||||
|
||||
# 检查编译器
|
||||
if [ ! -f "$COMPILER" ]; then
|
||||
echo "错误: 编译器不存在: $COMPILER"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查工具链
|
||||
if ! command -v riscv64-linux-gnu-gcc >/dev/null 2>&1; then
|
||||
echo "错误: 未找到 riscv64-linux-gnu-gcc"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v qemu-riscv64 >/dev/null 2>&1; then
|
||||
echo "错误: 未找到 qemu-riscv64"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=========================================="
|
||||
echo "RISC-V 基础功能测试"
|
||||
echo "=========================================="
|
||||
|
||||
# 定义测试用例
|
||||
TESTS="arith:50 add:30 sub:7 mul:50 div:25 mod:2 var:43"
|
||||
|
||||
PASS=0
|
||||
FAIL=0
|
||||
|
||||
for test in $TESTS; do
|
||||
name=$(echo $test | cut -d: -f1)
|
||||
expected=$(echo $test | cut -d: -f2)
|
||||
|
||||
echo -n "测试 $name (期望 $expected) ... "
|
||||
|
||||
# 生成汇编
|
||||
"$COMPILER" "$TEST_DIR/$name.sy" --emit-asm > /tmp/test_$name.s 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}失败 (汇编错误)${NC}"
|
||||
FAIL=$((FAIL + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
# 链接
|
||||
riscv64-linux-gnu-gcc -static /tmp/test_$name.s -o /tmp/test_$name -no-pie 2>/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}失败 (链接错误)${NC}"
|
||||
FAIL=$((FAIL + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
# 运行
|
||||
qemu-riscv64 /tmp/test_$name > /dev/null 2>&1
|
||||
exit_code=$?
|
||||
|
||||
if [ $exit_code -eq $expected ]; then
|
||||
echo -e "${GREEN}通过${NC}"
|
||||
PASS=$((PASS + 1))
|
||||
else
|
||||
echo -e "${RED}失败 (实际 $exit_code)${NC}"
|
||||
FAIL=$((FAIL + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
echo "=========================================="
|
||||
echo -e "测试结果: ${GREEN}通过 $PASS${NC} / ${RED}失败 $FAIL${NC}"
|
||||
echo "=========================================="
|
||||
|
||||
if [ $FAIL -eq 0 ]; then
|
||||
echo -e "${GREEN}✓ 所有基础测试通过!${NC}"
|
||||
exit 0
|
||||
else
|
||||
echo -e "${RED}✗ 有 $FAIL 个测试失败${NC}"
|
||||
exit 1
|
||||
fi
|
||||
@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
PROJECT_ROOT=$(cd "$(dirname "$0")/.." ; pwd)
|
||||
|
||||
if [[ $# -lt 1 || $# -gt 3 ]]; then
|
||||
echo "用法: $0 <input.sy> [output_dir] [--run]" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
input=$1
|
||||
out_dir="test/test_result/mir"
|
||||
run_exec=false
|
||||
input_dir=$(dirname "$input")
|
||||
|
||||
shift
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--run)
|
||||
run_exec=true
|
||||
;;
|
||||
*)
|
||||
out_dir="$1"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [[ ! -f "$input" ]]; then
|
||||
echo "输入文件不存在: $input" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
compiler="$PROJECT_ROOT/build/bin/compiler"
|
||||
if [[ ! -x "$compiler" ]]; then
|
||||
echo "未找到编译器: $compiler ,请先构建。" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$out_dir"
|
||||
base=$(basename "$input")
|
||||
stem=${base%.sy}
|
||||
mir_file="$out_dir/$stem.mir"
|
||||
asm_file="$out_dir/$stem.s"
|
||||
exe="$out_dir/$stem"
|
||||
stdin_file="$input_dir/$stem.in"
|
||||
expected_file="$input_dir/$stem.out"
|
||||
|
||||
# 生成 MIR
|
||||
"$compiler" --emit-mir "$input" > "$mir_file"
|
||||
echo "MIR 已生成: $mir_file"
|
||||
|
||||
# 生成汇编
|
||||
"$compiler" --emit-asm "$input" > "$asm_file"
|
||||
echo "汇编已生成: $asm_file"
|
||||
|
||||
if [[ "$run_exec" == true ]]; then
|
||||
if ! command -v riscv64-linux-gnu-gcc >/dev/null 2>&1; then
|
||||
echo "未找到 riscv64-linux-gnu-gcc" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! command -v qemu-riscv64 >/dev/null 2>&1; then
|
||||
echo "未找到 qemu-riscv64" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
riscv64-linux-gnu-gcc -static "$asm_file" -o "$exe" -no-pie
|
||||
|
||||
stdout_file="$out_dir/$stem.stdout"
|
||||
actual_file="$out_dir/$stem.actual.out"
|
||||
echo "运行 $exe ..."
|
||||
set +e
|
||||
if [[ -f "$stdin_file" ]]; then
|
||||
qemu-riscv64 "$exe" < "$stdin_file" > "$stdout_file"
|
||||
else
|
||||
qemu-riscv64 "$exe" > "$stdout_file"
|
||||
fi
|
||||
status=$?
|
||||
set -e
|
||||
cat "$stdout_file"
|
||||
echo "退出码: $status"
|
||||
{
|
||||
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
|
||||
if diff -u "$expected_file" "$actual_file"; then
|
||||
echo "输出匹配: $expected_file"
|
||||
else
|
||||
echo "输出不匹配: $expected_file" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "未找到预期输出文件,跳过比对: $expected_file"
|
||||
fi
|
||||
fi
|
||||
@ -1,4 +1,205 @@
|
||||
// 支配树分析:
|
||||
// - 构建/查询 Dominator Tree 及相关关系
|
||||
// - 为 mem2reg、CFG 优化与循环分析提供基础能力
|
||||
// - 使用 Cooper-Harvey-Kennedy 算法,近线性时间复杂度
|
||||
|
||||
#include "ir/IR.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace ir {
|
||||
|
||||
void DominatorTree::Compute(Function& func) {
|
||||
func.RebuildCFG();
|
||||
|
||||
// Build block list and reverse postorder (RPO)
|
||||
std::vector<BasicBlock*> blocks;
|
||||
std::unordered_map<BasicBlock*, int> rpo;
|
||||
{
|
||||
std::vector<BasicBlock*> rpo_vec;
|
||||
std::unordered_set<BasicBlock*> visited;
|
||||
std::function<void(BasicBlock*)> dfs = [&](BasicBlock* bb) {
|
||||
if (!bb || visited.count(bb)) return;
|
||||
visited.insert(bb);
|
||||
for (auto* succ : bb->GetSuccessors()) {
|
||||
dfs(succ);
|
||||
}
|
||||
rpo_vec.push_back(bb);
|
||||
};
|
||||
dfs(func.GetEntry());
|
||||
// Reverse to get RPO (postorder reversed)
|
||||
std::reverse(rpo_vec.begin(), rpo_vec.end());
|
||||
blocks = rpo_vec;
|
||||
for (int i = 0; i < (int)blocks.size(); ++i) {
|
||||
rpo[blocks[i]] = i;
|
||||
}
|
||||
}
|
||||
if (blocks.empty()) return;
|
||||
int n = (int)blocks.size();
|
||||
|
||||
auto* entry = func.GetEntry();
|
||||
if (!entry) return;
|
||||
|
||||
// ─── 1. CHK algorithm for immediate dominators ─────────────────────────
|
||||
idom_.clear();
|
||||
idom_[entry] = entry; // entry is its own dominator
|
||||
|
||||
// Intersect: find common ancestor of b1 and b2 walking up the dom tree
|
||||
// Uses RPO number: a dominator always has lower RPO number
|
||||
auto intersect = [&](BasicBlock* b1, BasicBlock* b2) -> BasicBlock* {
|
||||
auto i1 = rpo.find(b1), i2 = rpo.find(b2);
|
||||
if (i1 == rpo.end() || i2 == rpo.end()) return entry;
|
||||
int r1 = i1->second, r2 = i2->second;
|
||||
while (b1 != b2) {
|
||||
while (r1 > r2) {
|
||||
auto it = idom_.find(b1);
|
||||
if (it == idom_.end() || it->second == b1) return b1;
|
||||
b1 = it->second;
|
||||
r1 = rpo[b1];
|
||||
}
|
||||
while (r2 > r1) {
|
||||
auto it = idom_.find(b2);
|
||||
if (it == idom_.end() || it->second == b2) return b2;
|
||||
b2 = it->second;
|
||||
r2 = rpo[b2];
|
||||
}
|
||||
}
|
||||
return b1;
|
||||
};
|
||||
|
||||
bool changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
// Process in RPO (skip entry which is first in RPO)
|
||||
for (int i = 1; i < n; ++i) {
|
||||
auto* bb = blocks[i];
|
||||
// Find first predecessor with defined IDOM
|
||||
BasicBlock* new_idom = nullptr;
|
||||
for (auto* pred : bb->GetPredecessors()) {
|
||||
if (idom_.count(pred) && pred != bb) {
|
||||
new_idom = pred;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!new_idom) continue;
|
||||
|
||||
// Intersect with remaining predecessors
|
||||
for (auto* pred : bb->GetPredecessors()) {
|
||||
if (pred == new_idom || pred == bb) continue;
|
||||
if (idom_.count(pred)) {
|
||||
new_idom = intersect(pred, new_idom);
|
||||
}
|
||||
}
|
||||
|
||||
auto old = idom_.find(bb);
|
||||
if (old == idom_.end() || old->second != new_idom) {
|
||||
idom_[bb] = new_idom;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Entry is its own IDOM, set to nullptr for external queries
|
||||
idom_[entry] = nullptr;
|
||||
|
||||
// Unreached blocks get entry as IDOM
|
||||
for (auto* bb : blocks) {
|
||||
if (!idom_.count(bb)) idom_[bb] = entry;
|
||||
}
|
||||
|
||||
// ─── 2. Build children map and dom levels ──────────────────────────────
|
||||
children_.clear();
|
||||
dom_level_.clear();
|
||||
for (auto& [child, parent] : idom_) {
|
||||
if (parent) children_[parent].push_back(child);
|
||||
}
|
||||
|
||||
// BFS to compute dom levels
|
||||
std::queue<BasicBlock*> q;
|
||||
dom_level_[entry] = 0;
|
||||
q.push(entry);
|
||||
while (!q.empty()) {
|
||||
auto* cur = q.front();
|
||||
q.pop();
|
||||
size_t cur_level = dom_level_[cur];
|
||||
auto it = children_.find(cur);
|
||||
if (it != children_.end()) {
|
||||
for (auto* child : it->second) {
|
||||
dom_level_[child] = cur_level + 1;
|
||||
q.push(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── 3. Compute dominance frontier ─────────────────────────────────────
|
||||
df_.clear();
|
||||
for (int i = 0; i < n; ++i) {
|
||||
auto* b = blocks[i];
|
||||
if (b->GetPredecessors().size() < 2) continue;
|
||||
for (auto* p : b->GetPredecessors()) {
|
||||
auto* runner = p;
|
||||
auto* b_idom = GetIDom(b);
|
||||
while (runner != b_idom) {
|
||||
if (!runner) break;
|
||||
df_[runner].push_back(b);
|
||||
runner = GetIDom(runner);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Deduplicate DF entries
|
||||
for (auto& [bb, vec] : df_) {
|
||||
std::sort(vec.begin(), vec.end());
|
||||
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
|
||||
}
|
||||
|
||||
// ─── 4. Compute DFS order of dominator tree ────────────────────────────
|
||||
df_order_.clear();
|
||||
visited_.clear();
|
||||
std::function<void(BasicBlock*)> dfs_tree = [&](BasicBlock* bb) {
|
||||
if (!bb || visited_.count(bb)) return;
|
||||
visited_.insert(bb);
|
||||
df_order_.push_back(bb);
|
||||
auto it = children_.find(bb);
|
||||
if (it != children_.end()) {
|
||||
for (auto* child : it->second) {
|
||||
dfs_tree(child);
|
||||
}
|
||||
}
|
||||
};
|
||||
dfs_tree(entry);
|
||||
}
|
||||
|
||||
BasicBlock* DominatorTree::GetIDom(BasicBlock* bb) const {
|
||||
auto it = idom_.find(bb);
|
||||
return (it != idom_.end()) ? it->second : nullptr;
|
||||
}
|
||||
|
||||
const std::vector<BasicBlock*>& DominatorTree::GetChildren(
|
||||
BasicBlock* bb) const {
|
||||
static const std::vector<BasicBlock*> empty;
|
||||
auto it = children_.find(bb);
|
||||
return (it != children_.end()) ? it->second : empty;
|
||||
}
|
||||
|
||||
const std::vector<BasicBlock*>& DominatorTree::GetDominanceFrontier(
|
||||
BasicBlock* bb) const {
|
||||
static const std::vector<BasicBlock*> empty;
|
||||
auto it = df_.find(bb);
|
||||
return (it != df_.end()) ? it->second : empty;
|
||||
}
|
||||
|
||||
bool DominatorTree::Dominates(BasicBlock* a, BasicBlock* b) const {
|
||||
if (a == b) return true;
|
||||
BasicBlock* runner = b;
|
||||
while (runner) {
|
||||
runner = GetIDom(runner);
|
||||
if (runner == a) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
|
||||
@ -1,4 +1,187 @@
|
||||
// IR 常量折叠:
|
||||
// - 折叠可判定的常量表达式
|
||||
// - 简化常量控制流分支(按实现范围裁剪)
|
||||
// - 简化常量控制流分支
|
||||
|
||||
#include "ir/IR.h"
|
||||
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace ir {
|
||||
|
||||
namespace {
|
||||
|
||||
// 在释放指令前断开其 use-def 链,避免其他值的 uses_ 中有悬空指针
|
||||
static void DetachAndRemove(Instruction* inst) {
|
||||
// 先断开自身对操作数的引用,清除 use-def 链
|
||||
for (size_t i = 0; i < inst->GetNumOperands(); ++i)
|
||||
inst->SetOperand(i, nullptr);
|
||||
// 然后从父块中移除(清除父指针后不会再次尝试访问)
|
||||
if (auto* parent = inst->GetParent()) {
|
||||
parent->RemoveInstruction(inst);
|
||||
}
|
||||
}
|
||||
|
||||
bool FoldICmp(ICmpInst* cmp, Context& ctx) {
|
||||
auto* lhs = dynamic_cast<ConstantInt*>(cmp->GetLhs());
|
||||
auto* rhs = dynamic_cast<ConstantInt*>(cmp->GetRhs());
|
||||
if (!lhs || !rhs) return false;
|
||||
|
||||
int lv = lhs->GetValue(), rv = rhs->GetValue();
|
||||
bool result = false;
|
||||
switch (cmp->GetPredicate()) {
|
||||
case ICmpPredicate::EQ: result = lv == rv; break;
|
||||
case ICmpPredicate::NE: result = lv != rv; break;
|
||||
case ICmpPredicate::SLT: result = lv < rv; break;
|
||||
case ICmpPredicate::SLE: result = lv <= rv; break;
|
||||
case ICmpPredicate::SGT: result = lv > rv; break;
|
||||
case ICmpPredicate::SGE: result = lv >= rv; break;
|
||||
}
|
||||
cmp->ReplaceAllUsesWith(ctx.GetConstInt(result ? 1 : 0));
|
||||
DetachAndRemove(cmp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FoldFCmp(FCmpInst* cmp, Context& ctx) {
|
||||
auto* lhs = dynamic_cast<ConstantFloat*>(cmp->GetLhs());
|
||||
auto* rhs = dynamic_cast<ConstantFloat*>(cmp->GetRhs());
|
||||
if (!lhs || !rhs) return false;
|
||||
|
||||
float lv = lhs->GetValue(), rv = rhs->GetValue();
|
||||
bool result = false;
|
||||
switch (cmp->GetPredicate()) {
|
||||
case FCmpPredicate::OEQ: result = lv == rv; break;
|
||||
case FCmpPredicate::ONE: result = lv != rv; break;
|
||||
case FCmpPredicate::OLT: result = lv < rv; break;
|
||||
case FCmpPredicate::OLE: result = lv <= rv; break;
|
||||
case FCmpPredicate::OGT: result = lv > rv; break;
|
||||
case FCmpPredicate::OGE: result = lv >= rv; break;
|
||||
}
|
||||
cmp->ReplaceAllUsesWith(ctx.GetConstInt(result ? 1 : 0));
|
||||
DetachAndRemove(cmp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FoldZExt(ZExtInst* zext, Context& ctx) {
|
||||
auto* src = dynamic_cast<ConstantInt*>(zext->GetSrc());
|
||||
if (!src) return false;
|
||||
zext->ReplaceAllUsesWith(ctx.GetConstInt(src->GetValue() != 0 ? 1 : 0));
|
||||
DetachAndRemove(zext);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FoldSIToFP(SIToFPInst* inst, Context& ctx) {
|
||||
auto* src = dynamic_cast<ConstantInt*>(inst->GetSrc());
|
||||
if (!src) return false;
|
||||
inst->ReplaceAllUsesWith(ctx.GetConstFloat(static_cast<float>(src->GetValue())));
|
||||
DetachAndRemove(inst);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FoldFPToSI(FPToSIInst* inst, Context& ctx) {
|
||||
auto* src = dynamic_cast<ConstantFloat*>(inst->GetSrc());
|
||||
if (!src) return false;
|
||||
inst->ReplaceAllUsesWith(ctx.GetConstInt(static_cast<int>(src->GetValue())));
|
||||
DetachAndRemove(inst);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fold constant binary operations (int and float)
|
||||
bool FoldBinaryWithCtx(BinaryInst* bin, Context& ctx) {
|
||||
auto* lhs_c = dynamic_cast<ConstantInt*>(bin->GetLhs());
|
||||
auto* rhs_c = dynamic_cast<ConstantInt*>(bin->GetRhs());
|
||||
auto* lhs_f = dynamic_cast<ConstantFloat*>(bin->GetLhs());
|
||||
auto* rhs_f = dynamic_cast<ConstantFloat*>(bin->GetRhs());
|
||||
|
||||
if (lhs_c && rhs_c) {
|
||||
int lv = lhs_c->GetValue(), rv = rhs_c->GetValue();
|
||||
int result = 0;
|
||||
bool valid = true;
|
||||
switch (bin->GetOpcode()) {
|
||||
case Opcode::Add: result = lv + rv; break;
|
||||
case Opcode::Sub: result = lv - rv; break;
|
||||
case Opcode::Mul: result = lv * rv; break;
|
||||
case Opcode::Div: if (rv != 0) result = lv / rv; else valid = false; break;
|
||||
case Opcode::Mod: if (rv != 0) result = lv % rv; else valid = false; break;
|
||||
default: valid = false; break;
|
||||
}
|
||||
if (valid) {
|
||||
bin->ReplaceAllUsesWith(ctx.GetConstInt(result));
|
||||
DetachAndRemove(bin);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (lhs_f && rhs_f) {
|
||||
float lv = lhs_f->GetValue(), rv = rhs_f->GetValue();
|
||||
float result = 0.0f;
|
||||
bool valid = true;
|
||||
switch (bin->GetOpcode()) {
|
||||
case Opcode::FAdd: result = lv + rv; break;
|
||||
case Opcode::FSub: result = lv - rv; break;
|
||||
case Opcode::FMul: result = lv * rv; break;
|
||||
case Opcode::FDiv: if (rv != 0.0f) result = lv / rv; else valid = false; break;
|
||||
default: valid = false; break;
|
||||
}
|
||||
if (valid) {
|
||||
bin->ReplaceAllUsesWith(ctx.GetConstFloat(result));
|
||||
DetachAndRemove(bin);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool RunConstFold(Function& func, Context& ctx) {
|
||||
bool changed = false;
|
||||
std::unordered_set<void*> removed;
|
||||
|
||||
bool any_changed = true;
|
||||
while (any_changed) {
|
||||
any_changed = false;
|
||||
for (auto& bb : func.GetBlocks()) {
|
||||
// 每轮重新收集(因为指令列表在变化)
|
||||
std::vector<Instruction*> insts;
|
||||
for (auto& inst : bb->GetInstructions())
|
||||
insts.push_back(inst.get());
|
||||
|
||||
for (auto* inst : insts) {
|
||||
if (removed.count(inst)) continue;
|
||||
bool folded = false;
|
||||
switch (inst->GetOpcode()) {
|
||||
case Opcode::Add: case Opcode::Sub: case Opcode::Mul:
|
||||
case Opcode::Div: case Opcode::Mod:
|
||||
case Opcode::FAdd: case Opcode::FSub:
|
||||
case Opcode::FMul: case Opcode::FDiv:
|
||||
folded = FoldBinaryWithCtx(static_cast<BinaryInst*>(inst), ctx);
|
||||
break;
|
||||
case Opcode::ICmp:
|
||||
folded = FoldICmp(static_cast<ICmpInst*>(inst), ctx);
|
||||
break;
|
||||
case Opcode::FCmp:
|
||||
folded = FoldFCmp(static_cast<FCmpInst*>(inst), ctx);
|
||||
break;
|
||||
case Opcode::ZExt:
|
||||
folded = FoldZExt(static_cast<ZExtInst*>(inst), ctx);
|
||||
break;
|
||||
case Opcode::SIToFP:
|
||||
folded = FoldSIToFP(static_cast<SIToFPInst*>(inst), ctx);
|
||||
break;
|
||||
case Opcode::FPToSI:
|
||||
folded = FoldFPToSI(static_cast<FPToSIInst*>(inst), ctx);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
if (folded) {
|
||||
removed.insert(inst);
|
||||
any_changed = true;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
|
||||
Binary file not shown.
@ -1,4 +1,83 @@
|
||||
// SysY 运行库实现:
|
||||
// - 按实验/评测规范提供 I/O 等函数实现
|
||||
// - 与编译器生成的目标代码链接,支撑运行时行为
|
||||
#include<stdio.h>
|
||||
#include<stdarg.h>
|
||||
#include<sys/time.h>
|
||||
#include"sylib.h"
|
||||
/* Input & output functions */
|
||||
int getint(){int t; scanf("%d",&t); return t; }
|
||||
int getch(){char c; scanf("%c",&c); return (int)c; }
|
||||
float getfloat(){
|
||||
float n;
|
||||
scanf("%a", &n);
|
||||
return n;
|
||||
}
|
||||
|
||||
int getarray(int a[]){
|
||||
int n;
|
||||
scanf("%d",&n);
|
||||
for(int i=0;i<n;i++)scanf("%d",&a[i]);
|
||||
return n;
|
||||
}
|
||||
|
||||
int getfarray(float a[]) {
|
||||
int n;
|
||||
scanf("%d", &n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
scanf("%a", &a[i]);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
void putint(int a){ printf("%d",a);}
|
||||
void putch(int a){ printf("%c",a); }
|
||||
void putarray(int n,int a[]){
|
||||
printf("%d:",n);
|
||||
for(int i=0;i<n;i++)printf(" %d",a[i]);
|
||||
printf("\n");
|
||||
}
|
||||
void putfloat(float a) {
|
||||
printf("%a", a);
|
||||
}
|
||||
void putfarray(int n, float a[]) {
|
||||
printf("%d:", n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
printf(" %a", a[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void putf(char a[], ...) {
|
||||
va_list args;
|
||||
va_start(args, a);
|
||||
vfprintf(stdout, a, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* Timing function implementation */
|
||||
__attribute((constructor)) void before_main(){
|
||||
for(int i=0;i<_SYSY_N;i++)
|
||||
_sysy_h[i] = _sysy_m[i]= _sysy_s[i] = _sysy_us[i] =0;
|
||||
_sysy_idx=1;
|
||||
}
|
||||
__attribute((destructor)) void after_main(){
|
||||
for(int i=1;i<_sysy_idx;i++){
|
||||
fprintf(stderr,"Timer@%04d-%04d: %dH-%dM-%dS-%dus\n",\
|
||||
_sysy_l1[i],_sysy_l2[i],_sysy_h[i],_sysy_m[i],_sysy_s[i],_sysy_us[i]);
|
||||
_sysy_us[0]+= _sysy_us[i];
|
||||
_sysy_s[0] += _sysy_s[i]; _sysy_us[0] %= 1000000;
|
||||
_sysy_m[0] += _sysy_m[i]; _sysy_s[0] %= 60;
|
||||
_sysy_h[0] += _sysy_h[i]; _sysy_m[0] %= 60;
|
||||
}
|
||||
fprintf(stderr,"TOTAL: %dH-%dM-%dS-%dus\n",_sysy_h[0],_sysy_m[0],_sysy_s[0],_sysy_us[0]);
|
||||
}
|
||||
void _sysy_starttime(int lineno){
|
||||
_sysy_l1[_sysy_idx] = lineno;
|
||||
gettimeofday(&_sysy_start,NULL);
|
||||
}
|
||||
void _sysy_stoptime(int lineno){
|
||||
gettimeofday(&_sysy_end,NULL);
|
||||
_sysy_l2[_sysy_idx] = lineno;
|
||||
_sysy_us[_sysy_idx] += 1000000 * ( _sysy_end.tv_sec - _sysy_start.tv_sec ) + _sysy_end.tv_usec - _sysy_start.tv_usec;
|
||||
_sysy_s[_sysy_idx] += _sysy_us[_sysy_idx] / 1000000 ; _sysy_us[_sysy_idx] %= 1000000;
|
||||
_sysy_m[_sysy_idx] += _sysy_s[_sysy_idx] / 60 ; _sysy_s[_sysy_idx] %= 60;
|
||||
_sysy_h[_sysy_idx] += _sysy_m[_sysy_idx] / 60 ; _sysy_m[_sysy_idx] %= 60;
|
||||
_sysy_idx ++;
|
||||
}
|
||||
|
||||
@ -1,4 +1,31 @@
|
||||
// SysY 运行库头文件:
|
||||
// - 声明运行库函数原型(供编译器生成 call 或链接阶段引用)
|
||||
// - 与 sylib.c 配套,按规范逐步补齐声明
|
||||
#ifndef __SYLIB_H_
|
||||
#define __SYLIB_H_
|
||||
|
||||
#include<stdio.h>
|
||||
#include<stdarg.h>
|
||||
#include<sys/time.h>
|
||||
/* Input & output functions */
|
||||
int getint(),getch(),getarray(int a[]);
|
||||
float getfloat();
|
||||
int getfarray(float a[]);
|
||||
|
||||
void putint(int a),putch(int a),putarray(int n,int a[]);
|
||||
void putfloat(float a);
|
||||
void putfarray(int n, float a[]);
|
||||
|
||||
void putf(char a[], ...);
|
||||
|
||||
/* Timing function implementation */
|
||||
struct timeval _sysy_start,_sysy_end;
|
||||
#define starttime() _sysy_starttime(__LINE__)
|
||||
#define stoptime() _sysy_stoptime(__LINE__)
|
||||
#define _SYSY_N 1024
|
||||
int _sysy_l1[_SYSY_N],_sysy_l2[_SYSY_N];
|
||||
int _sysy_h[_SYSY_N], _sysy_m[_SYSY_N],_sysy_s[_SYSY_N],_sysy_us[_SYSY_N];
|
||||
int _sysy_idx;
|
||||
__attribute((constructor)) void before_main();
|
||||
__attribute((destructor)) void after_main();
|
||||
void _sysy_starttime(int lineno);
|
||||
void _sysy_stoptime(int lineno);
|
||||
|
||||
#endif
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
// test/test_case/functional/test_riscv.sy
|
||||
int main() {
|
||||
int a = 10;
|
||||
int b = 20;
|
||||
int c = a + b;
|
||||
return c; // 应该返回30
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1 @@
|
||||
3
|
||||
@ -0,0 +1,3 @@
|
||||
int main(){
|
||||
return 3;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
10
|
||||
@ -0,0 +1,8 @@
|
||||
//test domain of global var define and local define
|
||||
int a = 3;
|
||||
int b = 5;
|
||||
|
||||
int main(){
|
||||
int a = 5;
|
||||
return a + b;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
5
|
||||
@ -0,0 +1,8 @@
|
||||
//test local var define
|
||||
int main(){
|
||||
int a, b0, _c;
|
||||
a = 1;
|
||||
b0 = 2;
|
||||
_c = 3;
|
||||
return b0 + _c;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
0
|
||||
@ -0,0 +1,4 @@
|
||||
int a[10][10];
|
||||
int main(){
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
14
|
||||
@ -0,0 +1,9 @@
|
||||
//test array define
|
||||
int main(){
|
||||
int a[4][2] = {};
|
||||
int b[4][2] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
int c[4][2] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
|
||||
int d[4][2] = {1, 2, {3}, {5}, 7 , 8};
|
||||
int e[4][2] = {{d[2][1], c[2][1]}, {3, 4}, {5, 6}, {7, 8}};
|
||||
return e[3][1] + e[0][0] + e[0][1] + a[2][0];
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
21
|
||||
@ -0,0 +1,9 @@
|
||||
int main(){
|
||||
const int a[4][2] = {{1, 2}, {3, 4}, {}, 7};
|
||||
|
||||
int b[4][2] = {};
|
||||
int c[4][2] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
int d[3 + 1][2] = {1, 2, {3}, {5}, a[3][0], 8};
|
||||
int e[4][2][1] = {{d[2][1], {c[2][1]}}, {3, 4}, {5, 6}, {7, 8}};
|
||||
return e[3][1][0] + e[0][0][0] + e[0][1][0] + d[3][0];
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
//test const gloal var define
|
||||
const int a = 10, b = 5;
|
||||
|
||||
int main(){
|
||||
return b;
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
//test const local var define
|
||||
int main(){
|
||||
const int a = 10, b = 5;
|
||||
return b;
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
const int a[5]={0,1,2,3,4};
|
||||
|
||||
int main(){
|
||||
return a[4];
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
9
|
||||
@ -0,0 +1,11 @@
|
||||
int a;
|
||||
int func(int p){
|
||||
p = p - 1;
|
||||
return p;
|
||||
}
|
||||
int main(){
|
||||
int b;
|
||||
a = 10;
|
||||
b = func(a);
|
||||
return b;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
4
|
||||
@ -0,0 +1,8 @@
|
||||
int defn(){
|
||||
return 4;
|
||||
}
|
||||
|
||||
int main(){
|
||||
int a=defn();
|
||||
return a;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
9
|
||||
@ -0,0 +1,7 @@
|
||||
//test add
|
||||
int main(){
|
||||
int a, b;
|
||||
a = 10;
|
||||
b = -1;
|
||||
return a + b;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
15
|
||||
@ -0,0 +1,5 @@
|
||||
//test addc
|
||||
const int a = 10;
|
||||
int main(){
|
||||
return a + 5;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
248
|
||||
@ -0,0 +1,7 @@
|
||||
//test sub
|
||||
const int a = 10;
|
||||
int main(){
|
||||
int b;
|
||||
b = 2;
|
||||
return b - a;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
8
|
||||
@ -0,0 +1,6 @@
|
||||
//test subc
|
||||
int main(){
|
||||
int a;
|
||||
a = 10;
|
||||
return a - 2;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
50
|
||||
@ -0,0 +1,7 @@
|
||||
//test mul
|
||||
int main(){
|
||||
int a, b;
|
||||
a = 10;
|
||||
b = 5;
|
||||
return a * b;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
25
|
||||
@ -0,0 +1,5 @@
|
||||
//test mulc
|
||||
const int a = 5;
|
||||
int main(){
|
||||
return a * 5;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
2
|
||||
@ -0,0 +1,7 @@
|
||||
//test div
|
||||
int main(){
|
||||
int a, b;
|
||||
a = 10;
|
||||
b = 5;
|
||||
return a / b;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
2
|
||||
@ -0,0 +1,5 @@
|
||||
//test divc
|
||||
const int a = 10;
|
||||
int main(){
|
||||
return a / 5;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
3
|
||||
@ -0,0 +1,6 @@
|
||||
//test mod
|
||||
int main(){
|
||||
int a;
|
||||
a = 10;
|
||||
return a / 3;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
1
|
||||
@ -0,0 +1,6 @@
|
||||
//test rem
|
||||
int main(){
|
||||
int a;
|
||||
a = 10;
|
||||
return a % 3;
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
-5
|
||||
0
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue