修复库文件改动造成的链接失败

tansiping^2
Junhe Wu 2 weeks ago
parent 7766b1ba84
commit 8b6ad43df0

@ -0,0 +1,87 @@
# Fix: starttime/stoptime 库函数链接错误
**日期**: 2026-05-19
**分支**: fix/ir-opt
**测试结果**: 737/737 通过 (--O0 --run)
## 问题描述
运行 `bash scripts/run_ir_test.sh --O0 --run` 时,所有调用 `starttime()` / `stoptime()` 的 performance 测试用例在链接阶段失败:
```
undefined reference to `starttime'
undefined reference to `stoptime'
```
## 根因分析
`sylib/sylib.c` 中实际定义的计时函数是 `_sysy_starttime(int lineno)``_sysy_stoptime(int lineno)`。`sylib/sylib.h` 中的 `starttime()` / `stoptime()` 只是 C 预处理器宏:
```c
#define starttime() _sysy_starttime(__LINE__)
#define stoptime() _sysy_stoptime(__LINE__)
```
SysY 编译器在 IR 生成时直接将 `starttime` / `stoptime` 作为 LLVM IR 函数名,导致:
1. 链接器找不到 `starttime` / `stoptime` 符号(实际符号是 `_sysy_starttime` / `_sysy_stoptime`
2. 宏中的 `__LINE__` 无法通过 C 预处理器展开,调用未自动传入行号参数
## 修改内容
**文件**: `src/irgen/IRGenExp.cpp`
### 修改1: EnsureExternalDecl 函数名映射第167行
将外部函数声明的名称匹配从 `"starttime" || "stoptime"` 改为 `"_sysy_starttime" || "_sysy_stoptime"`
```cpp
// Before
} else if (name == "starttime" || name == "stoptime") {
module_.DeclareExternalFunc(name, ir::Type::GetVoidType(),
{ir::Type::GetInt32Type()});
// After
} else if (name == "_sysy_starttime" || name == "_sysy_stoptime") {
module_.DeclareExternalFunc(name, ir::Type::GetVoidType(),
{ir::Type::GetInt32Type()});
```
### 修改2: 调用点名称映射 + 行号自动插入第291行
在函数调用实参收集前,将 SysY 层面的 `starttime` / `stoptime` 映射为实际的库函数名,并自动插入源码行号作为实参:
```cpp
std::string callee_name = ctx->Ident()->getText();
// 收集实参
std::vector<ir::Value*> args;
// 映射 starttime/stoptime 到实际的库函数名,并自动插入行号
if (callee_name == "starttime") {
callee_name = "_sysy_starttime";
args.push_back(builder_.CreateConstInt(ctx->getStart()->getLine()));
} else if (callee_name == "stoptime") {
callee_name = "_sysy_stoptime";
args.push_back(builder_.CreateConstInt(ctx->getStart()->getLine()));
}
```
## 效果
修改前生成的 IR
```llvm
declare void @starttime(i32)
declare void @stoptime(i32)
...
call void @starttime() ; 无参数,链接失败
call void @stoptime()
```
修改后生成的 IR
```llvm
declare void @_sysy_starttime(i32)
declare void @_sysy_stoptime(i32)
...
call void @_sysy_starttime(i32 65) ; 正确函数名 + 行号参数
call void @_sysy_stoptime(i32 84)
```

@ -164,7 +164,7 @@ void IRGenImpl::EnsureExternalDecl(const std::string& name) {
module_.DeclareExternalFunc(name, ir::Type::GetVoidType(),
{ir::Type::GetInt32Type(),
ir::Type::GetPtrFloat32Type()});
} else if (name == "starttime" || name == "stoptime") {
} else if (name == "_sysy_starttime" || name == "_sysy_stoptime") {
module_.DeclareExternalFunc(name, ir::Type::GetVoidType(),
{ir::Type::GetInt32Type()});
} else {
@ -290,6 +290,15 @@ std::any IRGenImpl::visitUnaryExp(SysYParser::UnaryExpContext* ctx) {
// 收集实参
std::vector<ir::Value*> args;
// 映射 starttime/stoptime 到实际的库函数名,并自动插入行号
if (callee_name == "starttime") {
callee_name = "_sysy_starttime";
args.push_back(builder_.CreateConstInt(ctx->getStart()->getLine()));
} else if (callee_name == "stoptime") {
callee_name = "_sysy_stoptime";
args.push_back(builder_.CreateConstInt(ctx->getStart()->getLine()));
}
if (ctx->funcRParams()) {
for (auto* exp : ctx->funcRParams()->exp()) {
// 检查是否是数组变量(无索引的 lVar若是则传指针而非 load

Loading…
Cancel
Save