feat(backend/riscv32): 实现基础的编译器功能
- 完成 RV32IMA 指令集的代码生成 - 添加整数运算、分支、调用等基本指令支持 - 实现从 IR 到机器码的转换 - 添加简单的测试用例和测试框架
This commit is contained in:
3
ccompiler/backend/riscv32/tests/simple/01_return.c
Normal file
3
ccompiler/backend/riscv32/tests/simple/01_return.c
Normal file
@ -0,0 +1,3 @@
|
||||
int main() {
|
||||
return 65536;
|
||||
}
|
8
ccompiler/backend/riscv32/tests/simple/02_decl_expr.c
Normal file
8
ccompiler/backend/riscv32/tests/simple/02_decl_expr.c
Normal file
@ -0,0 +1,8 @@
|
||||
int main() {
|
||||
int a;
|
||||
int b;
|
||||
a = 1 + 2 * 3;
|
||||
b = 7;
|
||||
a = a - b + 1;
|
||||
return a;
|
||||
}
|
6
ccompiler/backend/riscv32/tests/simple/03_decl_init.c
Normal file
6
ccompiler/backend/riscv32/tests/simple/03_decl_init.c
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
int main() {
|
||||
int x = 10;
|
||||
x = x + 1;
|
||||
return x;
|
||||
}
|
10
ccompiler/backend/riscv32/tests/simple/04_if.c
Normal file
10
ccompiler/backend/riscv32/tests/simple/04_if.c
Normal file
@ -0,0 +1,10 @@
|
||||
int main(void) {
|
||||
int a;
|
||||
a = 1;
|
||||
if (a) {
|
||||
a = 1;
|
||||
} else {
|
||||
a = 2;
|
||||
}
|
||||
return a;
|
||||
}
|
10
ccompiler/backend/riscv32/tests/simple/05_else.c
Normal file
10
ccompiler/backend/riscv32/tests/simple/05_else.c
Normal file
@ -0,0 +1,10 @@
|
||||
int main(void) {
|
||||
int a;
|
||||
a = 0;
|
||||
if (a) {
|
||||
a = 1;
|
||||
} else {
|
||||
a = 2;
|
||||
}
|
||||
return a;
|
||||
}
|
9
ccompiler/backend/riscv32/tests/simple/06_fcall.c
Normal file
9
ccompiler/backend/riscv32/tests/simple/06_fcall.c
Normal file
@ -0,0 +1,9 @@
|
||||
int add(int, int);
|
||||
|
||||
int main(void) {
|
||||
return add(1, 2);
|
||||
}
|
||||
|
||||
int add(int a, int b) {
|
||||
return a + b;
|
||||
}
|
5
ccompiler/backend/riscv32/tests/simple/07_while.c
Normal file
5
ccompiler/backend/riscv32/tests/simple/07_while.c
Normal file
@ -0,0 +1,5 @@
|
||||
int main() {
|
||||
int i = 0;
|
||||
while (i < 10) i = i + 1;
|
||||
return i;
|
||||
}
|
12
ccompiler/backend/riscv32/tests/simple/08_do_while.c
Normal file
12
ccompiler/backend/riscv32/tests/simple/08_do_while.c
Normal file
@ -0,0 +1,12 @@
|
||||
// #include <stdio.h>
|
||||
|
||||
int main() {
|
||||
int i = 0;
|
||||
int pow = 1;
|
||||
do {
|
||||
pow = pow * 2;
|
||||
i = i + 1;
|
||||
} while(i < 7);
|
||||
// printf("%d", pow);
|
||||
return pow;
|
||||
}
|
7
ccompiler/backend/riscv32/tests/simple/09_for.c
Normal file
7
ccompiler/backend/riscv32/tests/simple/09_for.c
Normal file
@ -0,0 +1,7 @@
|
||||
int main() {
|
||||
int num = 0;
|
||||
for (int i = 0; i < 10; i += 1) {
|
||||
num = num + 1;
|
||||
}
|
||||
return num;
|
||||
}
|
7
ccompiler/backend/riscv32/tests/simple/10_main.c
Normal file
7
ccompiler/backend/riscv32/tests/simple/10_main.c
Normal file
@ -0,0 +1,7 @@
|
||||
int add(int a, int b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
return add(1, 2);
|
||||
}
|
18
ccompiler/backend/riscv32/tests/simple/11_recursive.c
Normal file
18
ccompiler/backend/riscv32/tests/simple/11_recursive.c
Normal file
@ -0,0 +1,18 @@
|
||||
// #include <stdio.h>
|
||||
|
||||
int factorial(int num);
|
||||
|
||||
int main() {
|
||||
int num = 5;
|
||||
int result = factorial(num);
|
||||
// printf("%d", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
int factorial(int num) {
|
||||
if (num == 0) {
|
||||
return 1;
|
||||
} else {
|
||||
return num * factorial(num - 1);
|
||||
}
|
||||
}
|
28
ccompiler/backend/riscv32/tests/simple/Makefile
Normal file
28
ccompiler/backend/riscv32/tests/simple/Makefile
Normal file
@ -0,0 +1,28 @@
|
||||
VM := ../../rv32-vm
|
||||
CC := ../../ccompiler
|
||||
STD_CC := gcc
|
||||
|
||||
TESTS := $(wildcard *.c)
|
||||
|
||||
# 定义所有测试目标
|
||||
TEST_TARGETS := $(patsubst %.c, %_test, $(TESTS))
|
||||
|
||||
all: $(TEST_TARGETS)
|
||||
|
||||
%_test: %.c
|
||||
@$(STD_CC) -g -o $@ $<
|
||||
@$(CC) $< flat.bin
|
||||
@./$@ ; ret_gcc=$$?
|
||||
@$(VM) flat.bin ; ret_vm=$$?
|
||||
@echo "Testing $@"
|
||||
@if [ $$ret_gcc -eq $$ret_vm ]; then \
|
||||
echo "$@ passed"; \
|
||||
else \
|
||||
echo "$@ failed: GCC returned $$ret_gcc, VM returned $$ret_vm"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
clean:
|
||||
rm -f $(TEST_TARGETS) flat.bin
|
||||
|
||||
.PHONY: all clean
|
6
ccompiler/backend/riscv32/tests/simple/hard_01.c
Normal file
6
ccompiler/backend/riscv32/tests/simple/hard_01.c
Normal file
@ -0,0 +1,6 @@
|
||||
int main() {
|
||||
int a, b;
|
||||
a = 1;
|
||||
b = 2;
|
||||
return a + b;
|
||||
}
|
86
ccompiler/backend/riscv32/tests/simple/test.py
Normal file
86
ccompiler/backend/riscv32/tests/simple/test.py
Normal file
@ -0,0 +1,86 @@
|
||||
import subprocess
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# 配置参数
|
||||
TEST_DIR = Path(".")
|
||||
CC_PATH = Path("../../ccompiler.exe")
|
||||
VM_PATH = Path("../../rv32-vm.exe")
|
||||
WORKSPACE = Path(".") # 测试工作目录
|
||||
|
||||
# 测试用例映射表(示例)
|
||||
TEST_CASE_MAP = {
|
||||
"./01_return.c": 65536,
|
||||
"./02_decl_expr.c": 1,
|
||||
"./03_decl_init.c": 11,
|
||||
"./04_if.c": 1,
|
||||
"./05_else.c": 2,
|
||||
"./06_fcall.c": 3,
|
||||
"./07_while.c": 10,
|
||||
"./08_do_while.c": 128,
|
||||
"./09_for.c": 10,
|
||||
"./10_main.c": 3,
|
||||
"./11_recursive.c": 120,
|
||||
}
|
||||
|
||||
def run_command(cmd, capture_stderr=True):
|
||||
"""执行命令并捕获stderr"""
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
cwd=WORKSPACE,
|
||||
stderr=subprocess.PIPE if capture_stderr else None,
|
||||
text=True,
|
||||
timeout=1,
|
||||
)
|
||||
return result.stderr.strip() if capture_stderr else None
|
||||
|
||||
def run_test(test_file, expected):
|
||||
print(f"\nTesting {test_file}...")
|
||||
|
||||
# 1. 编译生成flat.bin
|
||||
compile_cmd = [str(CC_PATH), str(test_file)]
|
||||
compile_err = run_command(compile_cmd)
|
||||
|
||||
if not (WORKSPACE / "flat.bin").exists():
|
||||
print(f" Compilation failed: {compile_err}")
|
||||
return False
|
||||
|
||||
# 2. 执行虚拟机
|
||||
vm_cmd = [str(VM_PATH), "flat.bin"]
|
||||
|
||||
# 3. 解析返回值(假设最后一行是返回值)
|
||||
try:
|
||||
vm_err = run_command(vm_cmd)
|
||||
actual = int(vm_err.split()[-1])
|
||||
except (ValueError, IndexError) as e:
|
||||
print(f" Invalid VM output: {vm_err}")
|
||||
return False
|
||||
except subprocess.TimeoutExpired:
|
||||
print(" Timeout expired")
|
||||
return False
|
||||
|
||||
# 4. 验证结果
|
||||
if actual == expected:
|
||||
print(f" PASSED {test_file}")
|
||||
return True
|
||||
else:
|
||||
print(f" FAILED: Expected {expected}, got {actual}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
passed = 0
|
||||
total = 0
|
||||
|
||||
for test_file, expected in TEST_CASE_MAP.items():
|
||||
total += 1
|
||||
if run_test(TEST_DIR / test_file, expected):
|
||||
passed += 1
|
||||
|
||||
# 清理中间文件
|
||||
if (WORKSPACE / "flat.bin").exists():
|
||||
os.remove(WORKSPACE / "flat.bin")
|
||||
|
||||
print(f"\nTest Summary: {passed}/{total} passed")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Reference in New Issue
Block a user