|
|
|
|
@ -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)
|
|
|
|
|
```
|