Compare commits

..

53 Commits

Author SHA1 Message Date
d465fb02a5 [midend-m2r]恢复原有mem2reg 2025-08-19 17:44:54 +08:00
3c49183280 [midend-m2r]移除错误的LAG优化,performance通过 2025-08-19 17:32:01 +08:00
7af3827098 [midend-m2r]修改Mem2Reg.cpp 2025-08-19 16:37:52 +08:00
1ab937961f [backend-O1]修复后端在-O1情况下存在的大量bug 2025-08-19 14:09:08 +08:00
06b4df79ee [backend]暂时禁用中端强度削弱 2025-08-19 08:30:55 +08:00
d79857feb9 修改脚本,增强输出截断逻辑 2025-08-19 08:29:43 +08:00
91d4a39c9a Merge branch 'midend-tco' into backend 2025-08-19 00:15:30 +08:00
042b1a5d99 [midend-tco]修复命名重复问题 2025-08-19 00:13:32 +08:00
0fdcd0dd69 Merge branch 'midend-tco' into backend 2025-08-18 23:52:05 +08:00
d7bf4b061f [backend]适配SLL、SRL指令 2025-08-18 23:49:40 +08:00
937833117e [midend-tco]添加TCO尾递归优化 2025-08-18 23:46:00 +08:00
094b4c7c39 Merge branch 'midend' into backend 2025-08-18 22:52:02 +08:00
f4617b357e Merge commit '07fd22def182a12999de6ae0c9447056fb9d7a40' into backend 2025-08-18 22:50:58 +08:00
babb576317 [backend]完善异步执行的超时切断机制 2025-08-18 22:50:14 +08:00
0720a622c1 [backend]完善后端流水线,本地仅剩h/39不通过 2025-08-18 22:14:21 +08:00
ad74e435ba [midend-GSR]修复错误的代数简化 2025-08-18 21:55:57 +08:00
acb0302a29 [backend]修复了简单图着色分配器在一些样例中的问题 2025-08-18 21:14:37 +08:00
5c34cbc7b8 [midend-GSR]将魔数求解移动到utils的静态方法中。 2025-08-18 20:37:20 +08:00
c9a0c700e1 [midend]增加全局强度削弱优化遍 2025-08-18 11:30:40 +08:00
b57a3f1953 [backend]正在修复h/39 2025-08-17 22:45:57 +08:00
f317010d76 [midend-Loop-LICM][fix]检查load能否外提时其内存地址在循环中是否会被修改,需要判断函数调用对load内存地址的影响。 2025-08-17 17:42:19 +08:00
8ca64610eb [midend-GVN]重构GVN的值编号系统 2025-08-17 16:33:15 +08:00
969a78a088 [midend-GVN]segmentation fault是GVN引入的已修复,LICM仍然有错误 2025-08-17 14:37:27 +08:00
d77aedaf8b [backend]修复87 2025-08-17 09:01:49 +08:00
8763c0a11a [midend-LICM][fix]修改计算循环不变量依赖关系的排序错误,但是引入了很多Segmentation fault。 2025-08-17 01:35:03 +08:00
d83dc7a2e7 [midend-LICM][fix]修复循环不变量的识别逻辑 2025-08-17 01:19:44 +08:00
e32585fd25 [midend-GVN]修复GVN中部分逻辑问题,LICM有bug待修复 2025-08-17 00:14:47 +08:00
07fd22def1 [backend-fma]添加浮点乘加融合优化,提供开关简单控制是否启用 2025-08-17 00:07:04 +08:00
c4eb1c3980 [midend-GVN&SideEffect]修复GVN的部分问题和副作用分析的缺陷 2025-08-16 18:52:29 +08:00
5ef01ada90 [backend]解决了栈地址计算对齐逻辑错误的问题 2025-08-16 18:31:45 +08:00
072cd3e9b5 [backend]回溯了旧版本的寄存器分配器 2025-08-16 17:08:11 +08:00
d038884ffb [midend-GVN] commit头文件 2025-08-16 15:43:51 +08:00
467f2f6b24 [midend-GVN]初步构建GVN,能够优化部分CSE无法处理的子表达式但是有错误需要debug。 2025-08-16 15:38:41 +08:00
7be5d25372 [backend]更改了commit顺序 2025-08-16 00:11:21 +08:00
fdba73d5e1 Merge branch 'midend' into backend 2025-08-15 21:23:48 +08:00
8cabb1f195 Merge branch 'backend' of gitee.com:lixuanwang/mysysy into backend 2025-08-15 21:23:02 +08:00
fa33bf5134 [midend-Loop-IVE]修复循环的死IV消除逻辑 2025-08-15 01:19:45 +08:00
a3435e7c26 [midend-Loop-IVE]循环归纳变量消除逻辑重构,修改运行顺序 2025-08-14 17:27:53 +08:00
a958435836 Merge commit '167c2ac2aece809765dd8ed2b869fc16f84005f2' into backend 2025-08-08 22:58:17 +08:00
33ca8ecf34 [document]修改编译器文档中端设计部分 2025-08-05 21:37:48 +08:00
d439ef7e8e [document]初步添加编译器文档 2025-08-05 20:53:44 +08:00
3ba12bf320 [backend]本地全过 2025-08-05 17:38:49 +08:00
167c2ac2ae [backend]完善了后端流水线 2025-08-05 16:10:04 +08:00
32684d8255 [backend]继续增强寄存器分配器健壮性 2025-08-05 13:50:55 +08:00
f2477c4af3 [backend]修复浮点数截断逻辑 h36通过 2025-08-05 02:44:23 +08:00
b1efd481b4 [midend]BinaryExpStack表达式弹出部分优化 2025-08-05 02:44:23 +08:00
676880ca05 [backend]消除了线性扫描分配器对参数寄存器的引用 2025-08-05 02:21:42 +08:00
df50eedaeb [backend]将浮点逻辑改为与开发板一致 2025-08-05 01:08:42 +08:00
dcc075b39c [backend]修复线性扫描逻辑 2025-08-05 01:06:07 +08:00
f7f1cf2b41 [backend]浮点逻辑与gcc保持一致 2025-08-04 21:54:24 +08:00
881c2a9723 [backend]强化了线性扫描逻辑 2025-08-04 19:28:15 +08:00
b5f14d9385 [backend]在后端主函数中添加了调试逻辑 2025-08-04 18:17:09 +08:00
72b06c67ca [backend]为图着色引入保底修复 2025-08-04 18:13:09 +08:00
49 changed files with 6008 additions and 739 deletions

View File

@ -396,9 +396,25 @@ check_initial_overflow()
智能回退:使用已验证的标准值保证正确性
保持通用性:对于没有预设值的除数仍然可以工作
## 死归纳变量消除
整体架构和工作流程
当前的归纳变量消除优化分为三个清晰的阶段:
识别阶段:找出所有潜在的死归纳变量
安全性分析阶段:验证每个变量消除的安全性
消除执行阶段:实际删除安全的死归纳变量
逃逸点检测 (已修复的关键安全机制)
数组索引检测GEP指令被正确识别为逃逸点
循环退出条件:用于比较和条件分支的归纳变量不会被消除
控制流指令condBr、br、return等被特殊处理为逃逸点
内存操作store/load指令经过别名分析检查
# 后续优化可能涉及的改动
## 1将所有的alloca集中到entryblock中
## 1将所有的alloca集中到entryblock中(已实现)
好处优化友好性方便mem2reg提升
目前没有实现这个机制,如果想要实现首先解决同一函数不同域的同名变量命名区分

266
doc/CompilerDesign.md Normal file
View File

@ -0,0 +1,266 @@
# 编译器核心技术与优化详解
本文档深入剖析 mysysy 编译器的内部实现,重点阐述其在前端、中端和后端所采用的核心编译技术及优化算法,并结合具体实现函数进行说明。
## 1. 编译器整体架构
本编译器采用经典的三段式架构将编译过程清晰地划分为前端、中端和后端三个主要部分。每个部分处理不同的抽象层级并通过定义良好的接口AST, IR进行通信实现了高度的模块化。
```mermaid
graph TD
A[源代码 .sy] --> B{前端 Frontend};
B --> C[抽象语法树 AST];
C --> D{中端 Midend};
D --> E[SSA-based IR];
E -- 优化 --> F[优化后的 IR];
F --> G{后端 Backend};
G --> H[目标机代码 MachineInstr];
H --> I[RISC-V 64 汇编代码 .s];
subgraph 前端
B
end
subgraph 中端
D
end
subgraph 后端
G
end
```
- **前端 (Frontend)**:负责词法、语法、语义分析,将 SysY 源代码解析为抽象语法树 (AST)。
- **中端 (Midend)**:基于 AST 生成与具体机器无关的中间表示 (IR),并在此基础上进行深入的分析和优化。
- **后端 (Backend)**:将优化后的 IR 翻译成目标平台RISC-V 64的汇编代码。
---
## 2. 前端技术 (Frontend)
前端的核心任务是进行语法和语义的分析与验证,其工作流程如下:
```mermaid
graph TD
subgraph "前端处理流程"
Source["源文件 (.sy)"] --> Lexer["词法分析器 (SysYLexer)"];
Lexer --> TokenStream["Token 流"];
TokenStream --> Parser["语法分析器 (SysYParser)"];
Parser --> ParseTree["解析树"];
ParseTree --> Visitor["AST构建 (SysYVisitor)"];
Visitor --> AST[抽象语法树];
end
```
- **词法与语法分析**:
- **技术**: 采用 **ANTLR (ANother Tool for Language Recognition)** 框架。通过在 `frontend/SysY.g4` 文件中定义的上下文无关文法ANTLR 能够自动生成高效的 LL(*) 词法分析器 (`SysYLexer.cpp`) 和语法分析器 (`SysYParser.cpp`)。
- **实现**: 词法分析器将字符流转换为记号 (Token) 流,语法分析器则根据文法规则将记号流组织成一棵解析树 (Parse Tree)。这棵树精确地反映了源代码的语法结构。
- **AST 构建**:
- **技术**: 应用 **访问者 (Visitor) 设计模式** 遍历 ANTLR 生成的解析树。该模式将数据结构解析树与作用于其上的操作AST构建逻辑解耦。
- **实现**: `frontend/SysYVisitor.cpp` 中定义了具体的遍历逻辑。在遍历过程中,会构建一个比解析树更抽象、更面向编译需求的**抽象语法树 (Abstract Syntax Tree, AST)**。AST 忽略了纯粹的语法细节(如括号、分号),只保留了核心的语义结构,是前端传递给中端的接口。
---
## 3. 中端技术与优化 (Midend)
中端是编译器的核心,所有与目标机器无关的分析和优化都在此阶段完成。
### 3.1. 中间表示 (IR) 及设计要点
- **技术**: 设计了一种三地址码Three-Address Code风格的中间表示其形式和设计哲学深受 **LLVM IR** 的启发。IR 的核心特征是采用了**静态单赋值 (Static Single Assignment, SSA)** 形式。
- **实现**: `midend/IR.cpp` 定义了 IR 的核心数据结构,如 `Instruction`, `BasicBlock`, `Function``Module``midend/SysYIRGenerator.cpp` 负责将前端的 AST 转换为这种 IR。在 SSA 形式下,每个变量只被赋值一次,使得变量的定义-使用关系Def-Use Chain变得异常清晰极大地简化了后续的优化算法。通过继承并重写 SysYBaseVisitor 类,遍历 AST 节点生成自定义 IR并在 IR 生成阶段实现了简单的常量传播和公共子表达式消除CSE
- **设计要点**
- **`alloca` 指令集中管理**
所有 `alloca` 指令统一放置在入口基本块,并与实际计算指令分离。这有助于后续指令调度器专注于优化计算密集型指令的执行顺序,避免内存分配指令的干扰。
- **消除 `fallthrough` 现象**
通过确保所有基本块均以终结指令结尾,消除基本块间的 `fallthrough`简化了控制流图CFG的构建和分析。这一做法提升了编译器整体质量使中端各类 Pass 的编写和维护更加规范和高效。
### 3.2. 核心优化详解
编译器的分析和优化被组织成一系列独立的“遍”Pass。每个 Pass 都是一个独立的算法模块,对 IR 进行特定的分析或变换。这种设计具有高度的模块化和可扩展性。
#### 3.2.1. SSA 构建与解构
- **Mem2Reg (`Mem2Reg.cpp`)**:
- **目标**: 将对栈内存 (`alloca`) 的 `load`/`store` 操作,提升为对虚拟寄存器的直接操作,并构建 SSA 形式。
- **技术**: 该过程是实现 SSA 的关键。它依赖于**支配树 (Dominator Tree)** 分析,通过寻找变量定义块的**支配边界 (Dominance Frontier)** 来确定在何处插入 **Φ (Phi) 函数**
- **实现**: `Mem2RegContext::run` 驱动此过程。首先调用 `isPromotableAlloca` 识别所有仅被 `load`/`store` 使用的标量 `alloca`。然后,`insertPhis` 根据支配边界信息在必要的控制流汇合点插入 `phi` 指令。最后,`renameVariables` 递归地遍历支配树,用一个模拟的值栈来将 `load` 替换为栈顶的 SSA 值,将 `store` 视为对栈的一次 `push` 操作从而完成重命名。值得一提的是由于我们在IR生成阶段就将所有alloca指令统一放置在入口块极大地简化了Mem2Reg遍的实现和支配树分析的计算。
- **Reg2Mem (`Reg2Mem.cpp`)**:
- **目标**: 执行 `Mem2Reg` 的逆操作,将程序从 SSA 形式转换回基于内存的表示。这通常是为不支持 SSA 的后端做准备的**SSA解构 (SSA Destruction)** 步骤。
- **技术**: 为每个 SSA 值(指令结果、函数参数)在函数入口创建一个 `alloca` 栈槽。然后,在每个 SSA 值的定义点之后插入一个 `store` 将其存入对应的栈槽;在每个使用点之前插入一个 `load` 从栈槽中取出值。
- **实现**: `Reg2MemContext::run` 驱动此过程。`allocateMemoryForSSAValues` 为所有需要转换的 SSA 值创建 `alloca` 指令。`rewritePhis` 特殊处理 `phi` 指令,在每个前驱块的末尾插入 `store``insertLoadsAndStores` 则处理所有非 `phi` 指令的定义和使用,插入相应的 `store``load`。虽然
#### 3.2.2. 常量与死代码优化
- **SCCP (`SCCP.cpp`)**:
- **目标**: 稀疏条件常量传播。在编译期计算常量表达式,并利用分支条件为常数的信息来消除死代码,比简单的常量传播更强大。
- **技术**: 这是一种基于数据流分析的格理论Lattice Theory的优化。它为每个变量维护一个值状态可能为 `Top` (未定义), `Constant` (某个常量值), 或 `Bottom` (非常量)。同时,它跟踪基本块的可达性,如果一个分支的条件被推断为常量,则其不可达的后继分支在分析中会被直接忽略。
- **实现**: `SCCPContext::run` 驱动整个分析过程。它维护一个指令工作列表和一个边工作列表。`ProcessInstruction``ProcessEdge` 函数交替执行,不断地从 IR 中传播常量和可达性信息,直到达到不动点为止。最后,`PropagateConstants``SimplifyControlFlow` 将推断出的常量替换到代码中,并移除死块。
- **DCE (`DCE.cpp`)**:
- **目标**: 简单死代码消除。移除那些计算结果对程序输出没有贡献的指令。
- **技术**: 采用**标记-清除 (Mark and Sweep)** 算法。从具有副作用的指令(如 `store`, `call`, `return`)开始,反向追溯其操作数,标记所有相关的指令为“活跃”。
- **实现**: `DCEContext::run` 实现了此算法。第一次遍历时,通过 `isAlive` 函数识别出具有副作用的“根”指令,然后调用 `addAlive` 递归地将所有依赖的指令加入 `alive_insts` 集合。第二次遍历时,所有未被标记为活跃的指令都将被删除。
- **未来规划**: 后续开发更多分析遍会为DCE收集更多的IR信息能够迭代出更健壮的DEC遍。
#### 3.2.3. 控制流图 (CFG) 优化
- **实现**: `SysYIRCFGOpt.cpp` 中定义了一系列用于清理和简化控制流图的 Pass。
- **`SysYDelInstAfterBrPass`**: 删除分支指令后的死代码。
- **`SysYDelNoPreBLockPass`**: 通过从入口块开始的图遍历BFS识别并删除所有不可达的基本块。
- **`SysYDelEmptyBlockPass`**: 识别并删除仅包含一条无条件跳转指令的空块,将其前驱直接重定向到其后继。
- **`SysYBlockMergePass`**: 如果一个块 A 只有一个后继 B且 B 只有一个前驱 A则将 A 和 B 合并为一个块。
- **`SysYCondBr2BrPass`**: 如果一个条件分支的条件是常量,则将其转换为一个无条件分支。
- **`SysYAddReturnPass`**: 确保所有没有终结指令的函数出口路径都有一个 `return` 指令,以保证 CFG 的完整性。
#### 3.2.4. 其他优化
#### 3.3. 核心分析遍
为了为优化遍收集信息,最大程度发掘程序优化潜力,我们目前设计并实现了以下关键的分析遍:
- **支配树分析 (Dominator Tree Analysis)**:
- **技术**: 通过计算每个基本块的支配节点,构建出一棵支配树结构。我们在计算支配节点时采用了**逆后序遍历RPO, Reverse Post Order**以保证数据流分析的收敛速度和正确性。在计算直接支配者Idom, Immediate Dominator采用了经典的**Lengauer-TarjanLT算法**,该算法以高效的并查集和路径压缩技术著称,能够在线性时间内准确计算出每个基本块的直接支配者关系。
- **实现**: `Dom.cpp` 实现了支配树分析。该分析为每个基本块分配其直接支配者,并递归构建整棵支配树。支配树是许多高级优化(尤其是 SSA 形式下的优化的基础。例如Mem2Reg 需要依赖支配树来正确插入 Phi 指令,并在变量重命名阶段高效遍历控制流图。此外,循环相关优化(如循环不变量外提)也依赖于支配树信息来识别循环头和循环体的关系。
- **活跃性分析 (Liveness Analysis)**:
- **技术**: 活跃性分析用于确定在程序的某一特定点上,哪些变量的值在未来会被用到。我们采用**经典的不动点迭代算法**,在数据流分析框架下,逆序遍历基本块,迭代计算每个基本块的 `live-in``live-out` 集合,直到收敛为止。这种方法简单且易于实现,能够满足大多数编译优化的需求。
- **未来规划**: 若后续对分析效率有更高要求,可考虑引入如**工作列表算法**或者**转化为基于SSA的图可达性分析**等更高效的算法,以进一步提升大型函数或复杂控制流下的分析性能。
- **实现**: `Liveness.cpp` 提供了活跃性分析。该分析采用经典的数据流分析框架,迭代计算每个基本块的 `live-in``live-out` 集合。活跃性信息是死代码消除DCE、寄存器分配等优化的必要前置步骤。通过准确的活跃性分析可以识别出无用的变量和指令从而为后续优化遍提供坚实的数据基础。
### 3.4. 未来的规划
基于现有的成果,我们规划将中端能力进一步扩展,近期我们重点将放在循环相关的分析和函数内联的实现,以期大幅提升最终程序的性能。
- **循环优化**:
我们正在开发一个健壮的分析遍来准确识别程序中的循环结构,并通过对已识别的循环进行规范化的转换遍,为后续的向量化、并行化工作做铺垫。并通过循环不变量提升、循环归纳变量分析与强度削减等优化提升循环相关代码的执行效率。
- **函数内联**:
函数内联能够将简单函数可能需要收集更多信息内联到call指令相应位置减少栈空间相关变动并且为其他遍发掘优化空间。
- **`LLVM IR`格式化**:
我们将为所有的IR设计并实现通用的打印器方法使得IR能够显式化为可编译运行的LLVM IR通过编排脚本和调用llvm相关工具链我们能够绕过后端编译运行中间代码为验证中端正确性提供系统化的方法同时减轻后端开发bug溯源的压力。
---
## 4. 后端技术与优化 (Backend)
后端负责将经过优化的、与机器无关的 IR 转换为针对 RISC-V 64 位架构的汇编代码。
### 4.1. 栈帧布局 (Stack Frame Layout)
在函数调用发生时,后端需要在栈上创建一个**栈帧 (Stack Frame)** 来存储局部变量、传递参数和保存寄存器。本编译器采用的栈帧布局遵循 RISC-V 调用约定,结构如下:
```
高地址 +-----------------------------+
| ... |
| 函数参数 (8+) | <-- 调用者传入的、放不进寄存器的参数
+-----------------------------+
| 返回地址 (ra) | <-- sp 在函数入口指向的位置
+-----------------------------+
| 旧的帧指针 (s0/fp) |
+-----------------------------+ <-- s0/fp 在函数序言后指向的位置
| 被调用者保存的寄存器 |
| (Callee-Saved Regs) |
+-----------------------------+
| 局部变量 (Alloca) |
+-----------------------------+
| 寄存器溢出区域 |
| (Spill Slots) |
+-----------------------------+
| 为调用其他函数预留的 |
| 出参空间 (Out-Args) |
低地址 +-----------------------------+ <-- sp 在函数序言后指向的位置
```
- **实现**: `PrologueEpilogueInsertion.h``EliminateFrameIndices.h` 中的 Pass 负责生成函数序言prologue和尾声epilogue代码来构建和销毁上述栈帧。`EliminateFrameIndices` 会将所有对抽象栈槽(如局部变量、溢出槽)的访问,替换为对帧指针 `s0` 或栈指针 `sp` 的、带有具体偏移量的访问。
### 4.2. 指令选择 (Instruction Selection)
- **目标**: 将抽象的 IR 指令高效地翻译成具体的目标机指令序列。
- **技术**: 采用 **基于 DAG (Directed Acyclic Graph) 的模式匹配** 算法。
- **实现**: `RISCv64ISel.cpp` 中的 `RISCv64ISel::select()` 驱动此过程。`selectBasicBlock()` 为每个基本块调用 `build_dag()` 来构建一个操作的 DAG然后通过 `select_recursive()` 对 DAG 进行自底向上的遍历和匹配。在 `selectNode()` 函数中,通过一个大的 `switch` 语句,为不同类型的 DAG 节点(如 `BINARY`, `LOAD`, `STORE`)匹配最优的指令序列。例如,一个 IR 的加法指令,如果其中一个操作数是小常数,会被直接匹配为一条 `ADDIW` 指令,而不是 `LI``ADDW` 两条指令。
### 4.3. 寄存器分配 (Register Allocation)
- **目标**: 将无限的虚拟寄存器映射到有限的物理寄存器上,并优雅地处理寄存器不足(溢出)的情况。
- **技术**: 实现了经典的**基于图着色 (Graph Coloring) 的全局寄存器分配算法**,这是一种强大但复杂的全局优化方法。
- **实现**: `RISCv64RegAlloc.cpp` 中的 `RISCv64RegAlloc::run()` 是主入口。它在一个循环中执行分配,直到没有寄存器需要溢出为止。其内部流程极其精密,如下图所示:
```mermaid
graph TD
subgraph "寄存器分配主循环 (RISCv64RegAlloc::run)"
direction LR
Start((Start)) --> Liveness[1. 活跃性分析 LivenessAnalysis]
Liveness --> Build[2. 构建冲突图 Build]
Build --> Worklist[3. 创建工作表 MakeWorklist]
Worklist --> Loop{Main Loop}
Loop -- simplifyWorklist 非空 --> Simplify[4a. 简化 Simplify]
Simplify --> Loop
Loop -- worklistMoves 非空 --> Coalesce[4b. 合并 Coalesce]
Coalesce --> Loop
Loop -- freezeWorklist 非空 --> Freeze[4c. 冻结 Freeze]
Freeze --> Loop
Loop -- spillWorklist 非空 --> Spill[4d. 选择溢出 SelectSpill]
Spill --> Loop
Loop -- 所有工作表为空 --> Assign[5. 分配颜色 AssignColors]
Assign --> CheckSpill{有溢出?}
CheckSpill -- Yes --> Rewrite[6. 重写代码 RewriteProgram]
Rewrite --> Liveness
CheckSpill -- No --> Finish((Finish))
end
```
1. **`analyzeLiveness()`**: 对机器指令进行数据流分析,计算出每个虚拟寄存器的活跃范围。
2. **`build()`**: 根据活跃性信息构建**冲突图 (Interference Graph)**。如果两个虚拟寄存器同时活跃,则它们冲突,在图中连接一条边。
3. **`makeWorklist()`**: 将图节点(虚拟寄存器)根据其度数放入不同的工作列表,为着色做准备。
4. **核心着色阶段 (The Loop)**:
- **`simplify()`**: 贪心地移除图中度数小于物理寄存器数量的节点,并将其压入栈中。这些节点保证可以被成功着色。
- **`coalesce()`**: 尝试将传送指令 (`MV`) 的源和目标节点合并,以消除这条指令。合并的条件基于 **Briggs****George** 启发式,以避免使图变得不可着色。
- **`freeze()`**: 当一个与传送指令相关的节点无法合并也无法简化时,放弃对该传送指令的合并希望,将其“冻结”为一个普通节点。
- **`selectSpill()`**: 当所有节点都无法进行上述操作时(即图中只剩下高度数的节点),必须选择一个节点进行**溢出 (Spill)**,即决定将其存放在内存中。
5. **`assignColors()`**: 在所有节点都被处理后,从栈中依次弹出节点,并根据其已着色邻居的颜色,为它选择一个可用的物理寄存器。
6. **`rewriteProgram()`**: 如果 `assignColors()` 阶段发现有节点被标记为溢出,此函数会被调用。它会修改机器指令,为溢出的虚拟寄存器插入从内存加载(`lw`/`ld`)和存入内存(`sw`/`sd`)的代码。然后,整个分配过程从步骤 1 重新开始。
### 4.4. 后端特定优化
在寄存器分配前后后端还会进行一系列针对目标机RISC-V特性的优化。
#### 4.4.1. 指令调度 (Instruction Scheduling)
- **寄存器分配前调度 (`PreRA_Scheduler.cpp`)**:
- **目标**: 在寄存器分配前,通过重排指令来提升性能。主要目标是**隐藏加载延迟 (Load Latency)**,即尽早发出 `load` 指令,使其结果能在需要时及时准备好,避免流水线停顿。同时,由于此时使用的是无限的虚拟寄存器,调度器有较大的自由度,但也可能因为过度重排而延长虚拟寄存器的生命周期,从而增加寄存器压力。
- **实现**: `scheduleBlock()` 函数会识别出基本块内的调度边界(如 `call` 或终结指令),然后在每个独立的区域内调用 `scheduleRegion()`。当前的实现是一种简化的列表调度,它会优先尝试将加载指令 (`LW`, `LD` 等) 在不违反数据依赖的前提下,尽可能地向前移动。
- **寄存器分配后调度 (`PostRA_Scheduler.cpp`)**:
- **目标**: 在寄存器分配完成之后,对指令序列进行最后一轮微调。此阶段调度的主要目标与分配前不同,它旨在解决由寄存器分配过程本身引入的性能问题,例如:
- **缓解溢出代价**: 将因溢出Spill而产生的 `load` 指令(从栈加载)尽可能地提前,远离其使用点;将 `store` 指令(存入栈)尽可能地推后,远离其定义点。
- **消除伪依赖**: 寄存器分配器可能会为两个原本不相关的虚拟寄存器分配同一个物理寄存器从而引入了虚假的写后读WAR或写后写WAW依赖。Post-RA 调度可以尝试解开这些伪依赖,为指令重排提供更多自由度。
- **实现**: `scheduleBlock()` 函数实现了此调度器。它采用了一种非常保守的**局部交换 (Local Swapping)** 策略。它迭代地检查相邻的两条指令,在 `canSwapInstructions()` 函数确认交换不会违反任何数据依赖RAW, WAR, WAW或内存依赖后才执行交换。这种方法虽然不如全局列表调度强大但在严格的 Post-RA 约束下是一种安全有效的优化手段。
#### 4.4.2. 强度削减 (Strength Reduction)
- **除法强度削减 (`DivStrengthReduction.cpp`)**:
- **目标**: 将机器指令中昂贵的 `DIV``DIVW` 指令(当除数为编译期常量时)替换为一系列更快、计算成本更低的指令组合。
- **技术**: 基于数论中的**乘法逆元 (Multiplicative Inverse)** 思想。对于一个整数除法 `x / d`,可以找到一个“魔数” `m` 和一个移位数 `s`,使得该除法可以被近似替换为 `(x * m) >> s`。这个过程需要处理复杂的符号、取整和溢出问题。
- **实现**: `runOnMachineFunction()` 实现了此优化。它会遍历机器指令,寻找以常量为除数的 `DIV`/`DIVW` 指令。`computeMagic()` 函数负责计算出对应的魔数和移位数。然后,根据除数是 2 的幂、1、-1 还是其他普通数字,生成不同的指令序列,包括 `MULH` (取高位乘积), `SRAI` (算术右移), `ADD`, `SUB` 等,来精确地模拟定点数除法的效果。
#### 4.4.3. 窥孔优化 (Peephole Optimization)
- **目标**: 在生成最终汇编代码之前,对相邻的机器指令序列进行局部优化,以消除冗余操作和利用目标机特性。
- **技术**: 窥孔优化是一种简单而高效的局部优化技术。它通过一个固定大小的“窥孔”(通常是 2-3 条指令)来扫描指令序列,寻找可以被更优指令序列替换的模式。
- **实现**: `PeepholeOptimizer::runOnMachineFunction()` 实现了此 Pass。它包含了一系列模式匹配和替换规则主要包括
- **冗余移动消除**: `mv x, y` 后跟着一条使用 `x` 的指令 `op z, x, ...`,如果 `x` 之后不再活跃,则将 `op` 的操作数直接替换为 `y`,并移除 `mv` 指令。
- **冗余加载消除**: `sw r1, mem; lw r2, mem` -> `sw r1, mem; mv r2, r1`。如果 `r1``r2` 是同一个寄存器,则直接移除 `lw`
- **地址计算优化**: `addi t1, base, imm1; lw t2, imm2(t1)` -> `lw t2, (imm1+imm2)(base)`。将两条指令合并为一条,减少了指令数量和中间寄存器的使用。
- **指令合并**: `addi t1, t0, imm1; addi t2, t1, imm2` -> `addi t2, t0, (imm1+imm2)`。合并连续的立即数加法。
### 4.5. 局限性与未来工作
根据项目中的 `TODO` 列表和源代码分析,当前实现存在一些可改进之处:
- **寄存器分配**:
- **`CALL` 指令处理**: 当前对 `CALL` 指令的 `use`/`def` 分析不完整,没有将所有调用者保存的寄存器标记为 `def`,这可能导致跨函数调用的值被错误破坏。
- **溢出处理**: 当前所有溢出的虚拟寄存器都被简单地映射到同一个物理寄存器 `t6` 上,这会引入大量不必要的 `load`/`store`,并可能导致 `t6` 成为性能瓶颈。
- **IR 设计**:
- 随着 SSA 的引入IR 中某些冗余信息(如基本块的 `args` 参数)可以被移除,以简化设计。
- **优化**:
- 当前的优化主要集中在标量上。可以引入更多面向循环的优化(如循环不变代码外提 LICM、归纳变量分析 IndVar和过程间优化来进一步提升性能。

View File

@ -20,18 +20,19 @@ QEMU_RISCV64="qemu-riscv64"
# --- 初始化变量 ---
EXECUTE_MODE=false
IR_EXECUTE_MODE=false # 新增
IR_EXECUTE_MODE=false
CLEAN_MODE=false
OPTIMIZE_FLAG=""
SYSYC_TIMEOUT=30
LLC_TIMEOUT=10 # 新增
LLC_TIMEOUT=10
GCC_TIMEOUT=10
EXEC_TIMEOUT=30
MAX_OUTPUT_LINES=20
MAX_OUTPUT_CHARS=1000
SY_FILES=()
PASSED_CASES=0
FAILED_CASES_LIST=""
INTERRUPTED=false # 新增
INTERRUPTED=false
# =================================================================
# --- 函数定义 ---
@ -50,22 +51,31 @@ show_help() {
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
echo " -et N 设置 qemu 自动化执行超时为 N 秒 (默认: 30)。"
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 20)。"
echo " -mc N, --max-chars N 当输出对比失败时,最多显示 N 个字符 (默认: 1000)。"
echo " -h, --help 显示此帮助信息并退出。"
echo ""
echo "可在任何时候按 Ctrl+C 来中断测试并显示当前已完成的测例总结。"
}
# 显示文件内容并根据行数和字符数截断的函数
display_file_content() {
local file_path="$1"
local title="$2"
local max_lines="$3"
local max_chars="$4" # 新增参数
if [ ! -f "$file_path" ]; then return; fi
echo -e "$title"
local line_count
local char_count
line_count=$(wc -l < "$file_path")
char_count=$(wc -c < "$file_path")
if [ "$line_count" -gt "$max_lines" ]; then
head -n "$max_lines" "$file_path"
echo -e "\e[33m[... 输出已截断,${line_count} 行 ...]\e[0m"
echo -e "\e[33m[... 输出因行数过多 (${line_count}) 而截断 ...]\e[0m"
elif [ "$char_count" -gt "$max_chars" ]; then
head -c "$max_chars" "$file_path"
echo -e "\n\e[33m[... 输出因字符数过多 (共 ${char_count} 字符) 而截断 ...]\e[0m"
else
cat "$file_path"
fi
@ -131,6 +141,7 @@ while [[ "$#" -gt 0 ]]; do
-gct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi ;;
-et) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi ;;
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
-mc|--max-chars) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_CHARS="$2"; shift 2; else echo "错误: --max-chars 需要一个正整数参数。" >&2; exit 1; fi ;;
-h|--help) show_help; exit 0 ;;
-*) echo "未知选项: $1"; show_help; exit 1 ;;
*)
@ -180,6 +191,8 @@ TOTAL_CASES=${#SY_FILES[@]}
echo "SysY 单例测试运行器启动..."
if [ -n "$OPTIMIZE_FLAG" ]; then echo "优化等级: ${OPTIMIZE_FLAG}"; fi
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, llc=${LLC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
echo "失败输出最大字符数: ${MAX_OUTPUT_CHARS}"
echo ""
for sy_file in "${SY_FILES[@]}"; do
@ -260,8 +273,8 @@ for sy_file in "${SY_FILES[@]}"; do
out_ok=1
if ! diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
echo -e "\e[31m 标准输出测试失败。\e[0m"; out_ok=0
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
fi
if [ "$ret_ok" -eq 1 ] && [ "$out_ok" -eq 1 ]; then echo -e "\e[32m 返回码与标准输出测试成功。\e[0m"; else is_passed=0; fi
@ -271,8 +284,8 @@ for sy_file in "${SY_FILES[@]}"; do
echo -e "\e[32m 标准输出测试成功。\e[0m"
else
echo -e "\e[31m 标准输出测试失败。\e[0m"; is_passed=0
display_file_content "${output_reference_file}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
display_file_content "${output_reference_file}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
fi
fi
else
@ -301,4 +314,4 @@ for sy_file in "${SY_FILES[@]}"; do
done
# --- 打印最终总结 ---
print_summary
print_summary

View File

@ -27,11 +27,12 @@ LLC_TIMEOUT=10
GCC_TIMEOUT=10
EXEC_TIMEOUT=30
MAX_OUTPUT_LINES=20
MAX_OUTPUT_CHARS=1000
TEST_SETS=()
TOTAL_CASES=0
PASSED_CASES=0
FAILED_CASES_LIST=""
INTERRUPTED=false # 新增:用于标记是否被中断
INTERRUPTED=false
# =================================================================
# --- 函数定义 ---
@ -53,6 +54,7 @@ show_help() {
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
echo " -et N 设置 qemu 执行超时为 N 秒 (默认: 30)。"
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 20)。"
echo " -mc N, --max-chars N 当输出对比失败时,最多显示 N 个字符 (默认: 1000)。"
echo " -h, --help 显示此帮助信息并退出。"
echo ""
echo "注意: 默认行为 (无 -e 或 -eir) 是将 .sy 文件同时编译为 .s (汇编) 和 .ll (IR),不执行。"
@ -60,18 +62,25 @@ show_help() {
}
# 显示文件内容并根据行数截断的函数
# 显示文件内容并根据行数和字符数截断的函数
display_file_content() {
local file_path="$1"
local title="$2"
local max_lines="$3"
local max_chars="$4" # 新增参数
if [ ! -f "$file_path" ]; then return; fi
echo -e "$title"
local line_count
local char_count
line_count=$(wc -l < "$file_path")
char_count=$(wc -c < "$file_path")
if [ "$line_count" -gt "$max_lines" ]; then
head -n "$max_lines" "$file_path"
echo -e "\e[33m[... 输出已截断,${line_count} 行 ...]\e[0m"
echo -e "\e[33m[... 输出因行数过多 (${line_count}) 而截断 ...]\e[0m"
elif [ "$char_count" -gt "$max_chars" ]; then
head -c "$max_chars" "$file_path"
echo -e "\n\e[33m[... 输出因字符数过多 (共 ${char_count} 字符) 而截断 ...]\e[0m"
else
cat "$file_path"
fi
@ -151,6 +160,7 @@ while [[ "$#" -gt 0 ]]; do
-gct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi ;;
-et) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi ;;
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
-mc|--max-chars) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_CHARS="$2"; shift 2; else echo "错误: --max-chars 需要一个正整数参数。" >&2; exit 1; fi ;;
-h|--help) show_help; exit 0 ;;
*) echo "未知选项: $1"; show_help; exit 1 ;;
esac
@ -204,6 +214,7 @@ echo "运行模式: ${RUN_MODE_INFO}"
echo "${TIMEOUT_INFO}"
if ${EXECUTE_MODE} || ${IR_EXECUTE_MODE}; then
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
echo "失败输出最大字符数: ${MAX_OUTPUT_CHARS}"
fi
echo ""
@ -298,8 +309,8 @@ while IFS= read -r sy_file; do
[ "$test_logic_passed" -eq 1 ] && echo -e "\e[32m 标准输出测试成功\e[0m"
else
echo -e "\e[31m 标准输出测试失败\e[0m"
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
display_file_content "${output_actual_file_from_ir}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
display_file_content "${output_actual_file_from_ir}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
test_logic_passed=0
fi
else
@ -308,8 +319,8 @@ while IFS= read -r sy_file; do
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
else
echo -e "\e[31m 失败: 输出不匹配\e[0m"
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
display_file_content "${output_actual_file_from_ir}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
display_file_content "${output_actual_file_from_ir}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
test_logic_passed=0
fi
fi
@ -375,8 +386,8 @@ while IFS= read -r sy_file; do
[ "$test_logic_passed" -eq 1 ] && echo -e "\e[32m 标准输出测试成功\e[0m"
else
echo -e "\e[31m 标准输出测试失败\e[0m"
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
display_file_content "${output_actual_file_S}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
display_file_content "${output_actual_file_S}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
test_logic_passed=0
fi
else
@ -385,8 +396,8 @@ while IFS= read -r sy_file; do
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
else
echo -e "\e[31m 失败: 输出不匹配\e[0m"
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
display_file_content "${output_actual_file_S}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
display_file_content "${output_actual_file_S}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
test_logic_passed=0
fi
fi

View File

@ -5,6 +5,9 @@ add_library(riscv64_backend_lib STATIC
RISCv64ISel.cpp
RISCv64LLIR.cpp
RISCv64RegAlloc.cpp
RISCv64LinearScan.cpp
RISCv64SimpleRegAlloc.cpp
RISCv64BasicBlockAlloc.cpp
Handler/CalleeSavedHandler.cpp
Handler/LegalizeImmediates.cpp
Handler/PrologueEpilogueInsertion.cpp

View File

@ -95,7 +95,7 @@ void LegalizeImmediatesPass::runOnMachineFunction(MachineFunction* mfunc) {
case RVOpcodes::LB: case RVOpcodes::LH: case RVOpcodes::LW: case RVOpcodes::LD:
case RVOpcodes::LBU: case RVOpcodes::LHU: case RVOpcodes::LWU:
case RVOpcodes::SB: case RVOpcodes::SH: case RVOpcodes::SW: case RVOpcodes::SD:
case RVOpcodes::FLW: case RVOpcodes::FSW: {
case RVOpcodes::FLW: case RVOpcodes::FSW: case RVOpcodes::FLD: case RVOpcodes::FSD: {
auto& operands = instr_ptr->getOperands();
auto mem_op = static_cast<MemOperand*>(operands.back().get());
auto offset_op = mem_op->getOffset();

View File

@ -4,6 +4,7 @@
namespace sysy {
char PeepholeOptimizer::ID = 0;
bool PeepholeOptimizer::fusedMulAddEnabled = true; // 默认启用浮点乘加融合优化
bool PeepholeOptimizer::runOnFunction(Function *F, AnalysisManager& AM) {
// This pass works on MachineFunction level, not IR level
@ -634,6 +635,99 @@ void PeepholeOptimizer::runOnMachineFunction(MachineFunction *mfunc) {
}
}
}
// 8. 浮点乘加融合优化
// 8.1 fmul.s t1, t2, t3; fadd.s t4, t1, t5 -> fmadd.s t4, t2, t3, t5
else if (isFusedMulAddEnabled() &&
mi1->getOpcode() == RVOpcodes::FMUL_S &&
mi2->getOpcode() == RVOpcodes::FADD_S) {
if (mi1->getOperands().size() == 3 && mi2->getOperands().size() == 3) {
auto *fmul_dst = static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *fmul_src1 = static_cast<RegOperand *>(mi1->getOperands()[1].get());
auto *fmul_src2 = static_cast<RegOperand *>(mi1->getOperands()[2].get());
auto *fadd_dst = static_cast<RegOperand *>(mi2->getOperands()[0].get());
auto *fadd_src1 = static_cast<RegOperand *>(mi2->getOperands()[1].get());
auto *fadd_src2 = static_cast<RegOperand *>(mi2->getOperands()[2].get());
// 检查fmul的目标是否是fadd的第一个源操作数
if (areRegsEqual(fmul_dst, fadd_src1)) {
// 检查中间寄存器是否在后续还会被使用
bool canOptimize = true;
for (size_t j = i + 2; j < instrs.size(); ++j) {
auto *later_instr = instrs[j].get();
// 如果中间寄存器被重新定义,则可以优化
if (isRegRedefinedAt(later_instr, fmul_dst, areRegsEqual)) {
break;
}
// 如果中间寄存器被使用,则不能优化
if (isRegUsedLater(instrs, fmul_dst, j)) {
canOptimize = false;
break;
}
}
if (canOptimize) {
// 创建新的FMADD_S指令: fmadd.s t4, t2, t3, t5
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::FMADD_S);
newInstr->addOperand(std::make_unique<RegOperand>(*fadd_dst));
newInstr->addOperand(std::make_unique<RegOperand>(*fmul_src1));
newInstr->addOperand(std::make_unique<RegOperand>(*fmul_src2));
newInstr->addOperand(std::make_unique<RegOperand>(*fadd_src2));
instrs[i + 1] = std::move(newInstr);
instrs.erase(instrs.begin() + i);
changed = true;
}
}
}
}
// 8.2 fmul.s t1, t2, t3; fadd.s t4, t5, t1 -> fmadd.s t4, t2, t3, t5
else if (isFusedMulAddEnabled() &&
mi1->getOpcode() == RVOpcodes::FMUL_S &&
mi2->getOpcode() == RVOpcodes::FADD_S) {
if (mi1->getOperands().size() == 3 && mi2->getOperands().size() == 3) {
auto *fmul_dst = static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *fmul_src1 = static_cast<RegOperand *>(mi1->getOperands()[1].get());
auto *fmul_src2 = static_cast<RegOperand *>(mi1->getOperands()[2].get());
auto *fadd_dst = static_cast<RegOperand *>(mi2->getOperands()[0].get());
auto *fadd_src1 = static_cast<RegOperand *>(mi2->getOperands()[1].get());
auto *fadd_src2 = static_cast<RegOperand *>(mi2->getOperands()[2].get());
// 检查fmul的目标是否是fadd的第二个源操作数
if (areRegsEqual(fmul_dst, fadd_src2)) {
// 检查中间寄存器是否在后续还会被使用
bool canOptimize = true;
for (size_t j = i + 2; j < instrs.size(); ++j) {
auto *later_instr = instrs[j].get();
// 如果中间寄存器被重新定义,则可以优化
if (isRegRedefinedAt(later_instr, fmul_dst, areRegsEqual)) {
break;
}
// 如果中间寄存器被使用,则不能优化
if (isRegUsedLater(instrs, fmul_dst, j)) {
canOptimize = false;
break;
}
}
if (canOptimize) {
// 创建新的FMADD_S指令: fmadd.s t4, t2, t3, t5
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::FMADD_S);
newInstr->addOperand(std::make_unique<RegOperand>(*fadd_dst));
newInstr->addOperand(std::make_unique<RegOperand>(*fmul_src1));
newInstr->addOperand(std::make_unique<RegOperand>(*fmul_src2));
newInstr->addOperand(std::make_unique<RegOperand>(*fadd_src1));
instrs[i + 1] = std::move(newInstr);
instrs.erase(instrs.begin() + i);
changed = true;
}
}
}
}
// 根据是否发生变化调整遍历索引
if (!changed) {

View File

@ -5,23 +5,6 @@
#include <iostream>
namespace sysy {
// 检查是否为内存加载/存储指令,以处理特殊的打印格式
bool isMemoryOp(RVOpcodes opcode) {
switch (opcode) {
// --- 整数加载/存储 (原有逻辑) ---
case RVOpcodes::LB: case RVOpcodes::LH: case RVOpcodes::LW: case RVOpcodes::LD:
case RVOpcodes::LBU: case RVOpcodes::LHU: case RVOpcodes::LWU:
case RVOpcodes::SB: case RVOpcodes::SH: case RVOpcodes::SW: case RVOpcodes::SD:
case RVOpcodes::FLW:
case RVOpcodes::FSW:
// 如果未来支持双精度也在这里添加FLD/FSD
// case RVOpcodes::FLD:
// case RVOpcodes::FSD:
return true;
default:
return false;
}
}
RISCv64AsmPrinter::RISCv64AsmPrinter(MachineFunction* mfunc) : MFunc(mfunc) {}
@ -82,7 +65,7 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
case RVOpcodes::SB: *OS << "sb "; break; case RVOpcodes::LD: *OS << "ld "; break;
case RVOpcodes::SD: *OS << "sd "; break; case RVOpcodes::FLW: *OS << "flw "; break;
case RVOpcodes::FSW: *OS << "fsw "; break; case RVOpcodes::FLD: *OS << "fld "; break;
case RVOpcodes::FSD: *OS << "fsd "; break;
case RVOpcodes::FSD: *OS << "fsd "; break;
case RVOpcodes::J: *OS << "j "; break; case RVOpcodes::JAL: *OS << "jal "; break;
case RVOpcodes::JALR: *OS << "jalr "; break; case RVOpcodes::RET: *OS << "ret"; break;
case RVOpcodes::BEQ: *OS << "beq "; break; case RVOpcodes::BNE: *OS << "bne "; break;
@ -96,15 +79,18 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
case RVOpcodes::FSUB_S: *OS << "fsub.s "; break;
case RVOpcodes::FMUL_S: *OS << "fmul.s "; break;
case RVOpcodes::FDIV_S: *OS << "fdiv.s "; break;
case RVOpcodes::FMADD_S: *OS << "fmadd.s "; break;
case RVOpcodes::FNEG_S: *OS << "fneg.s "; break;
case RVOpcodes::FEQ_S: *OS << "feq.s "; break;
case RVOpcodes::FLT_S: *OS << "flt.s "; break;
case RVOpcodes::FLE_S: *OS << "fle.s "; break;
case RVOpcodes::FCVT_S_W: *OS << "fcvt.s.w "; break;
case RVOpcodes::FCVT_W_S: *OS << "fcvt.w.s "; break;
case RVOpcodes::FCVT_W_S_RTZ: *OS << "fcvt.w.s "; break;
case RVOpcodes::FMV_S: *OS << "fmv.s "; break;
case RVOpcodes::FMV_W_X: *OS << "fmv.w.x "; break;
case RVOpcodes::FMV_X_W: *OS << "fmv.x.w "; break;
case RVOpcodes::FSRMI: *OS << "fsrmi "; break;
case RVOpcodes::CALL: { // 为CALL指令添加特殊处理逻辑
*OS << "call ";
// 遍历所有操作数,只寻找并打印函数名标签
@ -199,7 +185,7 @@ void RISCv64AsmPrinter::printOperand(MachineOperand* op) {
}
}
std::string RISCv64AsmPrinter::regToString(PhysicalReg reg) {
std::string RISCv64AsmPrinter::regToString(PhysicalReg reg) const {
switch (reg) {
case PhysicalReg::ZERO: return "x0"; case PhysicalReg::RA: return "ra";
case PhysicalReg::SP: return "sp"; case PhysicalReg::GP: return "gp";

View File

@ -1,10 +1,18 @@
#include "RISCv64Backend.h"
#include "RISCv64ISel.h"
#include "RISCv64RegAlloc.h"
#include "RISCv64LinearScan.h"
#include "RISCv64SimpleRegAlloc.h"
#include "RISCv64BasicBlockAlloc.h"
#include "RISCv64AsmPrinter.h"
#include "RISCv64Passes.h"
#include <sstream>
#include <future>
#include <chrono>
#include <atomic>
#include <memory>
#include <thread>
#include <iostream>
namespace sysy {
// 顶层入口
@ -193,29 +201,20 @@ std::string RISCv64CodeGen::module_gen() {
}
std::string RISCv64CodeGen::function_gen(Function* func) {
// === 完整的后端处理流水线 ===
// 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers)
DEBUG = 0;
DEEPDEBUG = 0;
RISCv64ISel isel;
std::unique_ptr<MachineFunction> mfunc = isel.runOnFunction(func);
// 第一次调试打印输出
std::stringstream ss_after_isel;
RISCv64AsmPrinter printer_isel(mfunc.get());
printer_isel.run(ss_after_isel, true);
if (DEBUG) {
std::cout << ss_after_isel.str();
}
// DEBUG = 1;
if (DEBUG) {
std::cerr << "====== Intermediate Representation after Instruction Selection ======\n"
<< ss_after_isel.str();
}
// DEBUG = 0;
// 阶段 2: 消除帧索引 (展开伪指令,计算局部变量偏移)
// 这个Pass必须在寄存器分配之前运行
EliminateFrameIndicesPass efi_pass;
efi_pass.runOnMachineFunction(mfunc.get());
@ -228,18 +227,106 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
<< ss_after_eli.str();
}
// 阶段 2: 除法强度削弱优化 (Division Strength Reduction)
// 阶段 2.1: 除法强度削弱优化 (Division Strength Reduction)
DivStrengthReduction div_strength_reduction;
div_strength_reduction.runOnMachineFunction(mfunc.get());
// 阶段 2.1: 指令调度 (Instruction Scheduling)
PreRA_Scheduler scheduler;
scheduler.runOnMachineFunction(mfunc.get());
// // 阶段 2.2: 指令调度 (Instruction Scheduling)
// PreRA_Scheduler scheduler;
// scheduler.runOnMachineFunction(mfunc.get());
// 阶段 3: 物理寄存器分配 (Register Allocation)
RISCv64RegAlloc reg_alloc(mfunc.get());
reg_alloc.run();
bool allocation_succeeded = false;
// 尝试迭代图着色 (IRC)
if (!irc_failed) {
if (DEBUG) std::cerr << "Attempting Register Allocation with Iterated Register Coloring (IRC)...\n";
RISCv64RegAlloc irc_alloc(mfunc.get());
auto stop_flag = std::make_shared<std::atomic<bool>>(false);
auto future = std::async(std::launch::async, &RISCv64RegAlloc::run, &irc_alloc, stop_flag);
std::future_status status = future.wait_for(std::chrono::seconds(25));
bool success_irc = false;
if (status == std::future_status::ready) {
try {
if (future.get()) {
success_irc = true;
} else {
std::cerr << "Warning: IRC explicitly returned failure for function '" << func->getName() << "'.\n";
}
} catch (const std::exception& e) {
std::cerr << "Error: IRC allocation threw an exception: " << e.what() << std::endl;
}
} else if (status == std::future_status::timeout) {
std::cerr << "Warning: IRC allocation timed out after 25 seconds. Requesting cancellation...\n";
stop_flag->store(true);
try {
future.get();
} catch (const std::exception& e) {
std::cerr << "Exception occurred during IRC thread shutdown after timeout: " << e.what() << std::endl;
}
}
if (success_irc) {
allocation_succeeded = true;
if (DEBUG) std::cerr << "IRC allocation succeeded.\n";
} else {
std::cerr << "Info: Blacklisting IRC for subsequent functions and falling back.\n";
irc_failed = true;
}
}
// 尝试简单图着色 (SGC)
if (!allocation_succeeded) {
// 如果是从IRC失败回退过来的需要重新创建干净的mfunc和ISel
RISCv64ISel isel_for_sgc;
if (irc_failed) {
if (DEBUG) std::cerr << "Info: Resetting MachineFunction for SGC attempt.\n";
mfunc = isel_for_sgc.runOnFunction(func);
EliminateFrameIndicesPass efi_pass_for_sgc;
efi_pass_for_sgc.runOnMachineFunction(mfunc.get());
}
if (DEBUG) std::cerr << "Attempting Register Allocation with Simple Graph Coloring (SGC)...\n";
bool sgc_completed_in_time = false;
{
RISCv64SimpleRegAlloc sgc_alloc(mfunc.get());
auto future = std::async(std::launch::async, &RISCv64SimpleRegAlloc::run, &sgc_alloc);
std::future_status status = future.wait_for(std::chrono::seconds(25));
if (status == std::future_status::ready) {
try {
future.get(); // 检查是否有异常
sgc_completed_in_time = true;
if (DEBUG) std::cerr << "SGC allocation completed successfully within the time limit.\n";
} catch (const std::exception& e) {
std::cerr << "Error: SGC allocation threw an exception: " << e.what() << std::endl;
}
}
}
if (sgc_completed_in_time) {
allocation_succeeded = true;
} else {
std::cerr << "Warning: SGC allocation timed out or failed for function '" << func->getName()
<< "'. Falling back.\n";
}
}
// 如果都失败了,则使用基本块分配器 (BBA)
if (!allocation_succeeded) {
// 为BBA准备干净的mfunc和ISel
std::cerr << "Info: Resetting MachineFunction for BBA fallback.\n";
RISCv64ISel isel_for_bba;
mfunc = isel_for_bba.runOnFunction(func);
EliminateFrameIndicesPass efi_pass_for_bba;
efi_pass_for_bba.runOnMachineFunction(mfunc.get());
std::cerr << "Info: Using Basic Block Allocator as final fallback.\n";
RISCv64BasicBlockAlloc bb_alloc(mfunc.get());
bb_alloc.run();
}
if (DEBUG) {
std::cerr << "====== stack info after reg alloc ======\n";
mfunc->dumpStackFrameInfo(std::cerr);
@ -258,9 +345,9 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
PeepholeOptimizer peephole;
peephole.runOnMachineFunction(mfunc.get());
// 阶段 5: 局部指令调度 (Local Scheduling)
PostRA_Scheduler local_scheduler;
local_scheduler.runOnMachineFunction(mfunc.get());
// // 阶段 5: 局部指令调度 (Local Scheduling)
// PostRA_Scheduler local_scheduler;
// local_scheduler.runOnMachineFunction(mfunc.get());
// 阶段 3.2: 插入序言和尾声
PrologueEpilogueInsertionPass pei_pass;
@ -276,7 +363,6 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
printer.run(ss);
return ss.str();
}
} // namespace sysy

View File

@ -0,0 +1,267 @@
#include "RISCv64BasicBlockAlloc.h"
#include "RISCv64Info.h"
#include "RISCv64AsmPrinter.h"
#include <iostream>
#include <algorithm>
// 外部调试级别控制变量
extern int DEBUG;
extern int DEEPDEBUG;
namespace sysy {
// 将 getInstrUseDef 的定义移到这里,因为它是一个全局的辅助函数
void getInstrUseDef(const MachineInstr* instr, std::set<unsigned>& use, std::set<unsigned>& def) {
auto opcode = instr->getOpcode();
const auto& operands = instr->getOperands();
auto get_vreg_id_if_virtual = [&](const MachineOperand* op, std::set<unsigned>& s) {
if (op->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<const RegOperand*>(op);
if (reg_op->isVirtual()) s.insert(reg_op->getVRegNum());
} else if (op->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<const MemOperand*>(op);
auto reg_op = mem_op->getBase();
if (reg_op->isVirtual()) s.insert(reg_op->getVRegNum());
}
};
if (op_info.count(opcode)) {
const auto& info = op_info.at(opcode);
for (int idx : info.first) if (idx < operands.size()) get_vreg_id_if_virtual(operands[idx].get(), def);
for (int idx : info.second) if (idx < operands.size()) get_vreg_id_if_virtual(operands[idx].get(), use);
// 内存操作数的基址寄存器总是use
for (const auto& op : operands) if (op->getKind() == MachineOperand::KIND_MEM) get_vreg_id_if_virtual(op.get(), use);
} else if (opcode == RVOpcodes::CALL) {
if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) get_vreg_id_if_virtual(operands[0].get(), def);
for (size_t i = 1; i < operands.size(); ++i) if (operands[i]->getKind() == MachineOperand::KIND_REG) get_vreg_id_if_virtual(operands[i].get(), use);
}
}
RISCv64BasicBlockAlloc::RISCv64BasicBlockAlloc(MachineFunction* mfunc)
: MFunc(mfunc), ISel(mfunc->getISel()) {
// 初始化临时寄存器池
int_temps = {PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3, PhysicalReg::T6};
fp_temps = {PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3, PhysicalReg::F4};
int_temp_idx = 0;
fp_temp_idx = 0;
// 构建ABI寄存器映射
if (MFunc->getFunc()) {
int int_arg_idx = 0;
int fp_arg_idx = 0;
for (Argument* arg : MFunc->getFunc()->getArguments()) {
unsigned arg_vreg = ISel->getVReg(arg);
if (arg->getType()->isFloat()) {
if (fp_arg_idx < 8) {
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + fp_arg_idx++);
abi_vreg_map[arg_vreg] = preg;
}
} else {
if (int_arg_idx < 8) {
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_arg_idx++);
abi_vreg_map[arg_vreg] = preg;
}
}
}
}
}
void RISCv64BasicBlockAlloc::run() {
if (DEBUG) std::cerr << "===== [BB-Alloc] Running Stateful Greedy Allocator for function: " << MFunc->getName() << " =====\n";
computeLiveness();
assignStackSlotsForAllVRegs();
for (auto& mbb : MFunc->getBlocks()) {
processBasicBlock(mbb.get());
}
// 将ABI寄存器映射如函数参数合并到最终结果中
MFunc->getFrameInfo().vreg_to_preg_map.insert(this->abi_vreg_map.begin(), this->abi_vreg_map.end());
}
PhysicalReg RISCv64BasicBlockAlloc::getNextIntTemp() {
PhysicalReg reg = int_temps[int_temp_idx];
int_temp_idx = (int_temp_idx + 1) % int_temps.size();
return reg;
}
PhysicalReg RISCv64BasicBlockAlloc::getNextFpTemp() {
PhysicalReg reg = fp_temps[fp_temp_idx];
fp_temp_idx = (fp_temp_idx + 1) % fp_temps.size();
return reg;
}
void RISCv64BasicBlockAlloc::computeLiveness() {
// 这是一个必需的步骤,用于确定在块末尾哪些变量需要被写回栈
// 为保持聚焦,此处暂时留空,但请确保您有一个有效的活性分析来填充 live_out 映射
}
void RISCv64BasicBlockAlloc::assignStackSlotsForAllVRegs() {
if (DEBUG) std::cerr << "[BB-Alloc] Assigning stack slots for all vregs.\n";
StackFrameInfo& frame_info = MFunc->getFrameInfo();
int current_offset = frame_info.locals_end_offset;
const auto& vreg_type_map = ISel->getVRegTypeMap();
for (unsigned vreg = 1; vreg < ISel->getVRegCounter(); ++vreg) {
if (this->abi_vreg_map.count(vreg) || frame_info.alloca_offsets.count(vreg) || frame_info.spill_offsets.count(vreg)) {
continue;
}
Type* type = vreg_type_map.count(vreg) ? vreg_type_map.at(vreg) : Type::getIntType();
int size = type->isPointer() ? 8 : 4;
current_offset -= size;
current_offset &= -size; // 按size对齐
frame_info.spill_offsets[vreg] = current_offset;
}
frame_info.spill_size = -(current_offset - frame_info.locals_end_offset);
}
void RISCv64BasicBlockAlloc::processBasicBlock(MachineBasicBlock* mbb) {
if (DEEPDEBUG) std::cerr << " [BB-Alloc] Processing block " << mbb->getName() << "\n";
vreg_to_preg.clear();
preg_to_vreg.clear();
dirty_pregs.clear();
auto& instrs = mbb->getInstructions();
std::vector<std::unique_ptr<MachineInstr>> new_instrs;
const auto& vreg_type_map = ISel->getVRegTypeMap();
for (auto& instr_ptr : instrs) {
std::set<unsigned> use_vregs, def_vregs;
getInstrUseDef(instr_ptr.get(), use_vregs, def_vregs);
std::map<unsigned, PhysicalReg> current_instr_map;
// 1. 确保所有use操作数都在物理寄存器中
for (unsigned vreg : use_vregs) {
current_instr_map[vreg] = ensureInReg(vreg, new_instrs);
}
// 2. 为所有def操作数分配物理寄存器
for (unsigned vreg : def_vregs) {
current_instr_map[vreg] = allocReg(vreg, new_instrs);
}
// 3. 重写指令将vreg替换为preg
for (const auto& pair : current_instr_map) {
instr_ptr->replaceVRegWithPReg(pair.first, pair.second);
}
new_instrs.push_back(std::move(instr_ptr));
}
// 4. 在块末尾,写回所有被修改过的且在后续块中活跃(live-out)的vreg
StackFrameInfo& frame_info = MFunc->getFrameInfo(); // **修正获取frame_info引用**
const auto& lo = live_out[mbb];
for(auto const& [preg, vreg] : preg_to_vreg) {
// **修正:简化逻辑,在此保底分配器中总是写回脏寄存器**
if (dirty_pregs.count(preg)) {
if (!frame_info.spill_offsets.count(vreg)) continue;
Type* type = vreg_type_map.at(vreg);
RVOpcodes store_op = type->isFloat() ? RVOpcodes::FSW : (type->isPointer() ? RVOpcodes::SD : RVOpcodes::SW);
auto store = std::make_unique<MachineInstr>(store_op);
store->addOperand(std::make_unique<RegOperand>(preg));
store->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(vreg))
));
new_instrs.push_back(std::move(store));
}
}
instrs = std::move(new_instrs);
}
PhysicalReg RISCv64BasicBlockAlloc::ensureInReg(unsigned vreg, std::vector<std::unique_ptr<MachineInstr>>& new_instrs) {
if (abi_vreg_map.count(vreg)) {
return abi_vreg_map.at(vreg);
}
if (vreg_to_preg.count(vreg)) {
return vreg_to_preg.at(vreg);
}
PhysicalReg preg = allocReg(vreg, new_instrs);
const auto& vreg_type_map = ISel->getVRegTypeMap();
Type* type = vreg_type_map.count(vreg) ? vreg_type_map.at(vreg) : Type::getIntType();
RVOpcodes load_op = type->isFloat() ? RVOpcodes::FLW : (type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW);
auto load = std::make_unique<MachineInstr>(load_op);
load->addOperand(std::make_unique<RegOperand>(preg));
load->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(MFunc->getFrameInfo().spill_offsets.at(vreg))
));
new_instrs.push_back(std::move(load));
dirty_pregs.erase(preg);
return preg;
}
PhysicalReg RISCv64BasicBlockAlloc::allocReg(unsigned vreg, std::vector<std::unique_ptr<MachineInstr>>& new_instrs) {
if (abi_vreg_map.count(vreg)) {
dirty_pregs.insert(abi_vreg_map.at(vreg)); // 如果参数被重定义,也标记为脏
return abi_vreg_map.at(vreg);
}
bool is_fp = ISel->getVRegTypeMap().at(vreg)->isFloat();
PhysicalReg preg = findFreeReg(is_fp);
if (preg == PhysicalReg::INVALID) {
preg = spillReg(is_fp, new_instrs);
}
if (preg_to_vreg.count(preg)) {
vreg_to_preg.erase(preg_to_vreg.at(preg));
}
vreg_to_preg[vreg] = preg;
preg_to_vreg[preg] = vreg;
dirty_pregs.insert(preg);
return preg;
}
PhysicalReg RISCv64BasicBlockAlloc::findFreeReg(bool is_fp) {
// **修正:使用正确的成员变量名 int_temps 和 fp_temps**
const auto& regs = is_fp ? fp_temps : int_temps;
for (PhysicalReg preg : regs) {
if (!preg_to_vreg.count(preg)) {
return preg;
}
}
return PhysicalReg::INVALID;
}
PhysicalReg RISCv64BasicBlockAlloc::spillReg(bool is_fp, std::vector<std::unique_ptr<MachineInstr>>& new_instrs) {
// **修正**: 调用成员函数需要使用 this->
PhysicalReg preg_to_spill = is_fp ? this->getNextFpTemp() : this->getNextIntTemp();
if (preg_to_vreg.count(preg_to_spill)) {
unsigned victim_vreg = preg_to_vreg.at(preg_to_spill);
if (dirty_pregs.count(preg_to_spill)) {
const auto& vreg_type_map = ISel->getVRegTypeMap();
Type* type = vreg_type_map.count(victim_vreg) ? vreg_type_map.at(victim_vreg) : Type::getIntType();
RVOpcodes store_op = type->isFloat() ? RVOpcodes::FSW : (type->isPointer() ? RVOpcodes::SD : RVOpcodes::SW);
auto store = std::make_unique<MachineInstr>(store_op);
store->addOperand(std::make_unique<RegOperand>(preg_to_spill));
store->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(MFunc->getFrameInfo().spill_offsets.at(victim_vreg))
));
new_instrs.push_back(std::move(store));
}
vreg_to_preg.erase(victim_vreg);
dirty_pregs.erase(preg_to_spill);
}
preg_to_vreg.erase(preg_to_spill);
return preg_to_spill;
}
} // namespace sysy

View File

@ -103,6 +103,60 @@ void RISCv64ISel::select() {
}
}
if (optLevel > 0) {
if (F && !F->getBasicBlocks().empty()) {
// 定位到第一个MachineBasicBlock也就是函数入口
BasicBlock* first_ir_block = F->getBasicBlocks_NoRange().front().get();
CurMBB = bb_map.at(first_ir_block);
int int_arg_idx = 0;
int fp_arg_idx = 0;
for (Argument* arg : F->getArguments()) {
Type* arg_type = arg->getType();
// --- 处理整数/指针参数 ---
if (!arg_type->isFloat() && int_arg_idx < 8) {
// 1. 获取参数原始的、将被预着色为 a0-a7 的 vreg
unsigned original_vreg = getVReg(arg);
// 2. 创建一个新的、安全的 vreg 来持有参数的值
unsigned saved_vreg = getNewVReg(arg_type);
// 3. 生成 mv saved_vreg, original_vreg 指令
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
mv->addOperand(std::make_unique<RegOperand>(saved_vreg));
mv->addOperand(std::make_unique<RegOperand>(original_vreg));
CurMBB->addInstruction(std::move(mv));
// 4.【关键】更新vreg映射表将arg的vreg指向新的、安全的vreg
// 这样,后续所有对该参数的 getVReg(arg) 调用都会自动获得 saved_vreg
// 使得函数体内的代码都使用这个被保存过的值。
vreg_map[arg] = saved_vreg;
int_arg_idx++;
}
// --- 处理浮点参数 ---
else if (arg_type->isFloat() && fp_arg_idx < 8) {
unsigned original_vreg = getVReg(arg);
unsigned saved_vreg = getNewVReg(arg_type);
// 对于浮点数,使用 fmv.s 指令
auto fmv = std::make_unique<MachineInstr>(RVOpcodes::FMV_S);
fmv->addOperand(std::make_unique<RegOperand>(saved_vreg));
fmv->addOperand(std::make_unique<RegOperand>(original_vreg));
CurMBB->addInstruction(std::move(fmv));
// 同样更新映射
vreg_map[arg] = saved_vreg;
fp_arg_idx++;
}
// 对于栈传递的参数,则无需处理
}
}
}
// 遍历基本块,进行指令选择
for (const auto& bb_ptr : F->getBasicBlocks()) {
selectBasicBlock(bb_ptr.get());
@ -526,6 +580,22 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(instr));
break;
}
case BinaryInst::kSll: { // 逻辑左移
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SLLW);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
case BinaryInst::kSrl: { // 逻辑右移
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SRLW);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
case BinaryInst::kICmpEQ: { // 等于 (a == b) -> (subw; seqz)
auto sub = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
sub->addOperand(std::make_unique<RegOperand>(dest_vreg));
@ -582,7 +652,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(xori));
break;
}
case BinaryInst::kICmpGE: { // 大于等于 (a >= b) -> !(a < b) -> (slt; xori)
case BinaryInst::kICmpGE: { // 大于等于 (a >= b) -> !(a < b) -> (slt; xori)
auto slt = std::make_unique<MachineInstr>(RVOpcodes::SLT);
slt->addOperand(std::make_unique<RegOperand>(dest_vreg));
slt->addOperand(std::make_unique<RegOperand>(lhs_vreg));
@ -745,83 +815,29 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(instr));
break;
}
case Instruction::kFtoI: { // 浮点 to 整数 (带向下取整)
// 目标:实现 floor(x) 的效果, C/C++中浮点转整数是截断(truncate)
// 对于正数floor(x) == truncate(x)
// RISC-V的 fcvt.w.s 默认是“四舍五入到偶数”
// 我们需要手动实现截断逻辑
// 逻辑:
// temp_i = fcvt.w.s(x) // 四舍五入
// temp_f = fcvt.s.w(temp_i) // 转回浮点
// if (x < temp_f) { // 如果原数更小,说明被“五入”了
// result = temp_i - 1
// } else {
// result = temp_i
// }
auto temp_i_vreg = getNewVReg(Type::getIntType());
auto temp_f_vreg = getNewVReg(Type::getFloatType());
auto cmp_vreg = getNewVReg(Type::getIntType());
case Instruction::kFtoI: { // 浮点 to 整数 (C/C++: 截断)
// C/C++ 标准要求向零截断 (truncate), 对应的RISC-V舍入模式是 RTZ (Round Towards Zero).
// fcvt.w.s 指令使用 fcsr 中的 frm 字段来决定舍入模式。
// 我们需要手动设置 frm=1 (RTZ), 执行转换, 然后恢复 frm=0 (RNE, 默认).
// 1. fcvt.w.s temp_i_vreg, src_vreg
auto fcvt_w = std::make_unique<MachineInstr>(RVOpcodes::FCVT_W_S);
fcvt_w->addOperand(std::make_unique<RegOperand>(temp_i_vreg));
fcvt_w->addOperand(std::make_unique<RegOperand>(src_vreg));
CurMBB->addInstruction(std::move(fcvt_w));
// 1. fsrmi x0, 1 (set rounding mode to RTZ)
auto fsrmi1 = std::make_unique<MachineInstr>(RVOpcodes::FSRMI);
fsrmi1->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
fsrmi1->addOperand(std::make_unique<ImmOperand>(1));
CurMBB->addInstruction(std::move(fsrmi1));
// 2. fcvt.s.w temp_f_vreg, temp_i_vreg
auto fcvt_s = std::make_unique<MachineInstr>(RVOpcodes::FCVT_S_W);
fcvt_s->addOperand(std::make_unique<RegOperand>(temp_f_vreg));
fcvt_s->addOperand(std::make_unique<RegOperand>(temp_i_vreg));
CurMBB->addInstruction(std::move(fcvt_s));
// 2. fcvt.w.s dest_vreg, src_vreg
auto fcvt = std::make_unique<MachineInstr>(RVOpcodes::FCVT_W_S);
fcvt->addOperand(std::make_unique<RegOperand>(dest_vreg));
fcvt->addOperand(std::make_unique<RegOperand>(src_vreg));
CurMBB->addInstruction(std::move(fcvt));
// 3. flt.s cmp_vreg, src_vreg, temp_f_vreg
auto flt = std::make_unique<MachineInstr>(RVOpcodes::FLT_S);
flt->addOperand(std::make_unique<RegOperand>(cmp_vreg));
flt->addOperand(std::make_unique<RegOperand>(src_vreg));
flt->addOperand(std::make_unique<RegOperand>(temp_f_vreg));
CurMBB->addInstruction(std::move(flt));
// 3. fsrmi x0, 0 (restore rounding mode to RNE)
auto fsrmi0 = std::make_unique<MachineInstr>(RVOpcodes::FSRMI);
fsrmi0->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
fsrmi0->addOperand(std::make_unique<ImmOperand>(0));
CurMBB->addInstruction(std::move(fsrmi0));
// 创建标签
int unique_id = this->local_label_counter++;
std::string rounded_up_label = MFunc->getName() + "_ftoi_rounded_up_" + std::to_string(unique_id);
std::string done_label = MFunc->getName() + "_ftoi_done_" + std::to_string(unique_id);
// 4. bne cmp_vreg, x0, rounded_up_label
auto bne = std::make_unique<MachineInstr>(RVOpcodes::BNE);
bne->addOperand(std::make_unique<RegOperand>(cmp_vreg));
bne->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
bne->addOperand(std::make_unique<LabelOperand>(rounded_up_label));
CurMBB->addInstruction(std::move(bne));
// 5. else 分支: mv dest_vreg, temp_i_vreg
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
mv->addOperand(std::make_unique<RegOperand>(dest_vreg));
mv->addOperand(std::make_unique<RegOperand>(temp_i_vreg));
CurMBB->addInstruction(std::move(mv));
// 6. j done_label
auto j = std::make_unique<MachineInstr>(RVOpcodes::J);
j->addOperand(std::make_unique<LabelOperand>(done_label));
CurMBB->addInstruction(std::move(j));
// 7. rounded_up_label:
auto label_up = std::make_unique<MachineInstr>(RVOpcodes::LABEL);
label_up->addOperand(std::make_unique<LabelOperand>(rounded_up_label));
CurMBB->addInstruction(std::move(label_up));
// 8. addiw dest_vreg, temp_i_vreg, -1
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDIW);
addi->addOperand(std::make_unique<RegOperand>(dest_vreg));
addi->addOperand(std::make_unique<RegOperand>(temp_i_vreg));
addi->addOperand(std::make_unique<ImmOperand>(-1));
CurMBB->addInstruction(std::move(addi));
// 9. done_label:
auto label_done = std::make_unique<MachineInstr>(RVOpcodes::LABEL);
label_done->addOperand(std::make_unique<LabelOperand>(done_label));
CurMBB->addInstruction(std::move(label_done));
break;
}
case Instruction::kFNeg: { // 浮点取负
@ -1202,10 +1218,11 @@ void RISCv64ISel::selectNode(DAGNode* node) {
auto r_value_byte = getVReg(memset->getValue());
// 为memset内部逻辑创建新的临时虚拟寄存器
auto r_counter = getNewVReg();
auto r_end_addr = getNewVReg();
auto r_current_addr = getNewVReg();
auto r_temp_val = getNewVReg();
Type* ptr_type = Type::getPointerType(Type::getIntType());
auto r_counter = getNewVReg(ptr_type);
auto r_end_addr = getNewVReg(ptr_type);
auto r_current_addr = getNewVReg(ptr_type);
auto r_temp_val = getNewVReg(Type::getIntType());
// 定义一系列lambda表达式来简化指令创建
auto add_instr = [&](RVOpcodes op, unsigned rd, unsigned rs1, unsigned rs2) {
@ -1296,7 +1313,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
// --- Step 1: 获取基地址 (此部分逻辑正确,保持不变) ---
auto base_ptr_node = node->operands[0];
auto current_addr_vreg = getNewVReg();
auto current_addr_vreg = getNewVReg(gep->getType());
if (auto alloca_base = dynamic_cast<AllocaInst*>(base_ptr_node->value)) {
auto frame_addr_instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_ADDR);
@ -1338,13 +1355,13 @@ void RISCv64ISel::selectNode(DAGNode* node) {
// 如果步长为0例如对一个void类型或空结构体索引则不产生任何偏移
if (stride != 0) {
// --- 为当前索引和步长生成偏移计算指令 ---
auto offset_vreg = getNewVReg();
auto offset_vreg = getNewVReg(Type::getIntType());
// 处理索引 - 区分常量与动态值
unsigned index_vreg;
if (auto const_index = dynamic_cast<ConstantValue*>(indexValue)) {
// 对于常量索引,直接创建新的虚拟寄存器
index_vreg = getNewVReg();
index_vreg = getNewVReg(Type::getIntType());
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(index_vreg));
li->addOperand(std::make_unique<ImmOperand>(const_index->getInt()));
@ -1362,7 +1379,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(mv));
} else {
// 步长不为1需要生成乘法指令
auto size_vreg = getNewVReg();
auto size_vreg = getNewVReg(Type::getIntType());
auto li_size = std::make_unique<MachineInstr>(RVOpcodes::LI);
li_size->addOperand(std::make_unique<RegOperand>(size_vreg));
li_size->addOperand(std::make_unique<ImmOperand>(stride));

View File

@ -1,4 +1,5 @@
#include "RISCv64LLIR.h"
#include "RISCv64Info.h"
#include <vector>
#include <iostream> // 用于 std::ostream 和 std::cerr
#include <string> // 用于 std::string
@ -119,4 +120,76 @@ void MachineFunction::dumpStackFrameInfo(std::ostream& os) const {
os << "---------------------------------------------------\n";
}
/**
* @brief (为紧急溢出模式添加)将指令中所有对特定虚拟寄存器的引用替换为指定的物理寄存器。
*/
void MachineInstr::replaceVRegWithPReg(unsigned old_vreg, PhysicalReg preg) {
for (auto& op : operands) {
if (op->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(op.get());
if (reg_op->isVirtual() && reg_op->getVRegNum() == old_vreg) {
// 将虚拟寄存器操作数直接转换为物理寄存器操作数
reg_op->setPReg(preg);
}
} else if (op->getKind() == MachineOperand::KIND_MEM) {
// 同时处理内存操作数中的基址寄存器
auto mem_op = static_cast<MemOperand*>(op.get());
auto base_reg = mem_op->getBase();
if (base_reg->isVirtual() && base_reg->getVRegNum() == old_vreg) {
base_reg->setPReg(preg);
}
}
}
}
/**
* @brief (为常规溢出模式添加)根据提供的映射表,重映射指令中的虚拟寄存器。
* 这个函数的逻辑与 RISCv64LinearScan::getInstrUseDef 非常相似,因为它也需要
* 知道哪个操作数是 use哪个是 def。
*/
void MachineInstr::remapVRegs(const std::map<unsigned, unsigned>& use_remap, const std::map<unsigned, unsigned>& def_remap) {
auto opcode = getOpcode();
// 辅助lambda用于替换寄存器操作数
auto remap_reg_op = [](RegOperand* reg_op, const std::map<unsigned, unsigned>& remap) {
if (reg_op->isVirtual() && remap.count(reg_op->getVRegNum())) {
reg_op->setVRegNum(remap.at(reg_op->getVRegNum()));
}
};
// 根据指令信息表op_info来确定 use 和 def
if (op_info.count(opcode)) {
const auto& info = op_info.at(opcode);
// 替换 def 操作数
for (int idx : info.first) {
if (idx < operands.size() && operands[idx]->getKind() == MachineOperand::KIND_REG) {
remap_reg_op(static_cast<RegOperand*>(operands[idx].get()), def_remap);
}
}
// 替换 use 操作数
for (int idx : info.second) {
if (idx < operands.size()) {
if (operands[idx]->getKind() == MachineOperand::KIND_REG) {
remap_reg_op(static_cast<RegOperand*>(operands[idx].get()), use_remap);
} else if (operands[idx]->getKind() == MachineOperand::KIND_MEM) {
// 内存操作数的基址寄存器总是 use
remap_reg_op(static_cast<MemOperand*>(operands[idx].get())->getBase(), use_remap);
}
}
}
} else if (opcode == RVOpcodes::CALL) {
// 处理 CALL 指令的特殊情况
// 第一个操作数(如果存在且是寄存器)是 def
if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) {
remap_reg_op(static_cast<RegOperand*>(operands[0].get()), def_remap);
}
// 其余寄存器操作数是 use
for (size_t i = 1; i < operands.size(); ++i) {
if (operands[i]->getKind() == MachineOperand::KIND_REG) {
remap_reg_op(static_cast<RegOperand*>(operands[i].get()), use_remap);
}
}
}
}
}

View File

@ -0,0 +1,694 @@
#include "RISCv64LinearScan.h"
#include "RISCv64LLIR.h"
#include "RISCv64ISel.h"
#include "RISCv64Info.h"
#include "RISCv64AsmPrinter.h"
#include <iostream>
#include <algorithm>
#include <set>
#include <sstream>
#include <functional>
// 外部调试级别控制变量
extern int DEBUG;
extern int DEEPDEBUG;
extern int DEEPERDEBUG;
namespace sysy {
// --- 调试辅助函数 ---
// These helpers are self-contained and only used for logging.
static std::string pregToString(PhysicalReg preg) {
// This map is a copy from AsmPrinter to avoid dependency issues.
static const std::map<PhysicalReg, std::string> preg_names = {
{PhysicalReg::ZERO, "zero"}, {PhysicalReg::RA, "ra"}, {PhysicalReg::SP, "sp"}, {PhysicalReg::GP, "gp"}, {PhysicalReg::TP, "tp"},
{PhysicalReg::T0, "t0"}, {PhysicalReg::T1, "t1"}, {PhysicalReg::T2, "t2"}, {PhysicalReg::T3, "t3"}, {PhysicalReg::T4, "t4"}, {PhysicalReg::T5, "t5"}, {PhysicalReg::T6, "t6"},
{PhysicalReg::S0, "s0"}, {PhysicalReg::S1, "s1"}, {PhysicalReg::S2, "s2"}, {PhysicalReg::S3, "s3"}, {PhysicalReg::S4, "s4"}, {PhysicalReg::S5, "s5"}, {PhysicalReg::S6, "s6"}, {PhysicalReg::S7, "s7"}, {PhysicalReg::S8, "s8"}, {PhysicalReg::S9, "s9"}, {PhysicalReg::S10, "s10"}, {PhysicalReg::S11, "s11"},
{PhysicalReg::A0, "a0"}, {PhysicalReg::A1, "a1"}, {PhysicalReg::A2, "a2"}, {PhysicalReg::A3, "a3"}, {PhysicalReg::A4, "a4"}, {PhysicalReg::A5, "a5"}, {PhysicalReg::A6, "a6"}, {PhysicalReg::A7, "a7"},
{PhysicalReg::F0, "f0"}, {PhysicalReg::F1, "f1"}, {PhysicalReg::F2, "f2"}, {PhysicalReg::F3, "f3"}, {PhysicalReg::F4, "f4"}, {PhysicalReg::F5, "f5"}, {PhysicalReg::F6, "f6"}, {PhysicalReg::F7, "f7"},
{PhysicalReg::F8, "f8"}, {PhysicalReg::F9, "f9"}, {PhysicalReg::F10, "f10"}, {PhysicalReg::F11, "f11"}, {PhysicalReg::F12, "f12"}, {PhysicalReg::F13, "f13"}, {PhysicalReg::F14, "f14"}, {PhysicalReg::F15, "f15"},
{PhysicalReg::F16, "f16"}, {PhysicalReg::F17, "f17"}, {PhysicalReg::F18, "f18"}, {PhysicalReg::F19, "f19"}, {PhysicalReg::F20, "f20"}, {PhysicalReg::F21, "f21"}, {PhysicalReg::F22, "f22"}, {PhysicalReg::F23, "f23"},
{PhysicalReg::F24, "f24"}, {PhysicalReg::F25, "f25"}, {PhysicalReg::F26, "f26"}, {PhysicalReg::F27, "f27"}, {PhysicalReg::F28, "f28"}, {PhysicalReg::F29, "f29"}, {PhysicalReg::F30, "f30"}, {PhysicalReg::F31, "f31"},
{PhysicalReg::INVALID, "INVALID"}
};
if (preg_names.count(preg)) return preg_names.at(preg);
return "UnknownPreg";
}
template<typename T>
static std::string setToString(const std::set<T>& s, std::function<std::string(T)> formatter) {
std::stringstream ss;
ss << "{ ";
bool first = true;
for (const auto& item : s) {
if (!first) ss << ", ";
ss << formatter(item);
first = false;
}
ss << " }";
return ss.str();
}
static std::string vregSetToString(const std::set<unsigned>& s) {
return setToString<unsigned>(s, [](unsigned v){ return "%v" + std::to_string(v); });
}
static std::string pregSetToString(const std::set<PhysicalReg>& s) {
return setToString<PhysicalReg>(s, pregToString);
}
// Helper function to check if a register is callee-saved.
// Defined locally to avoid scope issues.
static bool isCalleeSaved(PhysicalReg preg) {
if (preg >= PhysicalReg::S0 && preg <= PhysicalReg::S11) return true;
if (preg >= PhysicalReg::F8 && preg <= PhysicalReg::F9) return true;
if (preg >= PhysicalReg::F18 && preg <= PhysicalReg::F27) return true;
return false;
}
RISCv64LinearScan::RISCv64LinearScan(MachineFunction* mfunc)
: MFunc(mfunc),
ISel(mfunc->getISel()),
vreg_type_map(ISel->getVRegTypeMap()) {
allocable_int_regs = {
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3, PhysicalReg::T6,
PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3, PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
};
allocable_fp_regs = {
PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3, PhysicalReg::F4, PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7,
PhysicalReg::F10, PhysicalReg::F11, PhysicalReg::F12, PhysicalReg::F13, PhysicalReg::F14, PhysicalReg::F15, PhysicalReg::F16, PhysicalReg::F17,
PhysicalReg::F8, PhysicalReg::F9, PhysicalReg::F18, PhysicalReg::F19, PhysicalReg::F20, PhysicalReg::F21, PhysicalReg::F22,
PhysicalReg::F23, PhysicalReg::F24, PhysicalReg::F25, PhysicalReg::F26, PhysicalReg::F27,
PhysicalReg::F28, PhysicalReg::F29, PhysicalReg::F30, PhysicalReg::F31,
};
if (MFunc->getFunc()) {
int int_arg_idx = 0;
int fp_arg_idx = 0;
for (Argument* arg : MFunc->getFunc()->getArguments()) {
unsigned arg_vreg = ISel->getVReg(arg);
if (arg->getType()->isFloat()) {
if (fp_arg_idx < 8) {
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + fp_arg_idx++);
abi_vreg_map[arg_vreg] = preg;
}
} else {
if (int_arg_idx < 8) {
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_arg_idx++);
abi_vreg_map[arg_vreg] = preg;
}
}
}
}
}
bool RISCv64LinearScan::run() {
if (DEBUG) std::cerr << "===== [LSRA] Running for function: " << MFunc->getName() << " =====\n";
const int MAX_ITERATIONS = 3;
for (int iteration = 1; ; ++iteration) {
if (DEBUG && iteration > 1) {
std::cerr << "\n----- [LSRA] Re-running iteration " << iteration << " -----\n";
}
linearizeBlocks();
computeLiveIntervals();
bool needs_spill = linearScan();
// 如果当前这轮线性扫描不需要溢出,说明分配成功,直接跳出循环。
if (!needs_spill) {
break;
}
// --- 检查是否需要启动或已经失败于保底策略 ---
if (iteration > MAX_ITERATIONS) {
// 如果我们已经在保底模式下运行过,但这一轮 linearScan 仍然返回 true
// 这说明发生了无法解决的错误,此时才真正失败。
if (conservative_spill_mode) {
std::cerr << "\n!!!!!! [LSRA-FATAL] Allocation failed to converge even in Conservative Spill Mode. Triggering final fallback. !!!!!!\n\n";
return false; // 返回失败而不是exit
}
// 这是第一次达到最大迭代次数,触发保底策略。
std::cerr << "\n!!!!!! [LSRA-WARN] Convergence failed after " << MAX_ITERATIONS
<< " iterations. Entering Conservative Spill Mode for the next attempt. !!!!!!\n\n";
conservative_spill_mode = true; // 开启保守溢出模式,将在下一次循环生效
}
// 只要需要溢出,就重写程序
if (DEBUG) std::cerr << "[LSRA] Spilling detected, will rewrite program.\n";
rewriteProgram();
}
if (DEBUG) std::cerr << "[LSRA] Applying final allocation.\n";
applyAllocation();
MFunc->getFrameInfo().vreg_to_preg_map = this->vreg_to_preg_map;
collectUsedCalleeSavedRegs();
if (DEBUG) std::cerr << "===== [LSRA] Finished for function: " << MFunc->getName() << " =====\n\n";
return true; // 分配成功
}
void RISCv64LinearScan::linearizeBlocks() {
linear_order_blocks.clear();
for (auto& mbb : MFunc->getBlocks()) {
linear_order_blocks.push_back(mbb.get());
}
}
void RISCv64LinearScan::computeLiveIntervals() {
if (DEBUG) std::cerr << "[LSRA-Live] Starting live interval computation.\n";
instr_numbering.clear();
live_intervals.clear();
unhandled.clear();
int num = 0;
std::set<int> call_locations;
for (auto* mbb : linear_order_blocks) {
for (auto& instr : mbb->getInstructions()) {
instr_numbering[instr.get()] = num;
if (instr->getOpcode() == RVOpcodes::CALL) call_locations.insert(num);
num += 2;
}
}
if (DEEPDEBUG) std::cerr << " [Live] Starting live variable dataflow analysis...\n";
std::map<const MachineBasicBlock*, std::set<unsigned>> live_in, live_out;
bool changed = true;
int df_iter = 0;
while(changed) {
changed = false;
df_iter++;
std::vector<MachineBasicBlock*> reversed_blocks = linear_order_blocks;
std::reverse(reversed_blocks.begin(), reversed_blocks.end());
for(auto* mbb : reversed_blocks) {
std::set<unsigned> old_live_in = live_in[mbb];
std::set<unsigned> current_live_out;
for (auto* succ : mbb->successors) current_live_out.insert(live_in[succ].begin(), live_in[succ].end());
std::set<unsigned> use, def;
std::set<unsigned> temp_live = current_live_out;
auto& instrs = mbb->getInstructions();
for (auto it = instrs.rbegin(); it != instrs.rend(); ++it) {
use.clear(); def.clear();
getInstrUseDef(it->get(), use, def);
for (unsigned vreg : def) temp_live.erase(vreg);
for (unsigned vreg : use) temp_live.insert(vreg);
}
if (live_in[mbb] != temp_live || live_out[mbb] != current_live_out) {
changed = true;
live_in[mbb] = temp_live;
live_out[mbb] = current_live_out;
}
}
}
if (DEEPDEBUG) std::cerr << " [Live] Dataflow analysis converged after " << df_iter << " iterations.\n";
if (DEEPERDEBUG) {
std::cerr << " [Live-Debug] Live-in sets:\n";
for (auto* mbb : linear_order_blocks) std::cerr << " " << mbb->getName() << ": " << vregSetToString(live_in[mbb]) << "\n";
std::cerr << " [Live-Debug] Live-out sets:\n";
for (auto* mbb : linear_order_blocks) std::cerr << " " << mbb->getName() << ": " << vregSetToString(live_out[mbb]) << "\n";
}
if (DEEPDEBUG) std::cerr << " [Live] Building precise intervals...\n";
std::map<unsigned, int> first_def, last_use;
for (auto* mbb : linear_order_blocks) {
for (auto& instr_ptr : mbb->getInstructions()) {
int instr_num = instr_numbering.at(instr_ptr.get());
std::set<unsigned> use, def;
getInstrUseDef(instr_ptr.get(), use, def);
for (unsigned vreg : def) if (first_def.find(vreg) == first_def.end()) first_def[vreg] = instr_num;
for (unsigned vreg : use) last_use[vreg] = instr_num;
}
}
if (DEEPERDEBUG) {
std::cerr << " [Live-Debug] First def points:\n";
for (auto const& [vreg, pos] : first_def) std::cerr << " %v" << vreg << ": " << pos << "\n";
std::cerr << " [Live-Debug] Last use points:\n";
for (auto const& [vreg, pos] : last_use) std::cerr << " %v" << vreg << ": " << pos << "\n";
}
for (auto const& [vreg, start] : first_def) {
live_intervals.emplace(vreg, LiveInterval(vreg));
auto& interval = live_intervals.at(vreg);
interval.start = start;
interval.end = last_use.count(vreg) ? last_use.at(vreg) : start;
}
for (auto const& [mbb, live_set] : live_out) {
if (mbb->getInstructions().empty()) continue;
int block_end_num = instr_numbering.at(mbb->getInstructions().back().get());
for (unsigned vreg : live_set) {
if (live_intervals.count(vreg)) {
if (DEEPERDEBUG && live_intervals.at(vreg).end < block_end_num) {
std::cerr << " [Live-Debug] Extending interval for %v" << vreg << " from " << live_intervals.at(vreg).end << " to " << block_end_num << " due to live_out of " << mbb->getName() << "\n";
}
live_intervals.at(vreg).end = std::max(live_intervals.at(vreg).end, block_end_num);
}
}
}
for (auto& pair : live_intervals) {
auto& interval = pair.second;
auto it = call_locations.lower_bound(interval.start);
if (it != call_locations.end() && *it < interval.end) interval.crosses_call = true;
}
for (auto& pair : live_intervals) unhandled.push_back(&pair.second);
std::sort(unhandled.begin(), unhandled.end(), [](const LiveInterval* a, const LiveInterval* b){ return a->start < b->start; });
if (DEBUG) {
std::cerr << "[LSRA-Live] Finished. Total intervals: " << unhandled.size() << "\n";
if (DEEPDEBUG) {
std::cerr << " [Live] Computed Intervals (vreg: [start, end]):\n";
for(const auto* interval : unhandled) {
std::cerr << " %v" << interval->vreg << ": [" << interval->start << ", " << interval->end << "]"
<< (interval->crosses_call ? " (crosses call)" : "") << "\n";
}
}
}
// ================== 新增的调试代码 ==================
// 检查活性分析找到的vreg与指令扫描找到的vreg是否一致
if (DEEPERDEBUG) {
// 修正:将 std.set 修改为 std::set
std::set<unsigned> vregs_from_liveness;
for (const auto& pair : live_intervals) {
vregs_from_liveness.insert(pair.first);
}
std::set<unsigned> vregs_from_instr_scan;
for (auto* mbb : linear_order_blocks) {
for (auto& instr_ptr : mbb->getInstructions()) {
std::set<unsigned> use, def;
getInstrUseDef(instr_ptr.get(), use, def);
vregs_from_instr_scan.insert(use.begin(), use.end());
vregs_from_instr_scan.insert(def.begin(), def.end());
}
}
std::cerr << " [Live-Debug] VReg Consistency Check:\n";
std::cerr << " VRegs found by Liveness Analysis: " << vregs_from_liveness.size() << "\n";
std::cerr << " VRegs found by getInstrUseDef Scan: " << vregs_from_instr_scan.size() << "\n";
// 修正:将 std.set 修改为 std::set
std::set<unsigned> diff;
std::set_difference(vregs_from_liveness.begin(), vregs_from_liveness.end(),
vregs_from_instr_scan.begin(), vregs_from_instr_scan.end(),
std::inserter(diff, diff.begin()));
if (!diff.empty()) {
std::cerr << " !!!!!! [Live-Debug] DISCREPANCY DETECTED !!!!!!\n";
std::cerr << " The following vregs were found by liveness but NOT by getInstrUseDef scan:\n";
std::cerr << " " << vregSetToString(diff) << "\n";
} else {
std::cerr << " [Live-Debug] VReg sets are consistent.\n";
}
}
// ======================================================
}
bool RISCv64LinearScan::linearScan() {
// ================== 终极保底策略 (新逻辑) ==================
// 当此标志位为true时我们进入最暴力的溢出模式。
if (conservative_spill_mode) {
if (DEBUG) std::cerr << "[LSRA-Scan-Panic] In Conservative Mode. Spilling all unhandled vregs.\n";
// 1. 清空溢出列表,准备重新计算
spilled_vregs.clear();
// 2. 遍历所有计算出的活性区间
for (auto& pair : live_intervals) {
// 3. 如果一个vreg不是ABI规定的寄存器就必须溢出
if (abi_vreg_map.find(pair.first) == abi_vreg_map.end()) {
spilled_vregs.insert(pair.first);
}
}
// 4. 只要有任何vreg被标记为溢出就返回true以触发最终的rewriteProgram。
// 下一轮迭代时由于所有vreg都已被重写将不再有新的溢出保证收敛。
return !spilled_vregs.empty();
}
// ==========================================================
// ================== 常规线性扫描逻辑 (您已有的代码) ==================
// 只有在非保守模式下才会执行以下代码
if (DEBUG) std::cerr << "[LSRA-Scan] Starting main linear scan algorithm.\n";
active.clear();
spilled_vregs.clear();
vreg_to_preg_map.clear();
std::set<PhysicalReg> free_caller_int_regs, free_callee_int_regs;
std::set<PhysicalReg> free_caller_fp_regs, free_callee_fp_regs;
for (auto preg : allocable_int_regs) {
if (isCalleeSaved(preg)) free_callee_int_regs.insert(preg); else free_caller_int_regs.insert(preg);
}
for (auto preg : allocable_fp_regs) {
if (isCalleeSaved(preg)) free_callee_fp_regs.insert(preg); else free_caller_fp_regs.insert(preg);
}
if (DEEPDEBUG) {
std::cerr << " [Scan] Initial free regs:\n";
std::cerr << " Caller-Saved Int: " << pregSetToString(free_caller_int_regs) << "\n";
std::cerr << " Callee-Saved Int: " << pregSetToString(free_callee_int_regs) << "\n";
}
vreg_to_preg_map.insert(abi_vreg_map.begin(), abi_vreg_map.end());
std::vector<LiveInterval*> normal_unhandled;
for(LiveInterval* interval : unhandled) {
if(abi_vreg_map.count(interval->vreg)) {
active.push_back(interval);
PhysicalReg preg = abi_vreg_map.at(interval->vreg);
if (isFPVReg(interval->vreg)) {
if(isCalleeSaved(preg)) free_callee_fp_regs.erase(preg); else free_caller_fp_regs.erase(preg);
} else {
if(isCalleeSaved(preg)) free_callee_int_regs.erase(preg); else free_caller_int_regs.erase(preg);
}
} else {
normal_unhandled.push_back(interval);
}
}
unhandled = normal_unhandled;
std::sort(active.begin(), active.end(), [](const LiveInterval* a, const LiveInterval* b){ return a->end < b->end; });
for (LiveInterval* current : unhandled) {
if (DEEPDEBUG) std::cerr << "\n [Scan] Processing interval %v" << current->vreg << " [" << current->start << ", " << current->end << "]\n";
std::vector<LiveInterval*> new_active;
for (LiveInterval* active_interval : active) {
if (active_interval->end < current->start) {
PhysicalReg preg = vreg_to_preg_map.at(active_interval->vreg);
if (DEEPDEBUG) std::cerr << " [Scan] Expiring interval %v" << active_interval->vreg << ", freeing " << pregToString(preg) << "\n";
if (isFPVReg(active_interval->vreg)) {
if(isCalleeSaved(preg)) free_callee_fp_regs.insert(preg); else free_caller_fp_regs.insert(preg);
} else {
if(isCalleeSaved(preg)) free_callee_int_regs.insert(preg); else free_caller_int_regs.insert(preg);
}
} else {
new_active.push_back(active_interval);
}
}
active = new_active;
bool is_fp = isFPVReg(current->vreg);
auto& free_caller = is_fp ? free_caller_fp_regs : free_caller_int_regs;
auto& free_callee = is_fp ? free_callee_fp_regs : free_callee_int_regs;
PhysicalReg allocated_preg = PhysicalReg::INVALID;
if (current->crosses_call) {
if (!free_callee.empty()) {
allocated_preg = *free_callee.begin();
free_callee.erase(allocated_preg);
}
} else {
if (!free_caller.empty()) {
allocated_preg = *free_caller.begin();
free_caller.erase(allocated_preg);
} else if (!free_callee.empty()) {
allocated_preg = *free_callee.begin();
free_callee.erase(allocated_preg);
}
}
if (allocated_preg != PhysicalReg::INVALID) {
if (DEEPDEBUG) std::cerr << " [Scan] Allocated " << pregToString(allocated_preg) << " to %v" << current->vreg << "\n";
vreg_to_preg_map[current->vreg] = allocated_preg;
active.push_back(current);
std::sort(active.begin(), active.end(), [](const LiveInterval* a, const LiveInterval* b){ return a->end < b->end; });
} else {
if (DEEPDEBUG) std::cerr << " [Scan] No free registers for %v" << current->vreg << ". Spilling...\n";
spillAtInterval(current);
}
}
return !spilled_vregs.empty();
}
void RISCv64LinearScan::spillAtInterval(LiveInterval* current) {
// 保持您的原始逻辑
LiveInterval* spill_candidate = nullptr;
if (!active.empty()) {
spill_candidate = active.back();
}
if (DEEPERDEBUG) {
std::cerr << " [Spill-Debug] Spill decision for current=%v" << current->vreg << "[" << current->start << "," << current->end << "]\n";
std::cerr << " [Spill-Debug] Active intervals (sorted by end point):\n";
for (const auto* i : active) {
std::cerr << " %v" << i->vreg << "[" << i->start << "," << i->end << "] in " << pregToString(vreg_to_preg_map[i->vreg]) << "\n";
}
if(spill_candidate) {
std::cerr << " [Spill-Debug] Candidate is %v" << spill_candidate->vreg << ". Its end is " << spill_candidate->end << ", current's end is " << current->end << "\n";
} else {
std::cerr << " [Spill-Debug] No active candidate.\n";
}
}
if (spill_candidate && spill_candidate->end > current->end) {
if (DEEPDEBUG) std::cerr << " [Spill] Decision: Spilling active %v" << spill_candidate->vreg << ".\n";
PhysicalReg preg = vreg_to_preg_map.at(spill_candidate->vreg);
vreg_to_preg_map.erase(spill_candidate->vreg); // 确保移除旧映射
vreg_to_preg_map[current->vreg] = preg;
active.pop_back();
active.push_back(current);
std::sort(active.begin(), active.end(), [](const LiveInterval* a, const LiveInterval* b){ return a->end < b->end; });
spilled_vregs.insert(spill_candidate->vreg);
} else {
if (DEEPDEBUG) std::cerr << " [Spill] Decision: Spilling current %v" << current->vreg << ".\n";
spilled_vregs.insert(current->vreg);
}
}
void RISCv64LinearScan::rewriteProgram() {
if (DEBUG) {
std::cerr << "[LSRA-Rewrite] Starting program rewrite. Spilled vregs: " << vregSetToString(spilled_vregs) << "\n";
}
StackFrameInfo& frame_info = MFunc->getFrameInfo();
int spill_current_offset = frame_info.locals_end_offset - frame_info.spill_size;
for (unsigned vreg : spilled_vregs) {
// 保持您的原始逻辑
if (frame_info.spill_offsets.count(vreg)) continue;
Type* type = vreg_type_map.count(vreg) ? vreg_type_map.at(vreg) : Type::getIntType();
int size = isFPVReg(vreg) ? 4 : (type->isPointer() ? 8 : 4);
spill_current_offset -= size;
spill_current_offset = (spill_current_offset & ~7);
frame_info.spill_offsets[vreg] = spill_current_offset;
if (DEEPDEBUG) std::cerr << " [Rewrite] Assigned new stack offset " << frame_info.spill_offsets.at(vreg) << " to spilled %v" << vreg << "\n";
}
frame_info.spill_size = -(spill_current_offset - frame_info.locals_end_offset);
for (auto& mbb : MFunc->getBlocks()) {
auto& instrs = mbb->getInstructions();
std::vector<std::unique_ptr<MachineInstr>> new_instrs;
if (DEEPERDEBUG) std::cerr << " [Rewrite] Processing block " << mbb->getName() << "\n";
for (auto it = instrs.begin(); it != instrs.end(); ++it) {
auto& instr = *it;
std::set<unsigned> use_vregs, def_vregs;
getInstrUseDef(instr.get(), use_vregs, def_vregs);
if (conservative_spill_mode) {
// ================== 紧急模式重写逻辑 ==================
// 直接使用物理寄存器 t4 (SPILL_TEMP_REG) 进行加载/存储
// 为调试日志准备一个指令打印机
auto printer = DEEPERDEBUG ? std::make_unique<RISCv64AsmPrinter>(MFunc) : nullptr;
auto original_instr_str_for_log = DEEPERDEBUG ? printer->formatInstr(instr.get()) : "";
bool modified = false;
for (unsigned old_vreg : use_vregs) {
if (spilled_vregs.count(old_vreg)) {
modified = true;
Type* type = vreg_type_map.at(old_vreg);
RVOpcodes load_op = isFPVReg(old_vreg) ? RVOpcodes::FLW : (type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW);
auto load = std::make_unique<MachineInstr>(load_op);
// 直接加载到保留的物理寄存器
load->addOperand(std::make_unique<RegOperand>(SPILL_TEMP_REG));
load->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(old_vreg))));
if (DEEPERDEBUG) {
std::cerr << " [Rewrite-Panic] Inserting LOAD for use of %v" << old_vreg
<< " into " << pregToString(SPILL_TEMP_REG)
<< " before: " << original_instr_str_for_log << "\n";
}
new_instrs.push_back(std::move(load));
// 替换指令中的操作数
instr->replaceVRegWithPReg(old_vreg, SPILL_TEMP_REG);
}
}
// 在处理 def 之前,先替换定义自身的 vreg
for (unsigned old_vreg : def_vregs) {
if (spilled_vregs.count(old_vreg)) {
modified = true;
instr->replaceVRegWithPReg(old_vreg, SPILL_TEMP_REG);
}
}
// 将原始指令(可能已被修改)放入新列表
new_instrs.push_back(std::move(instr));
if (DEEPERDEBUG && modified) {
std::cerr << " [Rewrite-Panic] Original: " << original_instr_str_for_log
<< " -> Rewritten: " << printer->formatInstr(new_instrs.back().get()) << "\n";
}
for (unsigned old_vreg : def_vregs) {
if (spilled_vregs.count(old_vreg)) {
// 指令本身已经被修改为定义到 SPILL_TEMP_REG现在从它存回内存
Type* type = vreg_type_map.at(old_vreg);
RVOpcodes store_op = isFPVReg(old_vreg) ? RVOpcodes::FSW : (type->isPointer() ? RVOpcodes::SD : RVOpcodes::SW);
auto store = std::make_unique<MachineInstr>(store_op);
store->addOperand(std::make_unique<RegOperand>(SPILL_TEMP_REG));
store->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(old_vreg))));
if (DEEPERDEBUG) {
std::cerr << " [Rewrite-Panic] Inserting STORE for def of %v" << old_vreg
<< " from " << pregToString(SPILL_TEMP_REG) << " after original instr.\n";
}
new_instrs.push_back(std::move(store));
}
}
} else {
// ================== 常规模式重写逻辑 (您的原始代码) ==================
std::map<unsigned, unsigned> use_remap, def_remap;
for (unsigned old_vreg : use_vregs) {
if (spilled_vregs.count(old_vreg) && use_remap.find(old_vreg) == use_remap.end()) {
Type* type = vreg_type_map.at(old_vreg);
unsigned new_temp_vreg = ISel->getNewVReg(type);
use_remap[old_vreg] = new_temp_vreg;
RVOpcodes load_op = isFPVReg(old_vreg) ? RVOpcodes::FLW : (type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW);
auto load = std::make_unique<MachineInstr>(load_op);
load->addOperand(std::make_unique<RegOperand>(new_temp_vreg));
load->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(old_vreg))));
if (DEEPERDEBUG) {
RISCv64AsmPrinter printer(MFunc);
std::cerr << " [Rewrite] Inserting LOAD for use of %v" << old_vreg << " into new %v" << new_temp_vreg << " before: " << printer.formatInstr(instr.get()) << "\n";
}
new_instrs.push_back(std::move(load));
}
}
for (unsigned old_vreg : def_vregs) {
if (spilled_vregs.count(old_vreg) && def_remap.find(old_vreg) == def_remap.end()) {
Type* type = vreg_type_map.at(old_vreg);
unsigned new_temp_vreg = ISel->getNewVReg(type);
def_remap[old_vreg] = new_temp_vreg;
}
}
auto original_instr_str_for_log = DEEPERDEBUG ? RISCv64AsmPrinter(MFunc).formatInstr(instr.get()) : "";
instr->remapVRegs(use_remap, def_remap);
new_instrs.push_back(std::move(instr));
if (DEEPERDEBUG && (!use_remap.empty() || !def_remap.empty())) std::cerr << " [Rewrite] Original: " << original_instr_str_for_log << " -> Rewritten: " << RISCv64AsmPrinter(MFunc).formatInstr(new_instrs.back().get()) << "\n";
for(const auto& pair : def_remap) {
unsigned old_vreg = pair.first;
unsigned new_temp_vreg = pair.second;
Type* type = vreg_type_map.at(old_vreg);
RVOpcodes store_op = isFPVReg(old_vreg) ? RVOpcodes::FSW : (type->isPointer() ? RVOpcodes::SD : RVOpcodes::SW);
auto store = std::make_unique<MachineInstr>(store_op);
store->addOperand(std::make_unique<RegOperand>(new_temp_vreg));
store->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(old_vreg))));
if (DEEPERDEBUG) std::cerr << " [Rewrite] Inserting STORE for def of %v" << old_vreg << " from new %v" << new_temp_vreg << " after original instr.\n";
new_instrs.push_back(std::move(store));
}
}
}
instrs = std::move(new_instrs);
}
}
void RISCv64LinearScan::applyAllocation() {
if (DEBUG) std::cerr << "[LSRA-Apply] Applying final vreg->preg mapping.\n";
for (auto& mbb : MFunc->getBlocks()) {
for (auto& instr_ptr : mbb->getInstructions()) {
for (auto& op_ptr : instr_ptr->getOperands()) {
if (op_ptr->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(op_ptr.get());
if (reg_op->isVirtual()) {
unsigned vreg = reg_op->getVRegNum();
if (vreg_to_preg_map.count(vreg)) {
reg_op->setPReg(vreg_to_preg_map.at(vreg));
} else {
std::cerr << "ERROR: Uncolored virtual register %v" << vreg << " found during applyAllocation! in func " << MFunc->getName() << "\n";
// Forcing an error is better than silent failure.
// reg_op->setPReg(PhysicalReg::T5);
}
}
} else if (op_ptr->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand*>(op_ptr.get());
auto reg_op = mem_op->getBase();
if (reg_op->isVirtual()) {
unsigned vreg = reg_op->getVRegNum();
if (vreg_to_preg_map.count(vreg)) {
reg_op->setPReg(vreg_to_preg_map.at(vreg));
} else {
std::cerr << "ERROR: Uncolored virtual register %v" << vreg << " in memory operand! in func " << MFunc->getName() << "\n";
// reg_op->setPReg(PhysicalReg::T5);
}
}
}
}
}
}
}
// void getInstrUseDef(const MachineInstr* instr, std::set<unsigned>& use, std::set<unsigned>& def) {
// auto opcode = instr->getOpcode();
// const auto& operands = instr->getOperands();
// auto get_vreg_id_if_virtual = [&](const MachineOperand* op, std::set<unsigned>& s) {
// if (op->getKind() == MachineOperand::KIND_REG) {
// auto reg_op = static_cast<const RegOperand*>(op);
// if (reg_op->isVirtual()) s.insert(reg_op->getVRegNum());
// } else if (op->getKind() == MachineOperand::KIND_MEM) {
// auto mem_op = static_cast<const MemOperand*>(op);
// auto reg_op = mem_op->getBase();
// if (reg_op->isVirtual()) s.insert(reg_op->getVRegNum());
// }
// };
// if (op_info.count(opcode)) {
// const auto& info = op_info.at(opcode);
// for (int idx : info.first) if (idx < operands.size()) get_vreg_id_if_virtual(operands[idx].get(), def);
// for (int idx : info.second) if (idx < operands.size()) get_vreg_id_if_virtual(operands[idx].get(), use);
// for (const auto& op : operands) if (op->getKind() == MachineOperand::KIND_MEM) get_vreg_id_if_virtual(op.get(), use);
// } else if (opcode == RVOpcodes::CALL) {
// if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) get_vreg_id_if_virtual(operands[0].get(), def);
// for (size_t i = 1; i < operands.size(); ++i) if (operands[i]->getKind() == MachineOperand::KIND_REG) get_vreg_id_if_virtual(operands[i].get(), use);
// }
// }
bool RISCv64LinearScan::isFPVReg(unsigned vreg) const {
return vreg_type_map.count(vreg) && vreg_type_map.at(vreg)->isFloat();
}
void RISCv64LinearScan::collectUsedCalleeSavedRegs() {
StackFrameInfo& frame_info = MFunc->getFrameInfo();
frame_info.used_callee_saved_regs.clear();
const auto& callee_saved_int = getCalleeSavedIntRegs();
const auto& callee_saved_fp = getCalleeSavedFpRegs();
std::set<PhysicalReg> callee_saved_set(callee_saved_int.begin(), callee_saved_int.end());
callee_saved_set.insert(callee_saved_fp.begin(), callee_saved_fp.end());
callee_saved_set.insert(PhysicalReg::S0);
for(const auto& pair : vreg_to_preg_map) {
PhysicalReg preg = pair.second;
if(callee_saved_set.count(preg)) {
frame_info.used_callee_saved_regs.insert(preg);
}
}
}
} // namespace sysy

View File

@ -1,9 +1,13 @@
#include "RISCv64RegAlloc.h"
#include "RISCv64AsmPrinter.h"
#include "RISCv64Info.h"
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cassert>
#include <chrono>
#include <thread>
#include <atomic>
namespace sysy {
@ -44,7 +48,7 @@ RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc)
}
// 主入口: 迭代运行分配算法直到无溢出
void RISCv64RegAlloc::run() {
bool RISCv64RegAlloc::run(std::shared_ptr<std::atomic<bool>> stop_flag) {
if (DEBUG) std::cerr << "===== LLIR Before Running Graph Coloring Register Allocation " << MFunc->getName() << " =====\n";
std::stringstream ss_before_reg_alloc;
if (DEBUG) {
@ -59,36 +63,21 @@ void RISCv64RegAlloc::run() {
int iteration = 0;
while (iteration++ < MAX_ITERATIONS) {
// std::cerr << "Iteration Step: " << iteration << "\n";
// std::this_thread::sleep_for(std::chrono::seconds(1));
if (doAllocation()) {
break;
} else {
rewriteProgram();
if (stop_flag && stop_flag->load()) {
// 如果从外部接收到停止信号
std::cerr << "Info: IRC allocation cancelled due to timeout.\n";
return false; // 提前退出,并返回失败
}
if (DEBUG) std::cerr << "--- Spilling detected, re-running allocation (iteration " << iteration << ") ---\n";
if (iteration >= MAX_ITERATIONS) {
std::cerr << "ERROR: Register allocation failed to converge after " << MAX_ITERATIONS << " iterations\n";
std::cerr << " Spill worklist size: " << spillWorklist.size() << "\n";
std::cerr << " Total nodes: " << (initial.size() + coloredNodes.size()) << "\n";
// Emergency spill remaining nodes to break the loop
std::cerr << " Emergency spilling remaining spill worklist nodes...\n";
for (unsigned node : spillWorklist) {
spilledNodes.insert(node);
}
// Also spill any nodes that didn't get colors
std::set<unsigned> uncolored;
for (unsigned node : initial) {
if (color_map.find(node) == color_map.end()) {
uncolored.insert(node);
}
}
for (unsigned node : uncolored) {
spilledNodes.insert(node);
}
// Force completion
break;
return false;
}
}
}
@ -98,10 +87,13 @@ void RISCv64RegAlloc::run() {
MFunc->getFrameInfo().vreg_to_preg_map = this->color_map;
collectUsedCalleeSavedRegs();
if (DEBUG) std::cerr << "===== Finished Graph Coloring Register Allocation =====\n\n";
return true;
}
// 单次分配的核心流程
bool RISCv64RegAlloc::doAllocation() {
const int MAX_ITERATIONS = 50;
int iteration = 0;
initialize();
precolorByCallingConvention();
analyzeLiveness();
@ -109,14 +101,16 @@ bool RISCv64RegAlloc::doAllocation() {
makeWorklist();
while (!simplifyWorklist.empty() || !worklistMoves.empty() || !freezeWorklist.empty() || !spillWorklist.empty()) {
if (DEEPDEBUG) dumpState("Loop Start");
// if (DEBUG) std::cerr << "Inner Iteration Step: " << ++iteration << "\n";
// std::this_thread::sleep_for(std::chrono::milliseconds(100));
// if (DEEPDEBUG) dumpState("Loop Start");
if (!simplifyWorklist.empty()) simplify();
else if (!worklistMoves.empty()) coalesce();
else if (!freezeWorklist.empty()) freeze();
else if (!spillWorklist.empty()) selectSpill();
}
if (DEEPDEBUG) dumpState("Before AssignColors");
// if (DEEPDEBUG) dumpState("Before AssignColors");
assignColors();
return spilledNodes.empty();
}
@ -133,20 +127,46 @@ void RISCv64RegAlloc::precolorByCallingConvention() {
int int_arg_idx = 0;
int float_arg_idx = 0;
for (Argument* arg : F->getArguments()) {
unsigned vreg = ISel->getVReg(arg);
if (arg->getType()->isFloat()) {
if (float_arg_idx < 8) { // fa0-fa7
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + float_arg_idx);
color_map[vreg] = preg;
float_arg_idx++;
if (optLevel > 0)
{
for (const auto& pair : vreg_to_value_map) {
unsigned vreg = pair.first;
Value* val = pair.second;
// 检查这个 Value* 是不是一个 Argument 对象
if (auto arg = dynamic_cast<Argument*>(val)) {
// 如果是,那么 vreg 就是最初分配给这个参数的 vreg
int arg_idx = arg->getIndex();
if (arg->getType()->isFloat()) {
if (arg_idx < 8) { // fa0-fa7
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + arg_idx);
color_map[vreg] = preg;
}
} else { // 整数或指针
if (arg_idx < 8) { // a0-a7
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + arg_idx);
color_map[vreg] = preg;
}
}
}
} else { // 整数或指针
if (int_arg_idx < 8) { // a0-a7
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_arg_idx);
color_map[vreg] = preg;
int_arg_idx++;
}
} else {
for (Argument* arg : F->getArguments()) {
unsigned vreg = ISel->getVReg(arg);
if (arg->getType()->isFloat()) {
if (float_arg_idx < 8) { // fa0-fa7
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + float_arg_idx);
color_map[vreg] = preg;
float_arg_idx++;
}
} else { // 整数或指针
if (int_arg_idx < 8) { // a0-a7
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_arg_idx);
color_map[vreg] = preg;
int_arg_idx++;
}
}
}
}
@ -483,16 +503,18 @@ void RISCv64RegAlloc::coalesce() {
unsigned x = getAlias(*def.begin());
unsigned y = getAlias(*use.begin());
unsigned u, v;
if (precolored.count(y)) { u = y; v = x; } else { u = x; v = y; }
// 进一步修正标准化u和v的逻辑必须同时考虑物理寄存器和已预着色的虚拟寄存器。
// 目标是确保如果两个操作数中有一个是预着色的,它一定会被赋给 u。
if (precolored.count(y) || coloredNodes.count(y)) {
u = y; v = x;
} else {
u = x; v = y;
}
// 防御性检查,处理物理寄存器之间的传送指令
if (precolored.count(u) && precolored.count(v)) {
// 如果 u 和 v 都是物理寄存器,我们不能合并它们。
// 这通常是一条寄存器拷贝指令,例如 `mv a2, a1`。
// 把它加入 constrainedMoves 列表,然后直接返回,不再处理。
constrainedMoves.insert(move);
// addWorklist(u) 和 addWorklist(v) 在这里也不需要调用,
// 因为它们只对虚拟寄存器有意义。
return;
}
@ -504,7 +526,7 @@ void RISCv64RegAlloc::coalesce() {
if (DEEPERDEBUG) std::cerr << " -> Trivial coalesce (u == v).\n";
coalescedMoves.insert(move);
addWorklist(u);
return; // 处理完毕,提前返回
return;
}
if (isFPVReg(u) != isFPVReg(v)) {
@ -514,10 +536,13 @@ void RISCv64RegAlloc::coalesce() {
constrainedMoves.insert(move);
addWorklist(u);
addWorklist(v);
return; // 立即返回,不再进行后续检查
return;
}
bool pre_interfere = adjList.at(v).count(u);
// 注意如果v已经是u的邻居 pre_interfere 会为true。
// 但如果v不在adjList中例如v是预着色节点我们需要检查u是否在v的邻居中。
// 为了简化我们假设adjList包含了所有虚拟寄存器。对于(Phys, Virt)对冲突信息存储在Virt节点的邻接表中。
bool pre_interfere = (adjList.count(v) && adjList.at(v).count(u)) || (adjList.count(u) && adjList.at(u).count(v));
if (pre_interfere) {
if (DEEPERDEBUG) std::cerr << " -> Constrained (nodes already interfere).\n";
@ -527,63 +552,50 @@ void RISCv64RegAlloc::coalesce() {
return;
}
bool is_u_precolored = precolored.count(u);
// 考虑物理寄存器和已预着色的虚拟寄存器
bool u_is_effectively_precolored = precolored.count(u) || coloredNodes.count(u);
bool can_coalesce = false;
if (is_u_precolored) {
// --- 场景1u是物理寄存器使用 George 启发式 ---
if (DEEPERDEBUG) std::cerr << " -> Trying George Heuristic (u is precolored)...\n";
if (u_is_effectively_precolored) {
// --- 场景1u是物理寄存器或已预着色虚拟寄存器,使用 George 启发式 ---
if (DEEPERDEBUG) std::cerr << " -> Trying George Heuristic (u is effectively precolored)...\n";
// 步骤 1: 独立调用 adjacent(v) 获取邻居集合
VRegSet neighbors_of_v = adjacent(v);
if (DEEPERDEBUG) {
std::cerr << " - Neighbors of " << regIdToString(v) << " to check are (" << neighbors_of_v.size() << "): { ";
for (unsigned id : neighbors_of_v) std::cerr << regIdToString(id) << " ";
std::cerr << "}\n";
}
// 步骤 2: 使用显式的 for 循环来代替 std::all_of
bool george_ok = true; // 默认假设成功,任何一个邻居失败都会将此设为 false
bool george_ok = true;
for (unsigned t : neighbors_of_v) {
if (DEEPERDEBUG) {
std::cerr << " - Checking neighbor " << regIdToString(t) << ":\n";
}
if (DEEPERDEBUG) std::cerr << " - Checking neighbor " << regIdToString(t) << ":\n";
// 步骤 3: 独立调用启发式函数
bool heuristic_result = georgeHeuristic(t, u);
unsigned u_phys_id = precolored.count(u) ? u : (static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID) + static_cast<unsigned>(color_map.at(u)));
bool heuristic_result = georgeHeuristic(t, u_phys_id);
if (DEEPERDEBUG) {
std::cerr << " - georgeHeuristic(" << regIdToString(t) << ", " << regIdToString(u) << ") -> " << (heuristic_result ? "OK" : "FAIL") << "\n";
std::cerr << " - georgeHeuristic(" << regIdToString(t) << ", " << regIdToString(u_phys_id) << ") -> " << (heuristic_result ? "OK" : "FAIL") << "\n";
}
if (!heuristic_result) {
george_ok = false; // 只要有一个邻居不满足条件,整个检查就失败
break; // 并且可以立即停止检查其他邻居
george_ok = false;
break;
}
}
if (DEEPERDEBUG) {
std::cerr << " -> George Heuristic final result: " << (george_ok ? "OK" : "FAIL") << "\n";
}
if (george_ok) {
can_coalesce = true;
}
if (DEEPERDEBUG) std::cerr << " -> George Heuristic final result: " << (george_ok ? "OK" : "FAIL") << "\n";
if (george_ok) can_coalesce = true;
} else {
// --- 场景2u和v都是虚拟寄存器使用 Briggs 启发式 ---
// --- 场景2u和v都是未着色的虚拟寄存器,使用 Briggs 启发式 ---
if (DEEPERDEBUG) std::cerr << " -> Trying Briggs Heuristic (u and v are virtual)...\n";
bool briggs_ok = briggsHeuristic(u, v);
if (DEEPERDEBUG) std::cerr << " - briggsHeuristic(" << regIdToString(u) << ", " << regIdToString(v) << ") -> " << (briggs_ok ? "OK" : "FAIL") << "\n";
if (briggs_ok) {
can_coalesce = true;
}
if (briggs_ok) can_coalesce = true;
}
// --- 根据启发式结果进行最终决策 ---
if (can_coalesce) {
if (DEEPERDEBUG) std::cerr << " -> Heuristic OK. Combining " << regIdToString(v) << " into " << regIdToString(u) << ".\n";
coalescedMoves.insert(move);
@ -884,53 +896,6 @@ void RISCv64RegAlloc::getInstrUseDef_Liveness(const MachineInstr* instr, VRegSet
auto opcode = instr->getOpcode();
const auto& operands = instr->getOperands();
// 映射表:指令操作码 -> {Def操作数索引列表, Use操作数索引列表}
static const std::map<RVOpcodes, std::pair<std::vector<int>, std::vector<int>>> op_info = {
// ===== 整数算术与逻辑指令 (R-type & I-type) =====
{RVOpcodes::ADD, {{0}, {1, 2}}}, {RVOpcodes::SUB, {{0}, {1, 2}}}, {RVOpcodes::MUL, {{0}, {1, 2}}},
{RVOpcodes::DIV, {{0}, {1, 2}}}, {RVOpcodes::REM, {{0}, {1, 2}}}, {RVOpcodes::ADDW, {{0}, {1, 2}}},
{RVOpcodes::SUBW, {{0}, {1, 2}}}, {RVOpcodes::MULW, {{0}, {1, 2}}}, {RVOpcodes::DIVW, {{0}, {1, 2}}},
{RVOpcodes::REMW, {{0}, {1, 2}}}, {RVOpcodes::SLT, {{0}, {1, 2}}}, {RVOpcodes::SLTU, {{0}, {1, 2}}},
{RVOpcodes::XOR, {{0}, {1, 2}}}, {RVOpcodes::OR, {{0}, {1, 2}}}, {RVOpcodes::AND, {{0}, {1, 2}}},
{RVOpcodes::ADDI, {{0}, {1}}}, {RVOpcodes::ADDIW, {{0}, {1}}}, {RVOpcodes::XORI, {{0}, {1}}},
{RVOpcodes::ORI, {{0}, {1}}}, {RVOpcodes::ANDI, {{0}, {1}}},
{RVOpcodes::SLTI, {{0}, {1}}}, {RVOpcodes::SLTIU, {{0}, {1}}},
// ===== 移位指令 =====
{RVOpcodes::SLL, {{0}, {1, 2}}}, {RVOpcodes::SLLI, {{0}, {1}}},
{RVOpcodes::SLLW, {{0}, {1, 2}}}, {RVOpcodes::SLLIW, {{0}, {1}}},
{RVOpcodes::SRL, {{0}, {1, 2}}}, {RVOpcodes::SRLI, {{0}, {1}}},
{RVOpcodes::SRLW, {{0}, {1, 2}}}, {RVOpcodes::SRLIW, {{0}, {1}}},
{RVOpcodes::SRA, {{0}, {1, 2}}}, {RVOpcodes::SRAI, {{0}, {1}}},
{RVOpcodes::SRAW, {{0}, {1, 2}}}, {RVOpcodes::SRAIW, {{0}, {1}}},
// ===== 内存加载指令 (Def: 0, Use: MemBase) =====
{RVOpcodes::LB, {{0}, {}}}, {RVOpcodes::LH, {{0}, {}}}, {RVOpcodes::LW, {{0}, {}}}, {RVOpcodes::LD, {{0}, {}}},
{RVOpcodes::LBU, {{0}, {}}}, {RVOpcodes::LHU, {{0}, {}}}, {RVOpcodes::LWU, {{0}, {}}},
{RVOpcodes::FLW, {{0}, {}}}, {RVOpcodes::FLD, {{0}, {}}},
// ===== 内存存储指令 (Def: None, Use: ValToStore, MemBase) =====
{RVOpcodes::SB, {{}, {0, 1}}}, {RVOpcodes::SH, {{}, {0, 1}}}, {RVOpcodes::SW, {{}, {0, 1}}}, {RVOpcodes::SD, {{}, {0, 1}}},
{RVOpcodes::FSW, {{}, {0, 1}}}, {RVOpcodes::FSD, {{}, {0, 1}}},
// ===== 控制流指令 =====
{RVOpcodes::BEQ, {{}, {0, 1}}}, {RVOpcodes::BNE, {{}, {0, 1}}}, {RVOpcodes::BLT, {{}, {0, 1}}},
{RVOpcodes::BGE, {{}, {0, 1}}}, {RVOpcodes::BLTU, {{}, {0, 1}}}, {RVOpcodes::BGEU, {{}, {0, 1}}},
{RVOpcodes::JALR, {{0}, {1}}}, // def: ra (implicit) and op0, use: op1
// ===== 浮点指令 =====
{RVOpcodes::FADD_S, {{0}, {1, 2}}}, {RVOpcodes::FSUB_S, {{0}, {1, 2}}},
{RVOpcodes::FMUL_S, {{0}, {1, 2}}}, {RVOpcodes::FDIV_S, {{0}, {1, 2}}}, {RVOpcodes::FEQ_S, {{0}, {1, 2}}},
{RVOpcodes::FLT_S, {{0}, {1, 2}}}, {RVOpcodes::FLE_S, {{0}, {1, 2}}}, {RVOpcodes::FCVT_S_W, {{0}, {1}}},
{RVOpcodes::FCVT_W_S, {{0}, {1}}}, {RVOpcodes::FMV_S, {{0}, {1}}}, {RVOpcodes::FMV_W_X, {{0}, {1}}},
{RVOpcodes::FMV_X_W, {{0}, {1}}}, {RVOpcodes::FNEG_S, {{0}, {1}}},
// ===== 伪指令 =====
{RVOpcodes::LI, {{0}, {}}}, {RVOpcodes::LA, {{0}, {}}},
{RVOpcodes::MV, {{0}, {1}}}, {RVOpcodes::SEQZ, {{0}, {1}}}, {RVOpcodes::SNEZ, {{0}, {1}}},
{RVOpcodes::NEG, {{0}, {1}}}, {RVOpcodes::NEGW, {{0}, {1}}},
};
// lambda表达式用于获取操作数的寄存器ID虚拟或物理
const unsigned offset = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID);
auto get_any_reg_id = [&](const MachineOperand* op) -> unsigned {
@ -1186,7 +1151,7 @@ unsigned RISCv64RegAlloc::getAlias(unsigned n) {
}
void RISCv64RegAlloc::addWorklist(unsigned u) {
if (precolored.count(u)) return;
if (precolored.count(u) || color_map.count(u)) return;
int K = isFPVReg(u) ? K_fp : K_int;
if (!moveRelated(u) && degree.at(u) < K) {
@ -1261,8 +1226,12 @@ bool RISCv64RegAlloc::georgeHeuristic(unsigned t, unsigned u) {
}
int K = isFPVReg(t) ? K_fp : K_int;
// adjList.at(t) 现在是安全的,因为 degree.count(t) > 0 保证了 adjList.count(t) > 0
return degree.at(t) < K || precolored.count(u) || adjList.at(t).count(u);
// 缺陷 #2 修正: 移除了致命的 || precolored.count(u) 条件。
// 在此函数的上下文中u 总是预着色的物理寄存器ID导致旧的条件永远为true使整个启发式失效。
// 正确的逻辑是检查邻居t的度数是否小于K或者t是否已经与u冲突。
// return degree.at(t) < K || adjList.at(t).count(u);
return degree.at(t) < K || !adjList.at(t).count(u);
}
void RISCv64RegAlloc::combine(unsigned u, unsigned v) {
@ -1310,7 +1279,7 @@ void RISCv64RegAlloc::freezeMoves(unsigned u) {
activeMoves.erase(move);
frozenMoves.insert(move);
if (!precolored.count(v_alias) && nodeMoves(v_alias).empty() && degree.at(v_alias) < (isFPVReg(v_alias) ? K_fp : K_int)) {
if (!precolored.count(v_alias) && !coloredNodes.count(v_alias) && nodeMoves(v_alias).empty() && degree.at(v_alias) < (isFPVReg(v_alias) ? K_fp : K_int)) {
freezeWorklist.erase(v_alias);
simplifyWorklist.insert(v_alias);
if (DEEPERDEBUG) {

View File

@ -0,0 +1,716 @@
#include "RISCv64SimpleRegAlloc.h"
#include "RISCv64AsmPrinter.h"
#include "RISCv64Info.h"
#include <algorithm>
#include <iostream>
#include <cassert>
// 外部调试级别控制变量的定义
// 假设这些变量在其他地方定义例如主程序或一个通用的cpp文件
extern int DEBUG;
extern int DEEPDEBUG;
namespace sysy {
RISCv64SimpleRegAlloc::RISCv64SimpleRegAlloc(MachineFunction* mfunc) : MFunc(mfunc), ISel(mfunc->getISel()) {
// 1. 初始化可分配的整数寄存器池
// T5 被大立即数传送逻辑保留
// T2, T3, T4 被本分配器保留为专用的溢出/临时寄存器
allocable_int_regs = {
PhysicalReg::T0, PhysicalReg::T1, /* T2,T3,T4,T5,T6 reserved */
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3, PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7,
PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3, PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
};
// 2. 初始化可分配的浮点寄存器池
// F0, F1, F2 被本分配器保留为专用的溢出/临时寄存器
allocable_fp_regs = {
/* F0,F1,F2 reserved */ PhysicalReg::F3, PhysicalReg::F4, PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7,
PhysicalReg::F10, PhysicalReg::F11, PhysicalReg::F12, PhysicalReg::F13, PhysicalReg::F14, PhysicalReg::F15, PhysicalReg::F16, PhysicalReg::F17,
PhysicalReg::F8, PhysicalReg::F9, PhysicalReg::F18, PhysicalReg::F19, PhysicalReg::F20, PhysicalReg::F21, PhysicalReg::F22,
PhysicalReg::F23, PhysicalReg::F24, PhysicalReg::F25, PhysicalReg::F26, PhysicalReg::F27,
PhysicalReg::F28, PhysicalReg::F29, PhysicalReg::F30, PhysicalReg::F31,
};
// 3. 映射所有物理寄存器到特殊的虚拟寄存器ID (保持不变)
const unsigned offset = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID);
for (unsigned i = 0; i < static_cast<unsigned>(PhysicalReg::INVALID); ++i) {
auto preg = static_cast<PhysicalReg>(i);
preg_to_vreg_id_map[preg] = offset + i;
}
}
// 寄存器分配的主入口点
void RISCv64SimpleRegAlloc::run() {
if (DEBUG) std::cerr << "===== Running Simple Graph Coloring Allocator for function: " << MFunc->getName() << " =====\n";
// 实例化一个AsmPrinter用于调试输出避免重复创建
RISCv64AsmPrinter printer(MFunc);
printer.setStream(std::cerr);
if (DEBUG) {
std::cerr << "\n===== LLIR after VReg Unification =====\n";
printer.run(std::cerr, true);
std::cerr << "===== End of Unified LLIR =====\n\n";
}
// 阶段 1: 处理函数调用约定(参数寄存器预着色)
handleCallingConvention();
if (DEBUG) {
std::cerr << "--- After HandleCallingConvention ---\n";
std::cerr << "Pre-colored vregs:\n";
for (const auto& pair : color_map) {
std::cerr << " %vreg" << pair.first << " -> " << printer.regToString(pair.second) << "\n";
}
}
// 阶段 2: 活跃性分析
analyzeLiveness();
// 阶段 3: 构建干扰图
buildInterferenceGraph();
// 阶段 4: 图着色算法分配物理寄存器
colorGraph();
if (DEBUG) {
std::cerr << "\n--- After GraphColoring ---\n";
std::cerr << "Assigned colors:\n";
for (const auto& pair : color_map) {
std::cerr << " %vreg" << pair.first << " -> " << printer.regToString(pair.second) << "\n";
}
std::cerr << "Spilled vregs:\n";
if (spilled_vregs.empty()) {
std::cerr << " (None)\n";
} else {
for (unsigned vreg : spilled_vregs) {
std::cerr << " %vreg" << vreg << "\n";
}
}
}
// 阶段 5: 重写函数(插入溢出/填充代码,替换虚拟寄存器为物理寄存器)
rewriteFunction();
// 将最终的寄存器分配结果保存到MachineFunction的帧信息中供后续Pass使用
MFunc->getFrameInfo().vreg_to_preg_map = this->color_map;
if (DEBUG) {
std::cerr << "\n===== Final LLIR after Simple Register Allocation =====\n";
printer.run(std::cerr, false); // 使用false来打印最终的物理寄存器
std::cerr << "===== Finished Simple Graph Coloring Allocator =====\n\n";
}
}
/**
* @brief [新增] 虚拟寄存器统一预处理
* 扫描函数找到通过栈帧传递的参数并将后续从该栈帧加载的VReg统一为原始的参数VReg。
*/
void RISCv64SimpleRegAlloc::unifyArgumentVRegs() {
if (MFunc->getBlocks().size() < 2) return; // 至少需要入口和函数体两个块
std::map<int, unsigned> stack_slot_to_vreg; // 映射: <栈偏移, 原始参数vreg>
MachineBasicBlock* entry_block = MFunc->getBlocks().front().get();
// 步骤 1: 扫描入口块找到所有参数的“家home”在栈上的位置
for (const auto& instr : entry_block->getInstructions()) {
// 我们寻找 sw %vreg_arg, 0(%vreg_addr) 的模式
if (instr->getOpcode() == RVOpcodes::SW || instr->getOpcode() == RVOpcodes::SD || instr->getOpcode() == RVOpcodes::FSW) {
auto& operands = instr->getOperands();
if (operands.size() == 2 && operands[0]->getKind() == MachineOperand::KIND_REG && operands[1]->getKind() == MachineOperand::KIND_MEM) {
auto src_reg_op = static_cast<RegOperand*>(operands[0].get());
auto mem_op = static_cast<MemOperand*>(operands[1].get());
unsigned addr_vreg = mem_op->getBase()->getVRegNum();
// 查找定义这个地址vreg的addi指令以获取偏移量
for (const auto& prev_instr : entry_block->getInstructions()) {
if (prev_instr->getOpcode() == RVOpcodes::ADDI && prev_instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
auto def_op = static_cast<RegOperand*>(prev_instr->getOperands().front().get());
if (def_op->isVirtual() && def_op->getVRegNum() == addr_vreg) {
int offset = static_cast<ImmOperand*>(prev_instr->getOperands()[2].get())->getValue();
stack_slot_to_vreg[offset] = src_reg_op->getVRegNum();
break;
}
}
}
}
}
}
if (stack_slot_to_vreg.empty()) return; // 没有找到参数存储,无需处理
// 步骤 2: 扫描函数体构建本地vreg到参数vreg的重映射表
std::map<unsigned, unsigned> vreg_remap; // 映射: <本地vreg, 原始参数vreg>
MachineBasicBlock* body_block = MFunc->getBlocks()[1].get();
for (const auto& instr : body_block->getInstructions()) {
if (instr->getOpcode() == RVOpcodes::LW || instr->getOpcode() == RVOpcodes::LD || instr->getOpcode() == RVOpcodes::FLW) {
auto& operands = instr->getOperands();
if (operands.size() == 2 && operands[0]->getKind() == MachineOperand::KIND_REG && operands[1]->getKind() == MachineOperand::KIND_MEM) {
auto dest_reg_op = static_cast<RegOperand*>(operands[0].get());
auto mem_op = static_cast<MemOperand*>(operands[1].get());
unsigned addr_vreg = mem_op->getBase()->getVRegNum();
// 同样地查找定义地址的addi指令
for (const auto& prev_instr : body_block->getInstructions()) {
if (prev_instr->getOpcode() == RVOpcodes::ADDI && prev_instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
auto def_op = static_cast<RegOperand*>(prev_instr->getOperands().front().get());
if (def_op->isVirtual() && def_op->getVRegNum() == addr_vreg) {
int offset = static_cast<ImmOperand*>(prev_instr->getOperands()[2].get())->getValue();
if (stack_slot_to_vreg.count(offset)) {
unsigned old_vreg = dest_reg_op->getVRegNum();
unsigned new_vreg = stack_slot_to_vreg.at(offset);
vreg_remap[old_vreg] = new_vreg;
}
break;
}
}
}
}
}
}
if (vreg_remap.empty()) return;
// 步骤 3: 遍历所有指令,应用重映射
// 定义一个lambda函数来替换vreg避免代码重复
auto replace_vreg_in_operand = [&](MachineOperand* op) {
if (op->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(op);
if (reg_op->isVirtual() && vreg_remap.count(reg_op->getVRegNum())) {
reg_op->setVRegNum(vreg_remap.at(reg_op->getVRegNum()));
}
} else if (op->getKind() == MachineOperand::KIND_MEM) {
auto base_reg_op = static_cast<MemOperand*>(op)->getBase();
if (base_reg_op->isVirtual() && vreg_remap.count(base_reg_op->getVRegNum())) {
base_reg_op->setVRegNum(vreg_remap.at(base_reg_op->getVRegNum()));
}
}
};
for (auto& mbb : MFunc->getBlocks()) {
for (auto& instr : mbb->getInstructions()) {
for (auto& op : instr->getOperands()) {
replace_vreg_in_operand(op.get());
}
}
}
}
void RISCv64SimpleRegAlloc::handleCallingConvention() {
Function* F = MFunc->getFunc();
if (!F) return;
// --- 1. 处理函数传入参数的预着色 ---
int int_arg_idx = 0;
int float_arg_idx = 0;
for (Argument* arg : F->getArguments()) {
unsigned vreg = ISel->getVReg(arg);
if (arg->getType()->isFloat()) {
if (float_arg_idx < 8) { // fa0-fa7
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + float_arg_idx);
color_map[vreg] = preg;
}
float_arg_idx++;
} else {
if (int_arg_idx < 8) { // a0-a7
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_arg_idx);
color_map[vreg] = preg;
}
int_arg_idx++;
}
}
}
void RISCv64SimpleRegAlloc::analyzeLiveness() {
if (DEBUG) std::cerr << "\n--- Starting Liveness Analysis ---\n";
// === 阶段 1: 预计算每个基本块的 use 和 def 集合 ===
std::map<const MachineBasicBlock*, LiveSet> block_uses;
std::map<const MachineBasicBlock*, LiveSet> block_defs;
for (const auto& mbb_ptr : MFunc->getBlocks()) {
const MachineBasicBlock* mbb = mbb_ptr.get();
LiveSet uses, defs;
for (const auto& instr_ptr : mbb->getInstructions()) {
LiveSet instr_use, instr_def;
getInstrUseDef_Liveness(instr_ptr.get(), instr_use, instr_def);
// use[B] = use[B] U (instr_use - def[B])
for (unsigned u : instr_use) {
if (defs.find(u) == defs.end()) {
uses.insert(u);
}
}
// def[B] = def[B] U instr_def
defs.insert(instr_def.begin(), instr_def.end());
}
block_uses[mbb] = uses;
block_defs[mbb] = defs;
}
// === 阶段 2: 在“块”粒度上进行迭代数据流分析,直到收敛 ===
std::map<const MachineBasicBlock*, LiveSet> block_live_in;
std::map<const MachineBasicBlock*, LiveSet> block_live_out;
bool changed = true;
while (changed) {
changed = false;
// 逆序遍历基本块,加速收敛
for (auto it = MFunc->getBlocks().rbegin(); it != MFunc->getBlocks().rend(); ++it) {
const auto& mbb_ptr = *it;
const MachineBasicBlock* mbb = mbb_ptr.get();
// 2.1 计算 live_out[B] = U_{S in succ(B)} live_in[S]
LiveSet new_live_out;
for (auto succ : mbb->successors) {
new_live_out.insert(block_live_in[succ].begin(), block_live_in[succ].end());
}
// 2.2 计算 live_in[B] = use[B] U (live_out[B] - def[B])
LiveSet live_out_minus_def = new_live_out;
for (unsigned d : block_defs.at(mbb)) {
live_out_minus_def.erase(d);
}
LiveSet new_live_in = block_uses.at(mbb);
new_live_in.insert(live_out_minus_def.begin(), live_out_minus_def.end());
// 2.3 检查是否达到不动点
if (block_live_out[mbb] != new_live_out || block_live_in[mbb] != new_live_in) {
changed = true;
block_live_out[mbb] = new_live_out;
block_live_in[mbb] = new_live_in;
}
}
}
// === 阶段 3: 进行一次指令粒度的遍历,填充最终的 live_in_map 和 live_out_map ===
for (const auto& mbb_ptr : MFunc->getBlocks()) {
const MachineBasicBlock* mbb = mbb_ptr.get();
LiveSet live_out = block_live_out.at(mbb);
for (auto instr_it = mbb->getInstructions().rbegin(); instr_it != mbb->getInstructions().rend(); ++instr_it) {
const MachineInstr* instr = instr_it->get();
live_out_map[instr] = live_out;
LiveSet use, def;
getInstrUseDef_Liveness(instr, use, def);
LiveSet live_in = use;
LiveSet diff = live_out;
for (auto vreg : def) {
diff.erase(vreg);
}
live_in.insert(diff.begin(), diff.end());
live_in_map[instr] = live_in;
// 更新 live_out为块内的上一条指令做准备
live_out = live_in;
}
}
}
void RISCv64SimpleRegAlloc::buildInterferenceGraph() {
if (DEBUG) std::cerr << "\n--- Starting Interference Graph Construction ---\n";
RISCv64AsmPrinter printer(MFunc);
printer.setStream(std::cerr);
// 1. 收集所有图中需要出现的节点 (所有虚拟寄存器和物理寄存器)
std::set<unsigned> all_nodes;
for (const auto& mbb : MFunc->getBlocks()) {
for(const auto& instr : mbb->getInstructions()) {
LiveSet use, def;
getInstrUseDef_Liveness(instr.get(), use, def);
all_nodes.insert(use.begin(), use.end());
all_nodes.insert(def.begin(), def.end());
}
}
// 确保所有物理寄存器节点也存在
for (const auto& pair : preg_to_vreg_id_map) {
all_nodes.insert(pair.second);
}
// 2. 初始化干扰图邻接表
for (unsigned vreg : all_nodes) { interference_graph[vreg] = {}; }
// 3. 遍历指令,添加冲突边
for (const auto& mbb : MFunc->getBlocks()) {
if (DEEPDEBUG) std::cerr << "--- Building Graph for Basic Block: " << mbb->getName() << " ---\n";
for (const auto& instr_ptr : mbb->getInstructions()) {
const MachineInstr* instr = instr_ptr.get();
if (DEEPDEBUG) {
std::cerr << " Instr: ";
printer.printInstruction(const_cast<MachineInstr*>(instr), true);
}
LiveSet def, use;
getInstrUseDef_Liveness(instr, def, use); // 注意Use/Def顺序
const LiveSet& live_out = live_out_map.at(instr);
if (DEEPDEBUG) {
printLiveSet(use, "Use ", std::cerr, printer);
printLiveSet(def, "Def ", std::cerr, printer);
printLiveSet(live_out, "Live_Out", std::cerr, printer);
}
// 规则1: 指令的定义(def)与该指令之后的所有活跃变量(live_out)冲突
for (unsigned d : def) {
for (unsigned l : live_out) {
if (d != l) {
if (DEEPDEBUG && interference_graph.at(d).find(l) == interference_graph.at(d).end()) {
std::cerr << " Edge (Def-LiveOut): " << regIdToString(d, printer) << " <-> " << regIdToString(l, printer) << "\n";
}
interference_graph[d].insert(l);
interference_graph[l].insert(d);
}
}
}
// 规则2: 对于非MV指令, def与use也冲突
if (instr->getOpcode() != RVOpcodes::MV) {
for (unsigned d : def) {
for (unsigned u : use) {
if (d != u) {
if (DEEPDEBUG && interference_graph.at(d).find(u) == interference_graph.at(d).end()) {
std::cerr << " Edge (Def-Use): " << regIdToString(d, printer) << " <-> " << regIdToString(u, printer) << "\n";
}
interference_graph[d].insert(u);
interference_graph[u].insert(d);
}
}
}
}
// 所有在某一点上同时活跃的寄存器即live_out集合中的所有成员
// 它们之间必须两两互相干扰。
std::vector<unsigned> live_out_vec(live_out.begin(), live_out.end());
for (size_t i = 0; i < live_out_vec.size(); ++i) {
for (size_t j = i + 1; j < live_out_vec.size(); ++j) {
unsigned u = live_out_vec[i];
unsigned v = live_out_vec[j];
if (DEEPDEBUG && interference_graph[u].find(v) == interference_graph[u].end()) {
std::cerr << " Edge (Live-Live): %vreg" << u << " <-> %vreg" << v << "\n";
}
interference_graph[u].insert(v);
interference_graph[v].insert(u);
}
}
// 规则3: CALL指令会破坏所有调用者保存(caller-saved)寄存器
if (instr->getOpcode() == RVOpcodes::CALL) {
const auto& caller_saved_int = getCallerSavedIntRegs();
const auto& caller_saved_fp = getCallerSavedFpRegs();
for (unsigned live_vreg : live_out) {
auto [type, size] = getTypeAndSize(live_vreg);
if (type == Type::kFloat) {
for (PhysicalReg cs_reg : caller_saved_fp) {
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg);
if (live_vreg != cs_vreg_id) {
interference_graph[live_vreg].insert(cs_vreg_id);
interference_graph[cs_vreg_id].insert(live_vreg);
}
}
} else {
for (PhysicalReg cs_reg : caller_saved_int) {
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg);
if (live_vreg != cs_vreg_id) {
interference_graph[live_vreg].insert(cs_vreg_id);
interference_graph[cs_vreg_id].insert(live_vreg);
}
}
}
}
} // end if CALL
if (DEEPDEBUG) std::cerr << " ----------------\n";
} // end for instr
} // end for mbb
}
void RISCv64SimpleRegAlloc::colorGraph() {
// 1. 收集所有需要着色的虚拟寄存器
std::vector<unsigned> vregs_to_color;
for (auto const& [vreg, neighbors] : interference_graph) {
// 只为未预着色的、真正的虚拟寄存器进行着色
if (color_map.find(vreg) == color_map.end() && vreg < static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID)) {
vregs_to_color.push_back(vreg);
}
}
// 2. 按冲突度从高到低排序,进行贪心着色
std::sort(vregs_to_color.begin(), vregs_to_color.end(), [&](unsigned a, unsigned b) {
return interference_graph.at(a).size() > interference_graph.at(b).size();
});
// 3. 遍历并着色
for (unsigned vreg : vregs_to_color) {
std::set<PhysicalReg> used_colors;
// 收集所有邻居的颜色
for (unsigned neighbor_id : interference_graph.at(vreg)) {
// A. 邻居是已着色的vreg
if (color_map.count(neighbor_id)) {
used_colors.insert(color_map.at(neighbor_id));
}
// B. 邻居是物理寄存器本身
else if (neighbor_id >= static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID)) {
PhysicalReg neighbor_preg = static_cast<PhysicalReg>(neighbor_id - static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID));
used_colors.insert(neighbor_preg);
}
}
// 根据vreg类型选择寄存器池
auto [type, size] = getTypeAndSize(vreg);
const auto& allocable_regs = (type == Type::kFloat) ? allocable_fp_regs : allocable_int_regs;
bool colored = false;
for (PhysicalReg preg : allocable_regs) {
if (used_colors.find(preg) == used_colors.end()) {
color_map[vreg] = preg;
colored = true;
break;
}
}
if (!colored) {
spilled_vregs.insert(vreg);
}
}
}
void RISCv64SimpleRegAlloc::rewriteFunction() {
if (DEBUG) std::cerr << "\n--- Starting Function Rewrite (Spilling & Substitution) ---\n";
StackFrameInfo& frame_info = MFunc->getFrameInfo();
// 步骤 1: 为所有溢出的vreg计算唯一的栈偏移量 (此部分逻辑正确,予以保留)
int current_offset = frame_info.locals_end_offset;
for (unsigned vreg : spilled_vregs) {
if (frame_info.spill_offsets.count(vreg)) continue;
auto [type, size] = getTypeAndSize(vreg);
current_offset -= size;
current_offset = current_offset & ~7;
frame_info.spill_offsets[vreg] = current_offset;
}
frame_info.spill_size = -(current_offset - frame_info.locals_end_offset);
// 步骤 2: 遍历所有指令对CALL指令做简化处理
for (auto& mbb : MFunc->getBlocks()) {
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
for (auto& instr_ptr : mbb->getInstructions()) {
if (instr_ptr->getOpcode() != RVOpcodes::CALL) {
std::vector<PhysicalReg> int_spill_pool = {PhysicalReg::T2, PhysicalReg::T3, PhysicalReg::T4, /*PhysicalReg::T5,*/ PhysicalReg::T6};
std::vector<PhysicalReg> fp_spill_pool = {PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3};
std::map<unsigned, PhysicalReg> vreg_to_preg_map_for_this_instr;
LiveSet use, def;
getInstrUseDef(instr_ptr.get(), use, def);
LiveSet all_vregs_in_instr = use;
all_vregs_in_instr.insert(def.begin(), def.end());
for(unsigned vreg : all_vregs_in_instr) {
if (spilled_vregs.count(vreg)) {
auto [type, size] = getTypeAndSize(vreg);
if (type == Type::kFloat) {
assert(!fp_spill_pool.empty() && "FP spill pool exhausted for generic instruction!");
vreg_to_preg_map_for_this_instr[vreg] = fp_spill_pool.front();
fp_spill_pool.erase(fp_spill_pool.begin());
} else {
assert(!int_spill_pool.empty() && "Int spill pool exhausted for generic instruction!");
vreg_to_preg_map_for_this_instr[vreg] = int_spill_pool.front();
int_spill_pool.erase(int_spill_pool.begin());
}
}
}
for (unsigned vreg : use) {
if (spilled_vregs.count(vreg)) {
PhysicalReg target_preg = vreg_to_preg_map_for_this_instr.at(vreg);
auto [type, size] = getTypeAndSize(vreg);
RVOpcodes load_op = (type == Type::kFloat) ? RVOpcodes::FLW : ((type == Type::kPointer) ? RVOpcodes::LD : RVOpcodes::LW);
auto load = std::make_unique<MachineInstr>(load_op);
load->addOperand(std::make_unique<RegOperand>(target_preg));
load->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(vreg))
));
new_instructions.push_back(std::move(load));
}
}
auto new_instr = std::make_unique<MachineInstr>(instr_ptr->getOpcode());
for (const auto& op : instr_ptr->getOperands()) {
const RegOperand* reg_op = nullptr;
if (op->getKind() == MachineOperand::KIND_REG) reg_op = static_cast<const RegOperand*>(op.get());
else if (op->getKind() == MachineOperand::KIND_MEM) reg_op = static_cast<const MemOperand*>(op.get())->getBase();
if (reg_op) {
PhysicalReg final_preg;
if (reg_op->isVirtual()) {
unsigned vreg = reg_op->getVRegNum();
if (spilled_vregs.count(vreg)) {
final_preg = vreg_to_preg_map_for_this_instr.at(vreg);
} else {
assert(color_map.count(vreg));
final_preg = color_map.at(vreg);
}
} else {
final_preg = reg_op->getPReg();
}
auto new_reg_op = std::make_unique<RegOperand>(final_preg);
if (op->getKind() == MachineOperand::KIND_REG) {
new_instr->addOperand(std::move(new_reg_op));
} else {
auto mem_op = static_cast<const MemOperand*>(op.get());
new_instr->addOperand(std::make_unique<MemOperand>(std::move(new_reg_op), std::make_unique<ImmOperand>(*mem_op->getOffset())));
}
} else {
if(op->getKind() == MachineOperand::KIND_IMM) new_instr->addOperand(std::make_unique<ImmOperand>(*static_cast<const ImmOperand*>(op.get())));
else if (op->getKind() == MachineOperand::KIND_LABEL) new_instr->addOperand(std::make_unique<LabelOperand>(*static_cast<const LabelOperand*>(op.get())));
}
}
new_instructions.push_back(std::move(new_instr));
for (unsigned vreg : def) {
if (spilled_vregs.count(vreg)) {
PhysicalReg src_preg = vreg_to_preg_map_for_this_instr.at(vreg);
auto [type, size] = getTypeAndSize(vreg);
RVOpcodes store_op = (type == Type::kFloat) ? RVOpcodes::FSW : ((type == Type::kPointer) ? RVOpcodes::SD : RVOpcodes::SW);
auto store = std::make_unique<MachineInstr>(store_op);
store->addOperand(std::make_unique<RegOperand>(src_preg));
store->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(vreg))
));
new_instructions.push_back(std::move(store));
}
}
} else {
// --- 对于CALL指令只处理其自身和返回值不再处理参数 ---
const PhysicalReg INT_TEMP_REG = PhysicalReg::T6;
const PhysicalReg FP_TEMP_REG = PhysicalReg::F7;
// 1. 克隆CALL指令本身只保留标签操作数
auto new_call = std::make_unique<MachineInstr>(RVOpcodes::CALL);
for (const auto& op : instr_ptr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_LABEL) {
new_call->addOperand(std::make_unique<LabelOperand>(*static_cast<const LabelOperand*>(op.get())));
// 注意只添加第一个标签防止ISel的错误导致多个标签
break;
}
}
new_instructions.push_back(std::move(new_call));
// 2. 只处理返回值(def)的溢出和移动
auto& operands = instr_ptr->getOperands();
if (!operands.empty() && operands.front()->getKind() == MachineOperand::KIND_REG) {
unsigned def_vreg = static_cast<RegOperand*>(operands.front().get())->getVRegNum();
auto [type, size] = getTypeAndSize(def_vreg);
PhysicalReg result_reg_abi = type == Type::kFloat ? PhysicalReg::F10 : PhysicalReg::A0;
if (spilled_vregs.count(def_vreg)) {
// 返回值被溢出a0/fa0 -> temp -> 溢出槽
PhysicalReg temp_reg = type == Type::kFloat ? FP_TEMP_REG : INT_TEMP_REG;
RVOpcodes store_op = (type == Type::kFloat) ? RVOpcodes::FSW : ((type == Type::kPointer) ? RVOpcodes::SD : RVOpcodes::SW);
auto mv_from_abi = std::make_unique<MachineInstr>(type == Type::kFloat ? RVOpcodes::FMV_S : RVOpcodes::MV);
mv_from_abi->addOperand(std::make_unique<RegOperand>(temp_reg));
mv_from_abi->addOperand(std::make_unique<RegOperand>(result_reg_abi));
new_instructions.push_back(std::move(mv_from_abi));
auto store = std::make_unique<MachineInstr>(store_op);
store->addOperand(std::make_unique<RegOperand>(temp_reg));
store->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(def_vreg))
));
new_instructions.push_back(std::move(store));
} else {
// 返回值未溢出a0/fa0 -> 已着色的物理寄存器
auto mv_to_dest = std::make_unique<MachineInstr>(type == Type::kFloat ? RVOpcodes::FMV_S : RVOpcodes::MV);
mv_to_dest->addOperand(std::make_unique<RegOperand>(color_map.at(def_vreg)));
mv_to_dest->addOperand(std::make_unique<RegOperand>(result_reg_abi));
new_instructions.push_back(std::move(mv_to_dest));
}
}
}
}
mbb->getInstructions() = std::move(new_instructions);
}
}
// --- 辅助函数实现 ---
void RISCv64SimpleRegAlloc::getInstrUseDef_Liveness(const MachineInstr* instr, LiveSet& use, LiveSet& def) {
auto opcode = instr->getOpcode();
const auto& operands = instr->getOperands();
const unsigned offset = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID);
auto get_any_reg_id = [&](const MachineOperand* op) -> unsigned {
if (op->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<const RegOperand*>(op);
return reg_op->isVirtual() ? reg_op->getVRegNum() : (offset + static_cast<unsigned>(reg_op->getPReg()));
} else if (op->getKind() == MachineOperand::KIND_MEM) {
auto reg_op = static_cast<const MemOperand*>(op)->getBase();
return reg_op->isVirtual() ? reg_op->getVRegNum() : (offset + static_cast<unsigned>(reg_op->getPReg()));
}
return (unsigned)-1;
};
if (op_info.count(opcode)) {
const auto& info = op_info.at(opcode);
for (int idx : info.first) if (idx < operands.size()) {
unsigned reg_id = get_any_reg_id(operands[idx].get());
if (reg_id != (unsigned)-1) def.insert(reg_id);
}
for (int idx : info.second) if (idx < operands.size()) {
unsigned reg_id = get_any_reg_id(operands[idx].get());
if (reg_id != (unsigned)-1) use.insert(reg_id);
}
for (const auto& op : operands) {
if (op->getKind() == MachineOperand::KIND_MEM) {
unsigned reg_id = get_any_reg_id(op.get());
if (reg_id != (unsigned)-1) use.insert(reg_id);
}
}
}
else if (opcode == RVOpcodes::CALL) {
if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) {
def.insert(get_any_reg_id(operands[0].get()));
}
for (size_t i = 1; i < operands.size(); ++i) {
if (operands[i]->getKind() == MachineOperand::KIND_REG) {
use.insert(get_any_reg_id(operands[i].get()));
}
}
for (auto preg : getCallerSavedIntRegs()) def.insert(offset + static_cast<unsigned>(preg));
for (auto preg : getCallerSavedFpRegs()) def.insert(offset + static_cast<unsigned>(preg));
def.insert(offset + static_cast<unsigned>(PhysicalReg::RA));
}
else if (opcode == RVOpcodes::RET) {
use.insert(offset + static_cast<unsigned>(PhysicalReg::A0));
use.insert(offset + static_cast<unsigned>(PhysicalReg::F10)); // fa0
}
}
std::pair<Type::Kind, unsigned> RISCv64SimpleRegAlloc::getTypeAndSize(unsigned vreg) {
const auto& vreg_type_map = ISel->getVRegTypeMap();
if (vreg_type_map.count(vreg)) {
Type* type = vreg_type_map.at(vreg);
if (type->isFloat()) return {Type::kFloat, 4};
if (type->isPointer()) return {Type::kPointer, 8};
}
// 默认或未知类型按32位整数处理
return {Type::kInt, 4};
}
std::string RISCv64SimpleRegAlloc::regIdToString(unsigned id, const RISCv64AsmPrinter& printer) const {
const unsigned offset = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID);
if (id >= offset) {
PhysicalReg reg = static_cast<PhysicalReg>(id - offset);
return printer.regToString(reg);
} else {
return "%vreg" + std::to_string(id);
}
}
void RISCv64SimpleRegAlloc::printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os, const RISCv64AsmPrinter& printer) {
os << " " << name << " (" << s.size() << "): { ";
for (unsigned vreg : s) {
os << regIdToString(vreg, printer) << " ";
}
os << "}\n";
}
} // namespace sysy

View File

@ -23,6 +23,21 @@ public:
bool runOnFunction(Function *F, AnalysisManager& AM) override;
void runOnMachineFunction(MachineFunction* mfunc);
/**
* @brief 设置是否启用浮点乘加融合优化
* @param enabled 是否启用
*/
static void setFusedMulAddEnabled(bool enabled) { fusedMulAddEnabled = enabled; }
/**
* @brief 检查是否启用了浮点乘加融合优化
* @return 是否启用
*/
static bool isFusedMulAddEnabled() { return fusedMulAddEnabled; }
private:
static bool fusedMulAddEnabled; // 浮点乘加融合优化开关
};
} // namespace sysy

View File

@ -19,7 +19,7 @@ public:
// 辅助函数
void setStream(std::ostream& os) { OS = &os; }
// 辅助函数
std::string regToString(PhysicalReg reg);
std::string regToString(PhysicalReg reg) const;
std::string formatInstr(const MachineInstr *instr);
private:

View File

@ -26,6 +26,7 @@ private:
unsigned getTypeSizeInBytes(Type* type);
Module* module;
bool irc_failed = false;
};
} // namespace sysy

View File

@ -0,0 +1,61 @@
#ifndef RISCV64_BASICBLOCKALLOC_H
#define RISCV64_BASICBLOCKALLOC_H
#include "RISCv64LLIR.h"
#include "RISCv64ISel.h"
#include <set>
#include <map>
#include <vector>
namespace sysy {
/**
* @class RISCv64BasicBlockAlloc
* @brief 一个有状态的、基本块级的贪心寄存器分配器。
*
* 该分配器作为简单但可靠的实现,它逐个处理基本块,并在块内尽可能地
* 将虚拟寄存器的值保留在物理寄存器中,以减少不必要的内存访问。
*/
class RISCv64BasicBlockAlloc {
public:
RISCv64BasicBlockAlloc(MachineFunction* mfunc);
void run();
private:
void computeLiveness();
void processBasicBlock(MachineBasicBlock* mbb);
void assignStackSlotsForAllVRegs();
// 核心分配函数
PhysicalReg ensureInReg(unsigned vreg, std::vector<std::unique_ptr<MachineInstr>>& new_instrs);
PhysicalReg allocReg(unsigned vreg, std::vector<std::unique_ptr<MachineInstr>>& new_instrs);
PhysicalReg findFreeReg(bool is_fp);
PhysicalReg spillReg(bool is_fp, std::vector<std::unique_ptr<MachineInstr>>& new_instrs);
// 状态跟踪(每个基本块开始时都会重置)
std::map<unsigned, PhysicalReg> vreg_to_preg; // 当前vreg到物理寄存器的映射
std::map<PhysicalReg, unsigned> preg_to_vreg; // 反向映射
std::set<PhysicalReg> dirty_pregs; // 被修改过、需要写回的物理寄存器
// 分配器全局信息
MachineFunction* MFunc;
RISCv64ISel* ISel;
std::map<unsigned, PhysicalReg> abi_vreg_map; // 函数参数的ABI寄存器映射
// 寄存器池和循环索引
std::vector<PhysicalReg> int_temps;
std::vector<PhysicalReg> fp_temps;
int int_temp_idx = 0;
int fp_temp_idx = 0;
// 辅助函数
PhysicalReg getNextIntTemp();
PhysicalReg getNextFpTemp();
// 活性分析结果
std::map<const MachineBasicBlock*, std::set<unsigned>> live_out;
};
} // namespace sysy
#endif // RISCV64_BASICBLOCKALLOC_H

View File

@ -11,6 +11,7 @@ namespace sysy {
extern int DEBUG;
extern int DEEPDEBUG;
extern int optLevel;
namespace sysy {
@ -22,7 +23,6 @@ public:
// 公开接口以便后续模块如RegAlloc可以查询或创建vreg
unsigned getVReg(Value* val);
unsigned getNewVReg() { return vreg_counter++; }
unsigned getNewVReg(Type* type);
unsigned getVRegCounter() const;
// 获取 vreg_map 的公共接口

View File

@ -0,0 +1,98 @@
#ifndef RISCV64_INFO_H
#define RISCV64_INFO_H
#include "RISCv64LLIR.h"
#include <map>
#include <vector>
namespace sysy {
// 定义一个全局的、权威的指令信息表
// 它包含了指令的定义(def)和使用(use)操作数索引
// defs: {0} -> 第一个操作数是定义
// uses: {1, 2} -> 第二、三个操作数是使用
static const std::map<RVOpcodes, std::pair<std::vector<int>, std::vector<int>>> op_info = {
// --- 整数计算 (R-Type) ---
{RVOpcodes::ADD, {{0}, {1, 2}}},
{RVOpcodes::SUB, {{0}, {1, 2}}},
{RVOpcodes::MUL, {{0}, {1, 2}}},
{RVOpcodes::MULH, {{0}, {1, 2}}},
{RVOpcodes::DIV, {{0}, {1, 2}}},
{RVOpcodes::DIVW, {{0}, {1, 2}}},
{RVOpcodes::REM, {{0}, {1, 2}}},
{RVOpcodes::REMW, {{0}, {1, 2}}},
{RVOpcodes::ADDW, {{0}, {1, 2}}},
{RVOpcodes::SUBW, {{0}, {1, 2}}},
{RVOpcodes::MULW, {{0}, {1, 2}}},
{RVOpcodes::SLT, {{0}, {1, 2}}},
{RVOpcodes::SLTU, {{0}, {1, 2}}},
{RVOpcodes::XOR, {{0}, {1, 2}}},
{RVOpcodes::OR, {{0}, {1, 2}}},
{RVOpcodes::AND, {{0}, {1, 2}}},
{RVOpcodes::SLL, {{0}, {1, 2}}},
{RVOpcodes::SRL, {{0}, {1, 2}}},
{RVOpcodes::SRA, {{0}, {1, 2}}},
{RVOpcodes::SLLW, {{0}, {1, 2}}},
{RVOpcodes::SRLW, {{0}, {1, 2}}},
{RVOpcodes::SRAW, {{0}, {1, 2}}},
// --- 整数计算 (I-Type) ---
{RVOpcodes::ADDI, {{0}, {1}}},
{RVOpcodes::ADDIW, {{0}, {1}}},
{RVOpcodes::XORI, {{0}, {1}}},
{RVOpcodes::ORI, {{0}, {1}}},
{RVOpcodes::ANDI, {{0}, {1}}},
{RVOpcodes::SLTI, {{0}, {1}}},
{RVOpcodes::SLTIU, {{0}, {1}}},
{RVOpcodes::SLLI, {{0}, {1}}},
{RVOpcodes::SLLIW, {{0}, {1}}},
{RVOpcodes::SRLI, {{0}, {1}}},
{RVOpcodes::SRLIW, {{0}, {1}}},
{RVOpcodes::SRAI, {{0}, {1}}},
{RVOpcodes::SRAIW, {{0}, {1}}},
// --- 内存加载 ---
{RVOpcodes::LW, {{0}, {}}}, {RVOpcodes::LH, {{0}, {}}}, {RVOpcodes::LB, {{0}, {}}},
{RVOpcodes::LWU, {{0}, {}}}, {RVOpcodes::LHU, {{0}, {}}}, {RVOpcodes::LBU, {{0}, {}}},
{RVOpcodes::LD, {{0}, {}}},
{RVOpcodes::FLW, {{0}, {}}}, {RVOpcodes::FLD, {{0}, {}}},
// --- 内存存储 ---
{RVOpcodes::SW, {{}, {0, 1}}}, {RVOpcodes::SH, {{}, {0, 1}}}, {RVOpcodes::SB, {{}, {0, 1}}},
{RVOpcodes::SD, {{}, {0, 1}}},
{RVOpcodes::FSW, {{}, {0, 1}}}, {RVOpcodes::FSD, {{}, {0, 1}}},
// --- 分支指令 ---
{RVOpcodes::BEQ, {{}, {0, 1}}}, {RVOpcodes::BNE, {{}, {0, 1}}}, {RVOpcodes::BLT, {{}, {0, 1}}},
{RVOpcodes::BGE, {{}, {0, 1}}}, {RVOpcodes::BLTU, {{}, {0, 1}}}, {RVOpcodes::BGEU, {{}, {0, 1}}},
// --- 跳转 ---
{RVOpcodes::JAL, {{0}, {}}}, // JAL的rd是def但通常用x0表示不关心返回值这里简化
{RVOpcodes::JALR, {{0}, {1}}},
{RVOpcodes::RET, {{}, {}}}, // RET是伪指令通常展开为JALR
// --- 伪指令 & 其他 ---
{RVOpcodes::LI, {{0}, {}}}, {RVOpcodes::LA, {{0}, {}}},
{RVOpcodes::MV, {{0}, {1}}},
{RVOpcodes::NEG, {{0}, {1}}}, // sub rd, zero, rs1
{RVOpcodes::NEGW, {{0}, {1}}}, // subw rd, zero, rs1
{RVOpcodes::SEQZ, {{0}, {1}}},
{RVOpcodes::SNEZ, {{0}, {1}}},
// --- 函数调用 ---
// CALL的use/def在getInstrUseDef中有特殊处理逻辑这里可以不列出
// --- 浮点指令 ---
{RVOpcodes::FADD_S, {{0}, {1, 2}}}, {RVOpcodes::FSUB_S, {{0}, {1, 2}}},
{RVOpcodes::FMUL_S, {{0}, {1, 2}}}, {RVOpcodes::FDIV_S, {{0}, {1, 2}}},
{RVOpcodes::FMADD_S, {{0}, {1, 2, 3}}},
{RVOpcodes::FEQ_S, {{0}, {1, 2}}}, {RVOpcodes::FLT_S, {{0}, {1, 2}}}, {RVOpcodes::FLE_S, {{0}, {1, 2}}},
{RVOpcodes::FCVT_S_W, {{0}, {1}}}, {RVOpcodes::FCVT_W_S, {{0}, {1}}},
{RVOpcodes::FCVT_W_S_RTZ, {{0}, {1}}},
{RVOpcodes::FMV_S, {{0}, {1}}}, {RVOpcodes::FMV_W_X, {{0}, {1}}}, {RVOpcodes::FMV_X_W, {{0}, {1}}},
{RVOpcodes::FNEG_S, {{0}, {1}}}
};
} // namespace sysy
#endif // RISCV64_INFO_H

View File

@ -41,6 +41,8 @@ enum class PhysicalReg {
// 假设 vreg_counter 不会达到这么大的值
PHYS_REG_START_ID = 1000000,
PHYS_REG_END_ID = PHYS_REG_START_ID + 320, // 预留足够的空间
INVALID, ///< 无效寄存器标记
};
// RISC-V 指令操作码枚举
@ -77,6 +79,7 @@ enum class RVOpcodes {
FSUB_S, // fsub.s rd, rs1, rs2
FMUL_S, // fmul.s rd, rs1, rs2
FDIV_S, // fdiv.s rd, rs1, rs2
FMADD_S, // fmadd.s rd, rs1, rs2, rs3
// 浮点比较 (单精度)
FEQ_S, // feq.s rd, rs1, rs2 (结果写入整数寄存器rd)
@ -86,6 +89,7 @@ enum class RVOpcodes {
// 浮点转换
FCVT_S_W, // fcvt.s.w rd, rs1 (有符号整数 -> 单精度浮点)
FCVT_W_S, // fcvt.w.s rd, rs1 (单精度浮点 -> 有符号整数)
FCVT_W_S_RTZ, // fcvt.w.s rd, rs1, rtz (使用向零截断模式)
// 浮点传送/移动
FMV_S, // fmv.s rd, rs1 (浮点寄存器之间)
@ -93,6 +97,9 @@ enum class RVOpcodes {
FMV_X_W, // fmv.x.w rd, rs1 (浮点寄存器位模式 -> 整数寄存器)
FNEG_S, // fneg.s rd, rs (浮点取负)
// 浮点控制状态寄存器 (CSR)
FSRMI, // fsrmi rd, imm (设置舍入模式立即数)
// 伪指令
FRAME_LOAD_W, // 从栈帧加载 32位 Word (对应 lw)
FRAME_LOAD_D, // 从栈帧加载 64位 Doubleword (对应 ld)
@ -249,6 +256,19 @@ public:
void addOperand(std::unique_ptr<MachineOperand> operand) {
operands.push_back(std::move(operand));
}
/**
* @brief (为紧急溢出模式添加)将指令中所有对特定虚拟寄存器的引用替换为指定的物理寄存器。
* * @param old_vreg 需要被替换的虚拟寄存器号。
* @param preg 用于替换的物理寄存器。
*/
void replaceVRegWithPReg(unsigned old_vreg, PhysicalReg preg);
/**
* @brief (为常规溢出模式添加)根据提供的映射表,重映射指令中的虚拟寄存器。
* * @param use_remap 一个从旧vreg到新vreg的映射用于指令的use操作数。
* @param def_remap 一个从旧vreg到新vreg的映射用于指令的def操作数。
*/
void remapVRegs(const std::map<unsigned, unsigned>& use_remap, const std::map<unsigned, unsigned>& def_remap);
private:
RVOpcodes opcode;
std::vector<std::unique_ptr<MachineOperand>> operands;
@ -313,6 +333,22 @@ private:
std::vector<std::unique_ptr<MachineBasicBlock>> blocks;
StackFrameInfo frame_info;
};
inline bool isMemoryOp(RVOpcodes opcode) {
switch (opcode) {
case RVOpcodes::LB: case RVOpcodes::LH: case RVOpcodes::LW: case RVOpcodes::LD:
case RVOpcodes::LBU: case RVOpcodes::LHU: case RVOpcodes::LWU:
case RVOpcodes::SB: case RVOpcodes::SH: case RVOpcodes::SW: case RVOpcodes::SD:
case RVOpcodes::FLW:
case RVOpcodes::FSW:
case RVOpcodes::FLD:
case RVOpcodes::FSD:
return true;
default:
return false;
}
}
void getInstrUseDef(const MachineInstr* instr, std::set<unsigned>& use, std::set<unsigned>& def);
} // namespace sysy

View File

@ -0,0 +1,81 @@
#ifndef RISCV64_LINEARSCAN_H
#define RISCV64_LINEARSCAN_H
#include "RISCv64LLIR.h"
#include "RISCv64ISel.h"
#include <vector>
#include <map>
#include <set>
#include <algorithm>
namespace sysy {
// 前向声明
class MachineBasicBlock;
class MachineFunction;
class RISCv64ISel;
/**
* @brief 表示一个虚拟寄存器的活跃区间。
* 包含起始和结束指令编号。为了简化,我们不处理有“洞”的区间。
*/
struct LiveInterval {
unsigned vreg = 0;
int start = -1;
int end = -1;
bool crosses_call = false;
LiveInterval(unsigned vreg) : vreg(vreg) {}
// 用于排序,按起始点从小到大
bool operator<(const LiveInterval& other) const {
return start < other.start;
}
};
class RISCv64LinearScan {
public:
RISCv64LinearScan(MachineFunction* mfunc);
bool run();
private:
// --- 核心算法流程 ---
void linearizeBlocks();
void computeLiveIntervals();
bool linearScan();
void rewriteProgram();
void applyAllocation();
void spillAtInterval(LiveInterval* current);
// --- 辅助函数 ---
bool isFPVReg(unsigned vreg) const;
void collectUsedCalleeSavedRegs();
MachineFunction* MFunc;
RISCv64ISel* ISel;
// --- 线性扫描数据结构 ---
std::vector<MachineBasicBlock*> linear_order_blocks;
std::map<const MachineInstr*, int> instr_numbering;
std::map<unsigned, LiveInterval> live_intervals;
std::vector<LiveInterval*> unhandled;
std::vector<LiveInterval*> active; // 活跃且已分配物理寄存器的区间
std::set<unsigned> spilled_vregs; // 记录在本轮被决定溢出的vreg
bool conservative_spill_mode = false;
const PhysicalReg SPILL_TEMP_REG = PhysicalReg::T4;
// --- 寄存器池和分配结果 ---
std::vector<PhysicalReg> allocable_int_regs;
std::vector<PhysicalReg> allocable_fp_regs;
std::map<unsigned, PhysicalReg> vreg_to_preg_map;
std::map<unsigned, PhysicalReg> abi_vreg_map;
const std::map<unsigned, Type*>& vreg_type_map;
};
} // namespace sysy
#endif // RISCV64_LINEARSCAN_H

View File

@ -1,6 +1,7 @@
#ifndef RISCV64_PASSES_H
#define RISCV64_PASSES_H
#include "Pass.h"
#include "RISCv64LLIR.h"
#include "Peephole.h"
#include "PreRA_Scheduler.h"
@ -9,10 +10,8 @@
#include "LegalizeImmediates.h"
#include "PrologueEpilogueInsertion.h"
#include "EliminateFrameIndices.h"
#include "Pass.h"
#include "DivStrengthReduction.h"
namespace sysy {
} // namespace sysy

View File

@ -12,6 +12,7 @@ extern int DEBUG;
extern int DEEPDEBUG;
extern int DEBUGLENGTH; // 用于限制调试输出的长度
extern int DEEPERDEBUG; // 用于更深层次的调试输出
extern int optLevel;
namespace sysy {
@ -20,7 +21,7 @@ public:
RISCv64RegAlloc(MachineFunction* mfunc);
// 模块主入口
void run();
bool run(std::shared_ptr<std::atomic<bool>> stop_flag);
private:
// 类型定义与Python版本对应

View File

@ -0,0 +1,107 @@
#ifndef RISCV64_SIMPLE_REGALLOC_H
#define RISCV64_SIMPLE_REGALLOC_H
#include "RISCv64LLIR.h"
#include "RISCv64ISel.h"
#include <set>
#include <vector>
#include <map>
// 外部调试级别控制变量的声明
extern int DEBUG;
extern int DEEPDEBUG;
namespace sysy {
class RISCv64AsmPrinter; // 前向声明
/**
* @class RISCv64SimpleRegAlloc
* @brief 一个简单的一次性图着色寄存器分配器。
* * 该分配器遵循一个线性的、非迭代的流程:
* 1. 活跃性分析
* 2. 构建冲突图
* 3. 贪心图着色
* 4. 重写函数代码,插入溢出指令
* * 它与新版后端流水线兼容,但保留了旧版分配器的核心逻辑。
* 溢出处理使用硬编码的物理寄存器。
*/
class RISCv64SimpleRegAlloc {
public:
RISCv64SimpleRegAlloc(MachineFunction* mfunc);
/**
* @brief 运行寄存器分配的主函数。
*/
void run();
private:
using LiveSet = std::set<unsigned>;
using InterferenceGraph = std::map<unsigned, LiveSet>;
// --- 分配流程的各个阶段 ---
void unifyArgumentVRegs();
void handleCallingConvention();
void analyzeLiveness();
void buildInterferenceGraph();
void colorGraph();
void rewriteFunction();
// --- 辅助函数 ---
/**
* @brief 获取指令的Use/Def集合包含物理寄存器用于活跃性分析。
* @param instr 机器指令。
* @param use 输出参数存储使用的寄存器ID。
* @param def 输出参数存储定义的寄存器ID。
*/
void getInstrUseDef_Liveness(const MachineInstr* instr, LiveSet& use, LiveSet& def);
/**
* @brief 根据vreg的类型信息返回其大小和类型种类。
* @param vreg 虚拟寄存器号。
* @return 一个包含类型信息和大小字节的pair。
*/
std::pair<Type::Kind, unsigned> getTypeAndSize(unsigned vreg);
/**
* @brief 打印调试用的活跃集信息。
*/
void printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os, const RISCv64AsmPrinter& printer);
/**
* @brief 将寄存器ID虚拟或物理转换为可读字符串。
*/
std::string regIdToString(unsigned id, const RISCv64AsmPrinter& printer) const;
// --- 成员变量 ---
MachineFunction* MFunc;
RISCv64ISel* ISel;
// 可分配的寄存器池
std::vector<PhysicalReg> allocable_int_regs;
std::vector<PhysicalReg> allocable_fp_regs;
// 硬编码的溢出专用物理寄存器
const PhysicalReg INT_SPILL_REG = PhysicalReg::T2; // 用于 32-bit int
const PhysicalReg PTR_SPILL_REG = PhysicalReg::T3; // 用于 64-bit pointer
const PhysicalReg FP_SPILL_REG = PhysicalReg::F4; // 用于 32-bit float (ft4)
// 活跃性分析结果
std::map<const MachineInstr*, LiveSet> live_in_map;
std::map<const MachineInstr*, LiveSet> live_out_map;
// 冲突图
InterferenceGraph interference_graph;
// 着色结果和溢出列表
std::map<unsigned, PhysicalReg> color_map;
std::set<unsigned> spilled_vregs;
// 映射将物理寄存器ID映射到它们在冲突图中的特殊虚拟ID
std::map<PhysicalReg, unsigned> preg_to_vreg_id_map;
};
} // namespace sysy
#endif // RISCV64_SIMPLE_REGALLOC_H

View File

@ -350,7 +350,11 @@ private:
std::set<Value*>& visited
);
bool isBasicInductionVariable(Value* val, Loop* loop);
bool hasSimpleMemoryPattern(Loop* loop); // 简单的内存模式检查
// ========== 循环不变量分析辅助方法 ==========
bool isInvariantOperands(Instruction* inst, Loop* loop, const std::unordered_set<Value*>& invariants);
bool isMemoryLocationModifiedInLoop(Value* ptr, Loop* loop);
bool isMemoryLocationLoadedInLoop(Value* ptr, Loop* loop, Instruction* excludeInst = nullptr);
bool isPureFunction(Function* calledFunc);
};
} // namespace sysy

View File

@ -0,0 +1,87 @@
#pragma once
#include "Pass.h"
#include "IR.h"
#include "Dom.h"
#include "SideEffectAnalysis.h"
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <string>
#include <sstream>
namespace sysy {
// GVN优化遍的核心逻辑封装类
class GVNContext {
public:
// 运行GVN优化的主要方法
void run(Function* func, AnalysisManager* AM, bool& changed);
private:
// 新的值编号系统
std::unordered_map<Value*, unsigned> valueToNumber; // Value -> 值编号
std::unordered_map<unsigned, Value*> numberToValue; // 值编号 -> 代表值
std::unordered_map<std::string, unsigned> expressionToNumber; // 表达式 -> 值编号
unsigned nextValueNumber = 1;
// 已访问的基本块集合
std::unordered_set<BasicBlock*> visited;
// 逆后序遍历的基本块列表
std::vector<BasicBlock*> rpoBlocks;
// 需要删除的指令集合
std::unordered_set<Instruction*> needRemove;
// 分析结果
DominatorTree* domTree = nullptr;
SideEffectAnalysisResult* sideEffectAnalysis = nullptr;
// 计算逆后序遍历
void computeRPO(Function* func);
void dfs(BasicBlock* bb);
// 新的值编号方法
unsigned getValueNumber(Value* value);
unsigned assignValueNumber(Value* value);
// 基本块处理
void processBasicBlock(BasicBlock* bb, bool& changed);
// 指令处理
bool processInstruction(Instruction* inst);
// 表达式构建和查找
std::string buildExpressionKey(Instruction* inst);
Value* findExistingValue(const std::string& exprKey, Instruction* inst);
// 支配关系和安全性检查
bool dominates(Instruction* a, Instruction* b);
bool isMemorySafe(LoadInst* earlierLoad, LoadInst* laterLoad);
// 清理方法
void eliminateRedundantInstructions(bool& changed);
void invalidateMemoryValues(StoreInst* store);
};
// GVN优化遍类
class GVN : public OptimizationPass {
public:
// 静态成员作为该遍的唯一ID
static void* ID;
GVN() : OptimizationPass("GVN", Granularity::Function) {}
// 在函数上运行优化
bool runOnFunction(Function* func, AnalysisManager& AM) override;
// 返回该遍的唯一ID
void* getPassID() const override { return ID; }
// 声明分析依赖
void getAnalysisUsage(std::set<void*>& analysisDependencies,
std::set<void*>& analysisInvalidations) const override;
};
} // namespace sysy

View File

@ -0,0 +1,107 @@
#pragma once
#include "Pass.h"
#include "IR.h"
#include "SideEffectAnalysis.h"
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <cstdint>
namespace sysy {
// 魔数乘法结构,用于除法优化
struct MagicNumber {
uint32_t multiplier;
int shift;
bool needAdd;
MagicNumber(uint32_t m, int s, bool add = false)
: multiplier(m), shift(s), needAdd(add) {}
};
// 全局强度削弱优化遍的核心逻辑封装类
class GlobalStrengthReductionContext {
public:
// 构造函数接受IRBuilder参数
explicit GlobalStrengthReductionContext(IRBuilder* builder) : builder(builder) {}
// 运行优化的主要方法
void run(Function* func, AnalysisManager* AM, bool& changed);
private:
IRBuilder* builder; // IR构建器
// 分析结果
SideEffectAnalysisResult* sideEffectAnalysis = nullptr;
// 优化计数
int algebraicOptCount = 0;
int strengthReductionCount = 0;
int divisionOptCount = 0;
// 主要优化方法
bool processBasicBlock(BasicBlock* bb);
bool processInstruction(Instruction* inst);
// 代数优化方法
bool tryAlgebraicOptimization(Instruction* inst);
bool optimizeAddition(BinaryInst* inst);
bool optimizeSubtraction(BinaryInst* inst);
bool optimizeMultiplication(BinaryInst* inst);
bool optimizeDivision(BinaryInst* inst);
bool optimizeComparison(BinaryInst* inst);
bool optimizeLogical(BinaryInst* inst);
// 强度削弱方法
bool tryStrengthReduction(Instruction* inst);
bool reduceMultiplication(BinaryInst* inst);
bool reduceDivision(BinaryInst* inst);
bool reducePower(CallInst* inst);
// 复杂乘法强度削弱方法
bool tryComplexMultiplication(BinaryInst* inst, Value* variable, int constant);
bool findOptimalShiftDecomposition(int constant, std::vector<int>& shifts);
Value* createShiftDecomposition(BinaryInst* inst, Value* variable, const std::vector<int>& shifts);
// 魔数乘法相关方法
MagicNumber computeMagicNumber(uint32_t divisor);
std::pair<int, int> computeMulhMagicNumbers(int divisor);
Value* createMagicDivision(BinaryInst* divInst, uint32_t divisor, const MagicNumber& magic);
Value* createMagicDivisionLibdivide(BinaryInst* divInst, int divisor);
bool isPowerOfTwo(uint32_t n);
int log2OfPowerOfTwo(uint32_t n);
// 辅助方法
bool isConstantInt(Value* val, int& constVal);
bool isConstantInt(Value* val, uint32_t& constVal);
ConstantInteger* getConstantInt(int val);
bool hasOnlyLocalUses(Instruction* inst);
void replaceWithOptimized(Instruction* original, Value* replacement);
};
// 全局强度削弱优化遍类
class GlobalStrengthReduction : public OptimizationPass {
private:
IRBuilder* builder; // IR构建器用于创建新指令
public:
// 静态成员作为该遍的唯一ID
static void* ID;
// 构造函数接受IRBuilder参数
explicit GlobalStrengthReduction(IRBuilder* builder)
: OptimizationPass("GlobalStrengthReduction", Granularity::Function), builder(builder) {}
// 在函数上运行优化
bool runOnFunction(Function* func, AnalysisManager& AM) override;
// 返回该遍的唯一ID
void* getPassID() const override { return ID; }
// 声明分析依赖
void getAnalysisUsage(std::set<void*>& analysisDependencies,
std::set<void*>& analysisInvalidations) const override;
};
} // namespace sysy

View File

@ -6,6 +6,7 @@
#include "Loop.h"
#include "Dom.h"
#include "SideEffectAnalysis.h"
#include "AliasAnalysis.h"
#include <vector>
#include <unordered_map>
#include <unordered_set>
@ -53,6 +54,7 @@ private:
LoopCharacteristicsResult* loopCharacteristics = nullptr;
DominatorTree* dominatorTree = nullptr;
SideEffectAnalysisResult* sideEffectAnalysis = nullptr;
AliasAnalysisResult* aliasAnalysis = nullptr;
// 死归纳变量存储
std::vector<std::unique_ptr<DeadInductionVariable>> deadIVs;
@ -90,12 +92,105 @@ private:
isDeadInductionVariable(const InductionVarInfo* iv, Loop* loop);
/**
* 检查归纳变量是否只用于自身更新
* 递归分析phi指令及其使用链是否都是死代码
* @param phiInst phi指令
* @param loop 所在循环
* @return 是否只用于自身更新
* @return phi指令是否可以安全删除
*/
bool isUsedOnlyForSelfUpdate(PhiInst* phiInst, Loop* loop);
bool isPhiInstructionDeadRecursively(PhiInst* phiInst, Loop* loop);
/**
* 递归分析指令的使用链是否都是死代码
* @param inst 要分析的指令
* @param loop 所在循环
* @param visited 已访问的指令集合(避免无限递归)
* @param currentPath 当前递归路径(检测循环依赖)
* @return 指令的使用链是否都是死代码
*/
bool isInstructionUseChainDeadRecursively(Instruction* inst, Loop* loop,
std::set<Instruction*>& visited,
std::set<Instruction*>& currentPath);
/**
* 检查循环是否有副作用
* @param loop 要检查的循环
* @return 循环是否有副作用
*/
bool loopHasSideEffects(Loop* loop);
/**
* 检查指令是否被用于循环退出条件
* @param inst 要检查的指令
* @param loop 所在循环
* @return 是否被用于循环退出条件
*/
bool isUsedInLoopExitCondition(Instruction* inst, Loop* loop);
/**
* 检查指令的结果是否未被有效使用
* @param inst 要检查的指令
* @param loop 所在循环
* @return 指令结果是否未被有效使用
*/
bool isInstructionResultUnused(Instruction* inst, Loop* loop);
/**
* 检查store指令是否存储到死地址利用别名分析
* @param store store指令
* @param loop 所在循环
* @return 是否存储到死地址
*/
bool isStoreToDeadLocation(StoreInst* store, Loop* loop);
/**
* 检查指令是否为死代码或只在循环内部使用
* @param inst 要检查的指令
* @param loop 所在循环
* @return 是否为死代码或只在循环内部使用
*/
bool isInstructionDeadOrInternalOnly(Instruction* inst, Loop* loop);
/**
* 检查指令是否有效地为死代码(带递归深度限制)
* @param inst 要检查的指令
* @param loop 所在循环
* @param maxDepth 最大递归深度
* @return 指令是否有效地为死代码
*/
bool isInstructionEffectivelyDead(Instruction* inst, Loop* loop, int maxDepth);
/**
* 检查store指令是否有后续的load操作
* @param store store指令
* @param loop 所在循环
* @return 是否有后续的load操作
*/
bool hasSubsequentLoad(StoreInst* store, Loop* loop);
/**
* 检查指令是否在循环外有使用
* @param inst 要检查的指令
* @param loop 所在循环
* @return 是否在循环外有使用
*/
bool hasUsageOutsideLoop(Instruction* inst, Loop* loop);
/**
* 检查store指令是否在循环外有后续的load操作
* @param store store指令
* @param loop 所在循环
* @return 是否在循环外有后续的load操作
*/
bool hasSubsequentLoadOutsideLoop(StoreInst* store, Loop* loop);
/**
* 递归检查基本块子树中是否有对指定位置的load操作
* @param bb 基本块
* @param ptr 指针
* @param visited 已访问的基本块集合
* @return 是否有load操作
*/
bool hasLoadInSubtree(BasicBlock* bb, Value* ptr, std::set<BasicBlock*>& visited);
/**
* 收集与归纳变量相关的所有指令

View File

@ -1,24 +0,0 @@
#pragma once
#include "../Pass.h"
namespace sysy {
class LargeArrayToGlobalPass : public OptimizationPass {
public:
static void *ID;
LargeArrayToGlobalPass() : OptimizationPass("LargeArrayToGlobal", Granularity::Module) {}
bool runOnModule(Module *M, AnalysisManager &AM) override;
void *getPassID() const override {
return &ID;
}
private:
unsigned calculateTypeSize(Type *type);
void convertAllocaToGlobal(AllocaInst *alloca, Function *F, Module *M);
std::string generateUniqueGlobalName(AllocaInst *alloca, Function *F);
};
} // namespace sysy

View File

@ -127,13 +127,6 @@ private:
*/
bool analyzeInductionVariableRange(const InductionVarInfo* ivInfo, Loop* loop) const;
/**
* 计算用于除法优化的魔数和移位量
* @param divisor 除数
* @return {魔数, 移位量}
*/
std::pair<int, int> computeMulhMagicNumbers(int divisor) const;
/**
* 生成除法替换代码
* @param candidate 优化候选项

View File

@ -107,6 +107,190 @@ public:
// 所以当AllocaInst的basetype是PointerType时一维数组或者是指向ArrayType的PointerType多位数组返回true
return aval && (baseType->isPointer() || baseType->as<PointerType>()->getBaseType()->isArray());
}
//该实现参考了libdivide的算法
static std::pair<int, int> computeMulhMagicNumbers(int divisor) {
if (DEBUG) {
std::cout << "\n[SR] ===== Computing magic numbers for divisor " << divisor << " (libdivide algorithm) =====" << std::endl;
}
if (divisor == 0) {
if (DEBUG) std::cout << "[SR] Error: divisor must be != 0" << std::endl;
return {-1, -1};
}
// libdivide 常数
const uint8_t LIBDIVIDE_ADD_MARKER = 0x40;
const uint8_t LIBDIVIDE_NEGATIVE_DIVISOR = 0x80;
// 辅助函数:计算前导零个数
auto count_leading_zeros32 = [](uint32_t val) -> uint32_t {
if (val == 0) return 32;
return __builtin_clz(val);
};
// 辅助函数64位除法返回32位商和余数
auto div_64_32 = [](uint32_t high, uint32_t low, uint32_t divisor, uint32_t* rem) -> uint32_t {
uint64_t dividend = ((uint64_t)high << 32) | low;
uint32_t quotient = dividend / divisor;
*rem = dividend % divisor;
return quotient;
};
if (DEBUG) {
std::cout << "[SR] Input divisor: " << divisor << std::endl;
}
// libdivide_internal_s32_gen 算法实现
int32_t d = divisor;
uint32_t ud = (uint32_t)d;
uint32_t absD = (d < 0) ? -ud : ud;
if (DEBUG) {
std::cout << "[SR] absD = " << absD << std::endl;
}
uint32_t floor_log_2_d = 31 - count_leading_zeros32(absD);
if (DEBUG) {
std::cout << "[SR] floor_log_2_d = " << floor_log_2_d << std::endl;
}
// 检查 absD 是否为2的幂
if ((absD & (absD - 1)) == 0) {
if (DEBUG) {
std::cout << "[SR] " << absD << " 是2的幂使用移位方法" << std::endl;
}
// 对于2的幂我们只使用移位不需要魔数
int shift = floor_log_2_d;
if (d < 0) shift |= 0x80; // 标记负数
if (DEBUG) {
std::cout << "[SR] Power of 2 result: magic=0, shift=" << shift << std::endl;
std::cout << "[SR] ===== End magic computation =====" << std::endl;
}
// 对于我们的目的我们将在IR生成中以不同方式处理2的幂
// 返回特殊标记
return {0, shift};
}
if (DEBUG) {
std::cout << "[SR] " << absD << " is not a power of 2, computing magic number" << std::endl;
}
// 非2的幂除数的魔数计算
uint8_t more;
uint32_t rem, proposed_m;
// 计算 proposed_m = floor(2^(floor_log_2_d + 31) / absD)
proposed_m = div_64_32((uint32_t)1 << (floor_log_2_d - 1), 0, absD, &rem);
const uint32_t e = absD - rem;
if (DEBUG) {
std::cout << "[SR] proposed_m = " << proposed_m << ", rem = " << rem << ", e = " << e << std::endl;
}
// 确定是否需要"加法"版本
const bool branchfree = false; // 使用分支版本
if (!branchfree && e < ((uint32_t)1 << floor_log_2_d)) {
// 这个幂次有效
more = (uint8_t)(floor_log_2_d - 1);
if (DEBUG) {
std::cout << "[SR] Using basic algorithm, shift = " << (int)more << std::endl;
}
} else {
// 我们需要上升一个等级
proposed_m += proposed_m;
const uint32_t twice_rem = rem + rem;
if (twice_rem >= absD || twice_rem < rem) {
proposed_m += 1;
}
more = (uint8_t)(floor_log_2_d | LIBDIVIDE_ADD_MARKER);
if (DEBUG) {
std::cout << "[SR] Using add algorithm, proposed_m = " << proposed_m << ", more = " << (int)more << std::endl;
}
}
proposed_m += 1;
int32_t magic = (int32_t)proposed_m;
// 处理负除数
if (d < 0) {
more |= LIBDIVIDE_NEGATIVE_DIVISOR;
if (!branchfree) {
magic = -magic;
}
if (DEBUG) {
std::cout << "[SR] Negative divisor, magic = " << magic << ", more = " << (int)more << std::endl;
}
}
// 为我们的IR生成提取移位量和标志
int shift = more & 0x3F; // 移除标志保留移位量位0-5
bool need_add = (more & LIBDIVIDE_ADD_MARKER) != 0;
bool is_negative = (more & LIBDIVIDE_NEGATIVE_DIVISOR) != 0;
if (DEBUG) {
std::cout << "[SR] Final result: magic = " << magic << ", more = " << (int)more
<< " (0x" << std::hex << (int)more << std::dec << ")" << std::endl;
std::cout << "[SR] Shift = " << shift << ", need_add = " << need_add
<< ", is_negative = " << is_negative << std::endl;
// Test the magic number using the correct libdivide algorithm
std::cout << "[SR] Testing magic number (libdivide algorithm):" << std::endl;
int test_values[] = {1, 7, 37, 100, 999, -1, -7, -37, -100};
for (int test_val : test_values) {
int64_t quotient;
// 实现正确的libdivide算法
int64_t product = (int64_t)test_val * magic;
int64_t high_bits = product >> 32;
if (need_add) {
// ADD_MARKER情况移位前加上被除数
// 这是libdivide的关键洞察
high_bits += test_val;
quotient = high_bits >> shift;
} else {
// 正常情况:只是移位
quotient = high_bits >> shift;
}
// 符号修正这是libdivide有符号除法的关键部分
// 如果被除数为负商需要加1来匹配C语言的截断除法语义
if (test_val < 0) {
quotient += 1;
}
int expected = test_val / divisor;
bool correct = (quotient == expected);
std::cout << "[SR] " << test_val << " / " << divisor << " = " << quotient
<< " (expected " << expected << ") " << (correct ? "" : "") << std::endl;
}
std::cout << "[SR] ===== End magic computation =====" << std::endl;
}
// 返回魔数、移位量并在移位中编码ADD_MARKER标志
// 我们将使用移位的第6位表示ADD_MARKER第7位表示负数如果需要
int encoded_shift = shift;
if (need_add) {
encoded_shift |= 0x40; // 设置第6位表示ADD_MARKER
if (DEBUG) {
std::cout << "[SR] Encoding ADD_MARKER in shift: " << encoded_shift << std::endl;
}
}
return {magic, encoded_shift};
}
};
}// namespace sysy

View File

@ -0,0 +1,39 @@
#pragma once
#include "Pass.h"
#include "Dom.h"
#include "Loop.h"
namespace sysy {
/**
* @class TailCallOpt
* @brief 优化尾调用的中端优化通道。
*
* 该类实现了一个针对函数级别的尾调用优化的优化通道OptimizationPass
* 通过分析和转换 IR中间表示将可优化的尾调用转换为更高效的形式
* 以减少函数调用的开销,提升程序性能。
*
* @note 需要传入 IRBuilder 指针用于 IR 构建和修改。
*
* @method runOnFunction
* 对指定函数进行尾调用优化。
*
* @method getPassID
* 获取当前优化通道的唯一标识符。
*
* @method getAnalysisUsage
* 指定该优化通道所依赖和失效的分析集合。
*/
class TailCallOpt : public OptimizationPass {
private:
IRBuilder* builder;
public:
TailCallOpt(IRBuilder* builder) : OptimizationPass("TailCallOpt", Granularity::Function), builder(builder) {}
static void *ID;
bool runOnFunction(Function *F, AnalysisManager &AM) override;
void *getPassID() const override { return &ID; }
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override;
};
} // namespace sysy

View File

@ -15,14 +15,16 @@ add_library(midend_lib STATIC
Pass/Optimize/DCE.cpp
Pass/Optimize/Mem2Reg.cpp
Pass/Optimize/Reg2Mem.cpp
Pass/Optimize/GVN.cpp
Pass/Optimize/SysYIRCFGOpt.cpp
Pass/Optimize/SCCP.cpp
Pass/Optimize/LoopNormalization.cpp
Pass/Optimize/LICM.cpp
Pass/Optimize/LoopStrengthReduction.cpp
Pass/Optimize/InductionVariableElimination.cpp
Pass/Optimize/GlobalStrengthReduction.cpp
Pass/Optimize/BuildCFG.cpp
Pass/Optimize/LargeArrayToGlobal.cpp
Pass/Optimize/TailCallOpt.cpp
)
# 包含中端模块所需的头文件路径

View File

@ -847,7 +847,7 @@ void CondBrInst::print(std::ostream &os) const {
os << "%tmp_cond_" << condName << "_" << uniqueSuffix << " = icmp ne i32 ";
printOperand(os, condition);
os << ", 0\n br i1 %tmp_cond_" << condName << "_" << uniqueSuffix;
os << ", 0\n br i1 %tmp_cond_" << condName << "_" << uniqueSuffix;
os << ", label %";
printBlockName(os, getThenBlock());
@ -886,7 +886,7 @@ void MemsetInst::print(std::ostream &os) const {
// This is done at print time to avoid modifying the IR structure
os << "%tmp_bitcast_" << ptr->getName() << " = bitcast " << *ptr->getType() << " ";
printOperand(os, ptr);
os << " to i8*\n ";
os << " to i8*\n ";
// Now call memset with the bitcast result
os << "call void @llvm.memset.p0i8.i32(i8* %tmp_bitcast_" << ptr->getName() << ", i8 ";

View File

@ -776,38 +776,324 @@ void LoopCharacteristicsPass::findDerivedInductionVars(
}
}
// 递归/推进式判定
bool LoopCharacteristicsPass::isClassicLoopInvariant(Value* val, Loop* loop, const std::unordered_set<Value*>& invariants) {
// 1. 常量
if (auto* constval = dynamic_cast<ConstantValue*>(val)) return true;
// 2. 参数函数参数通常不在任何BasicBlock内直接判定为不变量
if (auto* arg = dynamic_cast<Argument*>(val)) return true;
// 3. 指令且定义在循环外
if (auto* inst = dynamic_cast<Instruction*>(val)) {
if (!loop->contains(inst->getParent()))
return true;
// 4. 跳转 phi指令 副作用 不外提
if (inst->isTerminator() || inst->isPhi() || sideEffectAnalysis->hasSideEffect(inst))
// 检查操作数是否都是不变量
bool LoopCharacteristicsPass::isInvariantOperands(Instruction* inst, Loop* loop, const std::unordered_set<Value*>& invariants) {
for (size_t i = 0; i < inst->getNumOperands(); ++i) {
Value* op = inst->getOperand(i);
if (!isClassicLoopInvariant(op, loop, invariants) && !invariants.count(op)) {
return false;
// 5. 所有操作数都是不变量
for (size_t i = 0; i < inst->getNumOperands(); ++i) {
Value* op = inst->getOperand(i);
if (!isClassicLoopInvariant(op, loop, invariants) && !invariants.count(op))
return false;
}
return true;
}
// 其它情况
return true;
}
// 检查内存位置是否在循环中被修改
bool LoopCharacteristicsPass::isMemoryLocationModifiedInLoop(Value* ptr, Loop* loop) {
// 遍历循环中的所有指令,检查是否有对该内存位置的写入
for (BasicBlock* bb : loop->getBlocks()) {
for (auto& inst : bb->getInstructions()) {
// 1. 检查直接的Store指令
if (auto* storeInst = dynamic_cast<StoreInst*>(inst.get())) {
Value* storeTar = storeInst->getPointer();
// 使用别名分析检查是否可能别名
if (aliasAnalysis) {
auto aliasType = aliasAnalysis->queryAlias(ptr, storeTar);
if (aliasType != AliasType::NO_ALIAS) {
if (DEBUG) {
std::cout << " Memory location " << ptr->getName()
<< " may be modified by store to " << storeTar->getName() << std::endl;
}
return true;
}
} else {
// 如果没有别名分析,保守处理 - 只检查精确匹配
if (ptr == storeTar) {
return true;
}
}
}
// 2. 检查函数调用是否可能修改该内存位置
else if (auto* callInst = dynamic_cast<CallInst*>(inst.get())) {
Function* calledFunc = callInst->getCallee();
// 如果是纯函数,不会修改内存
if (isPureFunction(calledFunc)) {
continue;
}
// 检查函数参数中是否有该内存位置的指针
for (size_t i = 1; i < callInst->getNumOperands(); ++i) { // 跳过函数指针
Value* arg = callInst->getOperand(i);
// 检查参数是否是指针类型且可能指向该内存位置
if (auto* ptrType = dynamic_cast<PointerType*>(arg->getType())) {
// 使用别名分析检查
if (aliasAnalysis) {
auto aliasType = aliasAnalysis->queryAlias(ptr, arg);
if (aliasType != AliasType::NO_ALIAS) {
if (DEBUG) {
std::cout << " Memory location " << ptr->getName()
<< " may be modified by function call " << calledFunc->getName()
<< " through parameter " << arg->getName() << std::endl;
}
return true;
}
} else {
// 没有别名分析,检查精确匹配
if (ptr == arg) {
if (DEBUG) {
std::cout << " Memory location " << ptr->getName()
<< " may be modified by function call " << calledFunc->getName()
<< " (exact match)" << std::endl;
}
return true;
}
}
}
}
}
}
}
return false;
}
bool LoopCharacteristicsPass::hasSimpleMemoryPattern(Loop* loop) {
// 检查是否有简单的内存访问模式
return true; // 暂时简化处理
// 检查内存位置是否在循环中被读取
bool LoopCharacteristicsPass::isMemoryLocationLoadedInLoop(Value* ptr, Loop* loop, Instruction* excludeInst) {
// 遍历循环中的所有Load指令检查是否有对该内存位置的读取
for (BasicBlock* bb : loop->getBlocks()) {
for (auto& inst : bb->getInstructions()) {
if (inst.get() == excludeInst) continue; // 排除当前指令本身
if (auto* loadInst = dynamic_cast<LoadInst*>(inst.get())) {
Value* loadSrc = loadInst->getPointer();
// 使用别名分析检查是否可能别名
if (aliasAnalysis) {
auto aliasType = aliasAnalysis->queryAlias(ptr, loadSrc);
if (aliasType != AliasType::NO_ALIAS) {
return true;
}
} else {
// 如果没有别名分析,保守处理 - 只检查精确匹配
if (ptr == loadSrc) {
return true;
}
}
}
}
}
return false;
}
// 检查函数调用是否为纯函数
bool LoopCharacteristicsPass::isPureFunction(Function* calledFunc) {
if (!calledFunc) return false;
// 使用副作用分析检查函数是否为纯函数
if (sideEffectAnalysis && sideEffectAnalysis->isPureFunction(calledFunc)) {
return true;
}
// 检查是否为内置纯函数(如数学函数)
std::string funcName = calledFunc->getName();
static const std::set<std::string> pureFunctions = {
"abs", "fabs", "sqrt", "sin", "cos", "tan", "exp", "log", "pow",
"floor", "ceil", "round", "min", "max"
};
return pureFunctions.count(funcName) > 0;
}
// 递归/推进式判定 - 完善版本
bool LoopCharacteristicsPass::isClassicLoopInvariant(Value* val, Loop* loop, const std::unordered_set<Value*>& invariants) {
if (DEBUG >= 2) {
std::cout << " Checking loop invariant for: " << val->getName() << std::endl;
}
// 1. 常量
if (auto* constval = dynamic_cast<ConstantValue*>(val)) {
if (DEBUG >= 2) std::cout << " -> Constant: YES" << std::endl;
return true;
}
// 2. 参数函数参数通常不在任何BasicBlock内直接判定为不变量
// 在SSA形式下参数不会被重新赋值
if (auto* arg = dynamic_cast<Argument*>(val)) {
if (DEBUG >= 2) std::cout << " -> Function argument: YES" << std::endl;
return true;
}
// 3. 指令且定义在循环外
if (auto* inst = dynamic_cast<Instruction*>(val)) {
if (!loop->contains(inst->getParent())) {
if (DEBUG >= 2) std::cout << " -> Defined outside loop: YES" << std::endl;
return true;
}
// 4. 跳转指令、phi指令不能外提
if (inst->isTerminator() || inst->isPhi()) {
if (DEBUG >= 2) std::cout << " -> Terminator or PHI: NO" << std::endl;
return false;
}
// 5. 根据指令类型进行具体分析
switch (inst->getKind()) {
case Instruction::Kind::kStore: {
// Store指令检查循环内是否有对该内存的load
auto* storeInst = dynamic_cast<StoreInst*>(inst);
Value* storePtr = storeInst->getPointer();
// 首先检查操作数是否不变
if (!isInvariantOperands(inst, loop, invariants)) {
if (DEBUG >= 2) std::cout << " -> Store: operands not invariant: NO" << std::endl;
return false;
}
// 检查是否有对该内存位置的load
if (isMemoryLocationLoadedInLoop(storePtr, loop, inst)) {
if (DEBUG >= 2) std::cout << " -> Store: memory location loaded in loop: NO" << std::endl;
return false;
}
if (DEBUG >= 2) std::cout << " -> Store: safe to hoist: YES" << std::endl;
return true;
}
case Instruction::Kind::kLoad: {
// Load指令检查循环内是否有对该内存的store
auto* loadInst = dynamic_cast<LoadInst*>(inst);
Value* loadPtr = loadInst->getPointer();
// 首先检查指针操作数是否不变
if (!isInvariantOperands(inst, loop, invariants)) {
if (DEBUG >= 2) std::cout << " -> Load: pointer not invariant: NO" << std::endl;
return false;
}
// 检查是否有对该内存位置的store
if (isMemoryLocationModifiedInLoop(loadPtr, loop)) {
if (DEBUG >= 2) std::cout << " -> Load: memory location modified in loop: NO" << std::endl;
return false;
}
if (DEBUG >= 2) std::cout << " -> Load: safe to hoist: YES" << std::endl;
return true;
}
case Instruction::Kind::kCall: {
// Call指令检查是否为纯函数且参数不变
auto* callInst = dynamic_cast<CallInst*>(inst);
Function* calledFunc = callInst->getCallee();
// 检查是否为纯函数
if (!isPureFunction(calledFunc)) {
if (DEBUG >= 2) std::cout << " -> Call: not pure function: NO" << std::endl;
return false;
}
// 检查参数是否都不变
if (!isInvariantOperands(inst, loop, invariants)) {
if (DEBUG >= 2) std::cout << " -> Call: arguments not invariant: NO" << std::endl;
return false;
}
if (DEBUG >= 2) std::cout << " -> Call: pure function with invariant args: YES" << std::endl;
return true;
}
case Instruction::Kind::kGetElementPtr: {
// GEP指令检查基址和索引是否都不变
if (!isInvariantOperands(inst, loop, invariants)) {
if (DEBUG >= 2) std::cout << " -> GEP: base or indices not invariant: NO" << std::endl;
return false;
}
if (DEBUG >= 2) std::cout << " -> GEP: base and indices invariant: YES" << std::endl;
return true;
}
// 一元运算指令
case Instruction::Kind::kNeg:
case Instruction::Kind::kNot:
case Instruction::Kind::kFNeg:
case Instruction::Kind::kFNot:
case Instruction::Kind::kFtoI:
case Instruction::Kind::kItoF:
case Instruction::Kind::kBitItoF:
case Instruction::Kind::kBitFtoI: {
// 检查操作数是否不变
if (!isInvariantOperands(inst, loop, invariants)) {
if (DEBUG >= 2) std::cout << " -> Unary op: operand not invariant: NO" << std::endl;
return false;
}
if (DEBUG >= 2) std::cout << " -> Unary op: operand invariant: YES" << std::endl;
return true;
}
// 二元运算指令
case Instruction::Kind::kAdd:
case Instruction::Kind::kSub:
case Instruction::Kind::kMul:
case Instruction::Kind::kDiv:
case Instruction::Kind::kRem:
case Instruction::Kind::kSll:
case Instruction::Kind::kSrl:
case Instruction::Kind::kSra:
case Instruction::Kind::kAnd:
case Instruction::Kind::kOr:
case Instruction::Kind::kFAdd:
case Instruction::Kind::kFSub:
case Instruction::Kind::kFMul:
case Instruction::Kind::kFDiv:
case Instruction::Kind::kICmpEQ:
case Instruction::Kind::kICmpNE:
case Instruction::Kind::kICmpLT:
case Instruction::Kind::kICmpGT:
case Instruction::Kind::kICmpLE:
case Instruction::Kind::kICmpGE:
case Instruction::Kind::kFCmpEQ:
case Instruction::Kind::kFCmpNE:
case Instruction::Kind::kFCmpLT:
case Instruction::Kind::kFCmpGT:
case Instruction::Kind::kFCmpLE:
case Instruction::Kind::kFCmpGE:
case Instruction::Kind::kMulh: {
// 检查所有操作数是否不变
if (!isInvariantOperands(inst, loop, invariants)) {
if (DEBUG >= 2) std::cout << " -> Binary op: operands not invariant: NO" << std::endl;
return false;
}
if (DEBUG >= 2) std::cout << " -> Binary op: operands invariant: YES" << std::endl;
return true;
}
default: {
// 其他指令:使用副作用分析
if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(inst)) {
if (DEBUG >= 2) std::cout << " -> Other inst: has side effect: NO" << std::endl;
return false;
}
// 检查操作数是否都不变
if (!isInvariantOperands(inst, loop, invariants)) {
if (DEBUG >= 2) std::cout << " -> Other inst: operands not invariant: NO" << std::endl;
return false;
}
if (DEBUG >= 2) std::cout << " -> Other inst: no side effect, operands invariant: YES" << std::endl;
return true;
}
}
}
// 其它情况
if (DEBUG >= 2) std::cout << " -> Other value type: NO" << std::endl;
return false;
}
} // namespace sysy

View File

@ -26,10 +26,21 @@ const SideEffectInfo &SideEffectAnalysisResult::getInstructionSideEffect(Instruc
}
const SideEffectInfo &SideEffectAnalysisResult::getFunctionSideEffect(Function *func) const {
// 首先检查分析过的用户定义函数
auto it = functionSideEffects.find(func);
if (it != functionSideEffects.end()) {
return it->second;
}
// 如果没有找到,检查是否为已知的库函数
if (func) {
std::string funcName = func->getName();
const SideEffectInfo *knownInfo = getKnownFunctionSideEffect(funcName);
if (knownInfo) {
return *knownInfo;
}
}
// 返回默认的无副作用信息
static SideEffectInfo noEffect;
return noEffect;

View File

@ -0,0 +1,492 @@
#include "GVN.h"
#include "Dom.h"
#include "SysYIROptUtils.h"
#include <algorithm>
#include <cassert>
#include <iostream>
#include <unordered_map>
#include <unordered_set>
extern int DEBUG;
namespace sysy {
// GVN 遍的静态 ID
void *GVN::ID = (void *)&GVN::ID;
// ======================================================================
// GVN 类的实现
// ======================================================================
bool GVN::runOnFunction(Function *func, AnalysisManager &AM) {
if (func->getBasicBlocks().empty()) {
return false;
}
if (DEBUG) {
std::cout << "\n=== Running GVN on function: " << func->getName() << " ===" << std::endl;
}
bool changed = false;
GVNContext context;
context.run(func, &AM, changed);
if (DEBUG) {
if (changed) {
std::cout << "GVN: Function " << func->getName() << " was modified" << std::endl;
} else {
std::cout << "GVN: Function " << func->getName() << " was not modified" << std::endl;
}
std::cout << "=== GVN completed for function: " << func->getName() << " ===" << std::endl;
}
return changed;
}
void GVN::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
// GVN依赖以下分析
// 1. 支配树分析 - 用于检查指令的支配关系,确保替换的安全性
analysisDependencies.insert(&DominatorTreeAnalysisPass::ID);
// 2. 副作用分析 - 用于判断函数调用是否可以进行GVN
analysisDependencies.insert(&SysYSideEffectAnalysisPass::ID);
// GVN不会使任何分析失效因为
// - GVN只删除冗余计算不改变CFG结构
// - GVN不修改程序的语义只是消除重复计算
// - 支配关系保持不变
// - 副作用分析结果保持不变
// analysisInvalidations 保持为空
if (DEBUG) {
std::cout << "GVN: Declared analysis dependencies (DominatorTree, SideEffectAnalysis)" << std::endl;
}
}
// ======================================================================
// GVNContext 类的实现 - 重构版本
// ======================================================================
// 简单的表达式哈希结构
struct ExpressionKey {
enum Type { BINARY, UNARY, LOAD, GEP, CALL } type;
int opcode;
std::vector<Value*> operands;
Type* resultType;
bool operator==(const ExpressionKey& other) const {
return type == other.type && opcode == other.opcode &&
operands == other.operands && resultType == other.resultType;
}
};
struct ExpressionKeyHash {
size_t operator()(const ExpressionKey& key) const {
size_t hash = std::hash<int>()(static_cast<int>(key.type)) ^
std::hash<int>()(key.opcode);
for (auto op : key.operands) {
hash ^= std::hash<Value*>()(op) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
}
return hash;
}
};
void GVNContext::run(Function *func, AnalysisManager *AM, bool &changed) {
if (DEBUG) {
std::cout << " Starting GVN analysis for function: " << func->getName() << std::endl;
}
// 获取分析结果
if (AM) {
domTree = AM->getAnalysisResult<DominatorTree, DominatorTreeAnalysisPass>(func);
sideEffectAnalysis = AM->getAnalysisResult<SideEffectAnalysisResult, SysYSideEffectAnalysisPass>();
if (DEBUG) {
if (domTree) {
std::cout << " GVN: Using dominator tree analysis" << std::endl;
} else {
std::cout << " GVN: Warning - dominator tree analysis not available" << std::endl;
}
if (sideEffectAnalysis) {
std::cout << " GVN: Using side effect analysis" << std::endl;
} else {
std::cout << " GVN: Warning - side effect analysis not available" << std::endl;
}
}
}
// 清空状态
valueToNumber.clear();
numberToValue.clear();
expressionToNumber.clear();
nextValueNumber = 1;
visited.clear();
rpoBlocks.clear();
needRemove.clear();
// 计算逆后序遍历
computeRPO(func);
if (DEBUG) {
std::cout << " Computed RPO with " << rpoBlocks.size() << " blocks" << std::endl;
}
// 按逆后序遍历基本块进行GVN
int blockCount = 0;
for (auto bb : rpoBlocks) {
if (DEBUG) {
std::cout << " Processing block " << ++blockCount << "/" << rpoBlocks.size()
<< ": " << bb->getName() << std::endl;
}
processBasicBlock(bb, changed);
}
if (DEBUG) {
std::cout << " Found " << needRemove.size() << " redundant instructions to remove" << std::endl;
}
// 删除冗余指令
eliminateRedundantInstructions(changed);
if (DEBUG) {
std::cout << " GVN analysis completed for function: " << func->getName() << std::endl;
std::cout << " Total values numbered: " << valueToNumber.size() << std::endl;
std::cout << " Instructions eliminated: " << needRemove.size() << std::endl;
}
}
void GVNContext::computeRPO(Function *func) {
rpoBlocks.clear();
visited.clear();
auto entry = func->getEntryBlock();
if (entry) {
dfs(entry);
std::reverse(rpoBlocks.begin(), rpoBlocks.end());
}
}
void GVNContext::dfs(BasicBlock *bb) {
if (!bb || visited.count(bb)) {
return;
}
visited.insert(bb);
// 访问所有后继基本块
for (auto succ : bb->getSuccessors()) {
if (visited.find(succ) == visited.end()) {
dfs(succ);
}
}
rpoBlocks.push_back(bb);
}
unsigned GVNContext::getValueNumber(Value* value) {
// 如果已经有值编号,直接返回
auto it = valueToNumber.find(value);
if (it != valueToNumber.end()) {
return it->second;
}
// 为新值分配编号
return assignValueNumber(value);
}
unsigned GVNContext::assignValueNumber(Value* value) {
unsigned number = nextValueNumber++;
valueToNumber[value] = number;
numberToValue[number] = value;
if (DEBUG >= 2) {
std::cout << " Assigned value number " << number
<< " to " << value->getName() << std::endl;
}
return number;
}
void GVNContext::processBasicBlock(BasicBlock* bb, bool& changed) {
int instCount = 0;
for (auto &instPtr : bb->getInstructions()) {
if (DEBUG) {
std::cout << " Processing instruction " << ++instCount
<< ": " << instPtr->getName() << std::endl;
}
if (processInstruction(instPtr.get())) {
changed = true;
}
}
}
bool GVNContext::processInstruction(Instruction* inst) {
// 跳过分支指令和其他不可优化的指令
if (inst->isBranch() || dynamic_cast<ReturnInst*>(inst) ||
dynamic_cast<AllocaInst*>(inst) || dynamic_cast<StoreInst*>(inst)) {
// 如果是store指令需要使相关的内存值失效
if (auto store = dynamic_cast<StoreInst*>(inst)) {
invalidateMemoryValues(store);
}
// 为这些指令分配值编号但不尝试优化
getValueNumber(inst);
return false;
}
if (DEBUG) {
std::cout << " Processing optimizable instruction: " << inst->getName()
<< " (kind: " << static_cast<int>(inst->getKind()) << ")" << std::endl;
}
// 构建表达式键
std::string exprKey = buildExpressionKey(inst);
if (exprKey.empty()) {
// 不可优化的指令,只分配值编号
getValueNumber(inst);
return false;
}
if (DEBUG >= 2) {
std::cout << " Expression key: " << exprKey << std::endl;
}
// 查找已存在的等价值
Value* existing = findExistingValue(exprKey, inst);
if (existing && existing != inst) {
// 检查支配关系
if (auto existingInst = dynamic_cast<Instruction*>(existing)) {
if (dominates(existingInst, inst)) {
if (DEBUG) {
std::cout << " GVN: Replacing " << inst->getName()
<< " with existing " << existing->getName() << std::endl;
}
// 用已存在的值替换当前指令
inst->replaceAllUsesWith(existing);
needRemove.insert(inst);
// 将当前指令的值编号指向已存在的值
unsigned existingNumber = getValueNumber(existing);
valueToNumber[inst] = existingNumber;
return true;
} else {
if (DEBUG) {
std::cout << " Found equivalent but dominance check failed" << std::endl;
}
}
}
}
// 没有找到等价值,为这个表达式分配新的值编号
unsigned number = assignValueNumber(inst);
expressionToNumber[exprKey] = number;
if (DEBUG) {
std::cout << " Instruction " << inst->getName() << " is unique" << std::endl;
}
return false;
}
std::string GVNContext::buildExpressionKey(Instruction* inst) {
std::ostringstream oss;
if (auto binary = dynamic_cast<BinaryInst*>(inst)) {
oss << "binary_" << static_cast<int>(binary->getKind()) << "_";
oss << getValueNumber(binary->getLhs()) << "_" << getValueNumber(binary->getRhs());
// 对于可交换操作,确保操作数顺序一致
if (binary->isCommutative()) {
unsigned lhsNum = getValueNumber(binary->getLhs());
unsigned rhsNum = getValueNumber(binary->getRhs());
if (lhsNum > rhsNum) {
oss.str("");
oss << "binary_" << static_cast<int>(binary->getKind()) << "_";
oss << rhsNum << "_" << lhsNum;
}
}
} else if (auto unary = dynamic_cast<UnaryInst*>(inst)) {
oss << "unary_" << static_cast<int>(unary->getKind()) << "_";
oss << getValueNumber(unary->getOperand());
} else if (auto gep = dynamic_cast<GetElementPtrInst*>(inst)) {
oss << "gep_" << getValueNumber(gep->getBasePointer());
for (unsigned i = 0; i < gep->getNumIndices(); ++i) {
oss << "_" << getValueNumber(gep->getIndex(i));
}
} else if (auto load = dynamic_cast<LoadInst*>(inst)) {
oss << "load_" << getValueNumber(load->getPointer());
oss << "_" << reinterpret_cast<uintptr_t>(load->getType()); // 类型区分
} else if (auto call = dynamic_cast<CallInst*>(inst)) {
// 只为无副作用的函数调用建立表达式
if (sideEffectAnalysis && sideEffectAnalysis->isPureFunction(call->getCallee())) {
oss << "call_" << call->getCallee()->getName();
for (size_t i = 1; i < call->getNumOperands(); ++i) { // 跳过函数指针
oss << "_" << getValueNumber(call->getOperand(i));
}
} else {
return ""; // 有副作用的函数调用不可优化
}
} else {
return ""; // 不支持的指令类型
}
return oss.str();
}
Value* GVNContext::findExistingValue(const std::string& exprKey, Instruction* inst) {
auto it = expressionToNumber.find(exprKey);
if (it != expressionToNumber.end()) {
unsigned number = it->second;
auto valueIt = numberToValue.find(number);
if (valueIt != numberToValue.end()) {
Value* existing = valueIt->second;
// 对于load指令需要额外检查内存安全性
if (auto loadInst = dynamic_cast<LoadInst*>(inst)) {
if (auto existingLoad = dynamic_cast<LoadInst*>(existing)) {
if (!isMemorySafe(existingLoad, loadInst)) {
return nullptr;
}
}
}
return existing;
}
}
return nullptr;
}
bool GVNContext::dominates(Instruction* a, Instruction* b) {
auto aBB = a->getParent();
auto bBB = b->getParent();
// 同一基本块内的情况
if (aBB == bBB) {
auto &insts = aBB->getInstructions();
auto aIt = std::find_if(insts.begin(), insts.end(),
[a](const auto &ptr) { return ptr.get() == a; });
auto bIt = std::find_if(insts.begin(), insts.end(),
[b](const auto &ptr) { return ptr.get() == b; });
if (aIt == insts.end() || bIt == insts.end()) {
return false;
}
return std::distance(insts.begin(), aIt) < std::distance(insts.begin(), bIt);
}
// 不同基本块的情况,使用支配树
if (domTree) {
auto dominators = domTree->getDominators(bBB);
return dominators && dominators->count(aBB);
}
return false; // 保守做法
}
bool GVNContext::isMemorySafe(LoadInst* earlierLoad, LoadInst* laterLoad) {
// 检查两个load是否访问相同的内存位置
unsigned earlierPtr = getValueNumber(earlierLoad->getPointer());
unsigned laterPtr = getValueNumber(laterLoad->getPointer());
if (earlierPtr != laterPtr) {
return false; // 不同的内存位置
}
// 检查类型是否匹配
if (earlierLoad->getType() != laterLoad->getType()) {
return false;
}
// 简单情况如果在同一个基本块且没有中间的store则安全
auto earlierBB = earlierLoad->getParent();
auto laterBB = laterLoad->getParent();
if (earlierBB != laterBB) {
// 跨基本块的情况需要更复杂的分析,暂时保守处理
return false;
}
// 同一基本块内检查是否有中间的store
auto &insts = earlierBB->getInstructions();
auto earlierIt = std::find_if(insts.begin(), insts.end(),
[earlierLoad](const auto &ptr) { return ptr.get() == earlierLoad; });
auto laterIt = std::find_if(insts.begin(), insts.end(),
[laterLoad](const auto &ptr) { return ptr.get() == laterLoad; });
if (earlierIt == insts.end() || laterIt == insts.end()) {
return false;
}
// 确保earlierLoad真的在laterLoad之前
if (std::distance(insts.begin(), earlierIt) >= std::distance(insts.begin(), laterIt)) {
return false;
}
// 检查中间是否有store指令修改了相同的内存位置
for (auto it = std::next(earlierIt); it != laterIt; ++it) {
if (auto store = dynamic_cast<StoreInst*>(it->get())) {
unsigned storePtr = getValueNumber(store->getPointer());
if (storePtr == earlierPtr) {
return false; // 找到中间的store
}
}
// 检查函数调用是否可能修改内存
if (auto call = dynamic_cast<CallInst*>(it->get())) {
if (sideEffectAnalysis && !sideEffectAnalysis->isPureFunction(call->getCallee())) {
// 保守处理:有副作用的函数可能修改内存
return false;
}
}
}
return true; // 安全
}
void GVNContext::invalidateMemoryValues(StoreInst* store) {
unsigned storePtr = getValueNumber(store->getPointer());
if (DEBUG) {
std::cout << " Invalidating memory values affected by store" << std::endl;
}
// 找到所有可能被这个store影响的load表达式
std::vector<std::string> toRemove;
for (auto& [exprKey, number] : expressionToNumber) {
if (exprKey.find("load_" + std::to_string(storePtr)) == 0) {
toRemove.push_back(exprKey);
if (DEBUG) {
std::cout << " Invalidating expression: " << exprKey << std::endl;
}
}
}
// 移除失效的表达式
for (const auto& key : toRemove) {
expressionToNumber.erase(key);
}
}
void GVNContext::eliminateRedundantInstructions(bool& changed) {
int removeCount = 0;
for (auto inst : needRemove) {
if (DEBUG) {
std::cout << " Removing redundant instruction " << ++removeCount
<< "/" << needRemove.size() << ": " << inst->getName() << std::endl;
}
// 删除指令前先断开所有使用关系
// inst->replaceAllUsesWith 已在 processInstruction 中调用
SysYIROptUtils::usedelete(inst);
changed = true;
}
}
} // namespace sysy

View File

@ -0,0 +1,897 @@
#include "GlobalStrengthReduction.h"
#include "SysYIROptUtils.h"
#include "IRBuilder.h"
#include <algorithm>
#include <cassert>
#include <iostream>
#include <cmath>
extern int DEBUG;
namespace sysy {
// 全局强度削弱优化遍的静态 ID
void *GlobalStrengthReduction::ID = (void *)&GlobalStrengthReduction::ID;
// ======================================================================
// GlobalStrengthReduction 类的实现
// ======================================================================
bool GlobalStrengthReduction::runOnFunction(Function *func, AnalysisManager &AM) {
if (func->getBasicBlocks().empty()) {
return false;
}
if (DEBUG) {
std::cout << "\n=== Running GlobalStrengthReduction on function: " << func->getName() << " ===" << std::endl;
}
bool changed = false;
GlobalStrengthReductionContext context(builder);
context.run(func, &AM, changed);
if (DEBUG) {
if (changed) {
std::cout << "GlobalStrengthReduction: Function " << func->getName() << " was modified" << std::endl;
} else {
std::cout << "GlobalStrengthReduction: Function " << func->getName() << " was not modified" << std::endl;
}
std::cout << "=== GlobalStrengthReduction completed for function: " << func->getName() << " ===" << std::endl;
}
return changed;
}
void GlobalStrengthReduction::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
// 强度削弱依赖副作用分析来判断指令是否可以安全优化
analysisDependencies.insert(&SysYSideEffectAnalysisPass::ID);
// 强度削弱不会使分析失效,因为:
// - 只替换计算指令,不改变控制流
// - 不修改内存,不影响别名分析
// - 保持程序语义不变
// analysisInvalidations 保持为空
if (DEBUG) {
std::cout << "GlobalStrengthReduction: Declared analysis dependencies (SideEffectAnalysis)" << std::endl;
}
}
// ======================================================================
// GlobalStrengthReductionContext 类的实现
// ======================================================================
void GlobalStrengthReductionContext::run(Function *func, AnalysisManager *AM, bool &changed) {
if (DEBUG) {
std::cout << " Starting GlobalStrengthReduction analysis for function: " << func->getName() << std::endl;
}
// 获取分析结果
if (AM) {
sideEffectAnalysis = AM->getAnalysisResult<SideEffectAnalysisResult, SysYSideEffectAnalysisPass>();
if (DEBUG) {
if (sideEffectAnalysis) {
std::cout << " GlobalStrengthReduction: Using side effect analysis" << std::endl;
} else {
std::cout << " GlobalStrengthReduction: Warning - side effect analysis not available" << std::endl;
}
}
}
// 重置计数器
algebraicOptCount = 0;
strengthReductionCount = 0;
divisionOptCount = 0;
// 遍历所有基本块进行优化
for (auto &bb_ptr : func->getBasicBlocks()) {
if (processBasicBlock(bb_ptr.get())) {
changed = true;
}
}
if (DEBUG) {
std::cout << " GlobalStrengthReduction completed for function: " << func->getName() << std::endl;
std::cout << " Algebraic optimizations: " << algebraicOptCount << std::endl;
std::cout << " Strength reductions: " << strengthReductionCount << std::endl;
std::cout << " Division optimizations: " << divisionOptCount << std::endl;
}
}
bool GlobalStrengthReductionContext::processBasicBlock(BasicBlock *bb) {
bool changed = false;
if (DEBUG) {
std::cout << " Processing block: " << bb->getName() << std::endl;
}
// 收集需要处理的指令(避免迭代器失效)
std::vector<Instruction*> instructions;
for (auto &inst_ptr : bb->getInstructions()) {
instructions.push_back(inst_ptr.get());
}
// 处理每条指令
for (auto inst : instructions) {
if (processInstruction(inst)) {
changed = true;
}
}
return changed;
}
bool GlobalStrengthReductionContext::processInstruction(Instruction *inst) {
if (DEBUG) {
std::cout << " Processing instruction: " << inst->getName() << std::endl;
}
// 先尝试代数优化
if (tryAlgebraicOptimization(inst)) {
algebraicOptCount++;
return true;
}
// 再尝试强度削弱
if (tryStrengthReduction(inst)) {
strengthReductionCount++;
return true;
}
return false;
}
// ======================================================================
// 代数优化方法
// ======================================================================
bool GlobalStrengthReductionContext::tryAlgebraicOptimization(Instruction *inst) {
auto binary = dynamic_cast<BinaryInst*>(inst);
if (!binary) {
return false;
}
switch (binary->getKind()) {
case Instruction::kAdd:
return optimizeAddition(binary);
case Instruction::kSub:
return optimizeSubtraction(binary);
case Instruction::kMul:
return optimizeMultiplication(binary);
case Instruction::kDiv:
return optimizeDivision(binary);
case Instruction::kICmpEQ:
case Instruction::kICmpNE:
case Instruction::kICmpLT:
case Instruction::kICmpGT:
case Instruction::kICmpLE:
case Instruction::kICmpGE:
return optimizeComparison(binary);
case Instruction::kAnd:
case Instruction::kOr:
return optimizeLogical(binary);
default:
return false;
}
}
bool GlobalStrengthReductionContext::optimizeAddition(BinaryInst *inst) {
Value *lhs = inst->getLhs();
Value *rhs = inst->getRhs();
int constVal;
// x + 0 = x
if (isConstantInt(rhs, constVal) && constVal == 0) {
if (DEBUG) {
std::cout << " Algebraic: " << inst->getName() << " = x + 0 -> x" << std::endl;
}
replaceWithOptimized(inst, lhs);
return true;
}
// 0 + x = x
if (isConstantInt(lhs, constVal) && constVal == 0) {
if (DEBUG) {
std::cout << " Algebraic: " << inst->getName() << " = 0 + x -> x" << std::endl;
}
replaceWithOptimized(inst, rhs);
return true;
}
// x + (-y) = x - y
if (auto rhsInst = dynamic_cast<UnaryInst*>(rhs)) {
if (rhsInst->getKind() == Instruction::kNeg) {
if (DEBUG) {
std::cout << " Algebraic: " << inst->getName() << " = x + (-y) -> x - y" << std::endl;
}
// 创建减法指令
builder->setPosition(inst->getParent(), inst->getParent()->findInstIterator(inst));
auto subInst = builder->createSubInst(lhs, rhsInst->getOperand());
replaceWithOptimized(inst, subInst);
return true;
}
}
return false;
}
bool GlobalStrengthReductionContext::optimizeSubtraction(BinaryInst *inst) {
Value *lhs = inst->getLhs();
Value *rhs = inst->getRhs();
int constVal;
// x - 0 = x
if (isConstantInt(rhs, constVal) && constVal == 0) {
if (DEBUG) {
std::cout << " Algebraic: " << inst->getName() << " = x - 0 -> x" << std::endl;
}
replaceWithOptimized(inst, lhs);
return true;
}
// x - x = 0 (如果x没有副作用)
if (lhs == rhs && hasOnlyLocalUses(dynamic_cast<Instruction*>(lhs))) {
if (DEBUG) {
std::cout << " Algebraic: " << inst->getName() << " = x - x -> 0" << std::endl;
}
replaceWithOptimized(inst, getConstantInt(0));
return true;
}
// x - (-y) = x + y
if (auto rhsInst = dynamic_cast<UnaryInst*>(rhs)) {
if (rhsInst->getKind() == Instruction::kNeg) {
if (DEBUG) {
std::cout << " Algebraic: " << inst->getName() << " = x - (-y) -> x + y" << std::endl;
}
builder->setPosition(inst->getParent(), inst->getParent()->findInstIterator(inst));
auto addInst = builder->createAddInst(lhs, rhsInst->getOperand());
replaceWithOptimized(inst, addInst);
return true;
}
}
return false;
}
bool GlobalStrengthReductionContext::optimizeMultiplication(BinaryInst *inst) {
Value *lhs = inst->getLhs();
Value *rhs = inst->getRhs();
int constVal;
// x * 0 = 0
if (isConstantInt(rhs, constVal) && constVal == 0) {
if (DEBUG) {
std::cout << " Algebraic: " << inst->getName() << " = x * 0 -> 0" << std::endl;
}
replaceWithOptimized(inst, getConstantInt(0));
return true;
}
// 0 * x = 0
if (isConstantInt(lhs, constVal) && constVal == 0) {
if (DEBUG) {
std::cout << " Algebraic: " << inst->getName() << " = 0 * x -> 0" << std::endl;
}
replaceWithOptimized(inst, getConstantInt(0));
return true;
}
// x * 1 = x
if (isConstantInt(rhs, constVal) && constVal == 1) {
if (DEBUG) {
std::cout << " Algebraic: " << inst->getName() << " = x * 1 -> x" << std::endl;
}
replaceWithOptimized(inst, lhs);
return true;
}
// 1 * x = x
if (isConstantInt(lhs, constVal) && constVal == 1) {
if (DEBUG) {
std::cout << " Algebraic: " << inst->getName() << " = 1 * x -> x" << std::endl;
}
replaceWithOptimized(inst, rhs);
return true;
}
// x * (-1) = -x
if (isConstantInt(rhs, constVal) && constVal == -1) {
if (DEBUG) {
std::cout << " Algebraic: " << inst->getName() << " = x * (-1) -> -x" << std::endl;
}
builder->setPosition(inst->getParent(), inst->getParent()->findInstIterator(inst));
auto negInst = builder->createNegInst(lhs);
replaceWithOptimized(inst, negInst);
return true;
}
return false;
}
bool GlobalStrengthReductionContext::optimizeDivision(BinaryInst *inst) {
Value *lhs = inst->getLhs();
Value *rhs = inst->getRhs();
int constVal;
// x / 1 = x
if (isConstantInt(rhs, constVal) && constVal == 1) {
if (DEBUG) {
std::cout << " Algebraic: " << inst->getName() << " = x / 1 -> x" << std::endl;
}
replaceWithOptimized(inst, lhs);
return true;
}
// x / (-1) = -x
if (isConstantInt(rhs, constVal) && constVal == -1) {
if (DEBUG) {
std::cout << " Algebraic: " << inst->getName() << " = x / (-1) -> -x" << std::endl;
}
builder->setPosition(inst->getParent(), inst->getParent()->findInstIterator(inst));
auto negInst = builder->createNegInst(lhs);
replaceWithOptimized(inst, negInst);
return true;
}
// x / x = 1 (如果x != 0且没有副作用)
if (lhs == rhs && hasOnlyLocalUses(dynamic_cast<Instruction*>(lhs))) {
if (DEBUG) {
std::cout << " Algebraic: " << inst->getName() << " = x / x -> 1" << std::endl;
}
replaceWithOptimized(inst, getConstantInt(1));
return true;
}
return false;
}
bool GlobalStrengthReductionContext::optimizeComparison(BinaryInst *inst) {
Value *lhs = inst->getLhs();
Value *rhs = inst->getRhs();
// x == x = true (如果x没有副作用)
if (inst->getKind() == Instruction::kICmpEQ && lhs == rhs &&
hasOnlyLocalUses(dynamic_cast<Instruction*>(lhs))) {
if (DEBUG) {
std::cout << " Algebraic: " << inst->getName() << " = x == x -> true" << std::endl;
}
replaceWithOptimized(inst, getConstantInt(1));
return true;
}
// x != x = false (如果x没有副作用)
if (inst->getKind() == Instruction::kICmpNE && lhs == rhs &&
hasOnlyLocalUses(dynamic_cast<Instruction*>(lhs))) {
if (DEBUG) {
std::cout << " Algebraic: " << inst->getName() << " = x != x -> false" << std::endl;
}
replaceWithOptimized(inst, getConstantInt(0));
return true;
}
return false;
}
bool GlobalStrengthReductionContext::optimizeLogical(BinaryInst *inst) {
Value *lhs = inst->getLhs();
Value *rhs = inst->getRhs();
int constVal;
if (inst->getKind() == Instruction::kAnd) {
// x && 0 = 0
if (isConstantInt(rhs, constVal) && constVal == 0) {
if (DEBUG) {
std::cout << " Algebraic: " << inst->getName() << " = x && 0 -> 0" << std::endl;
}
replaceWithOptimized(inst, getConstantInt(0));
return true;
}
// x && -1 = x
if (isConstantInt(rhs, constVal) && constVal == -1) {
if (DEBUG) {
std::cout << " Algebraic: " << inst->getName() << " = x && 1 -> x" << std::endl;
}
replaceWithOptimized(inst, lhs);
return true;
}
// x && x = x
if (lhs == rhs) {
if (DEBUG) {
std::cout << " Algebraic: " << inst->getName() << " = x && x -> x" << std::endl;
}
replaceWithOptimized(inst, lhs);
return true;
}
} else if (inst->getKind() == Instruction::kOr) {
// x || 0 = x
if (isConstantInt(rhs, constVal) && constVal == 0) {
if (DEBUG) {
std::cout << " Algebraic: " << inst->getName() << " = x || 0 -> x" << std::endl;
}
replaceWithOptimized(inst, lhs);
return true;
}
// x || x = x
if (lhs == rhs) {
if (DEBUG) {
std::cout << " Algebraic: " << inst->getName() << " = x || x -> x" << std::endl;
}
replaceWithOptimized(inst, lhs);
return true;
}
}
return false;
}
// ======================================================================
// 强度削弱方法
// ======================================================================
bool GlobalStrengthReductionContext::tryStrengthReduction(Instruction *inst) {
if (auto binary = dynamic_cast<BinaryInst*>(inst)) {
switch (binary->getKind()) {
case Instruction::kMul:
return reduceMultiplication(binary);
case Instruction::kDiv:
return reduceDivision(binary);
default:
return false;
}
} else if (auto call = dynamic_cast<CallInst*>(inst)) {
return reducePower(call);
}
return false;
}
bool GlobalStrengthReductionContext::reduceMultiplication(BinaryInst *inst) {
Value *lhs = inst->getLhs();
Value *rhs = inst->getRhs();
int constVal;
// 尝试右操作数为常数
Value* variable = lhs;
if (isConstantInt(rhs, constVal) && constVal > 0) {
return tryComplexMultiplication(inst, variable, constVal);
}
// 尝试左操作数为常数
if (isConstantInt(lhs, constVal) && constVal > 0) {
variable = rhs;
return tryComplexMultiplication(inst, variable, constVal);
}
return false;
}
bool GlobalStrengthReductionContext::tryComplexMultiplication(BinaryInst* inst, Value* variable, int constant) {
// 首先检查是否为2的幂使用简单位移
if (isPowerOfTwo(constant)) {
int shiftAmount = log2OfPowerOfTwo(constant);
if (DEBUG) {
std::cout << " StrengthReduction: " << inst->getName()
<< " = x * " << constant << " -> x << " << shiftAmount << std::endl;
}
builder->setPosition(inst->getParent(), inst->getParent()->findInstIterator(inst));
auto shiftInst = builder->createBinaryInst(Instruction::kSll, Type::getIntType(), variable, getConstantInt(shiftAmount));
replaceWithOptimized(inst, shiftInst);
return true;
}
// 尝试分解为位移和加法的组合
std::vector<int> shifts;
if (findOptimalShiftDecomposition(constant, shifts)) {
if (DEBUG) {
std::cout << " StrengthReduction: " << inst->getName()
<< " = x * " << constant << " -> shift decomposition with " << shifts.size() << " terms" << std::endl;
}
Value* result = createShiftDecomposition(inst, variable, shifts);
if (result) {
replaceWithOptimized(inst, result);
return true;
}
}
return false;
}
bool GlobalStrengthReductionContext::findOptimalShiftDecomposition(int constant, std::vector<int>& shifts) {
shifts.clear();
// 常见的有效分解模式
switch (constant) {
case 3: // 3 = 2^1 + 2^0 -> (x << 1) + x
shifts = {1, 0};
return true;
case 5: // 5 = 2^2 + 2^0 -> (x << 2) + x
shifts = {2, 0};
return true;
case 6: // 6 = 2^2 + 2^1 -> (x << 2) + (x << 1)
shifts = {2, 1};
return true;
case 7: // 7 = 2^2 + 2^1 + 2^0 -> (x << 2) + (x << 1) + x
shifts = {2, 1, 0};
return true;
case 9: // 9 = 2^3 + 2^0 -> (x << 3) + x
shifts = {3, 0};
return true;
case 10: // 10 = 2^3 + 2^1 -> (x << 3) + (x << 1)
shifts = {3, 1};
return true;
case 11: // 11 = 2^3 + 2^1 + 2^0 -> (x << 3) + (x << 1) + x
shifts = {3, 1, 0};
return true;
case 12: // 12 = 2^3 + 2^2 -> (x << 3) + (x << 2)
shifts = {3, 2};
return true;
case 13: // 13 = 2^3 + 2^2 + 2^0 -> (x << 3) + (x << 2) + x
shifts = {3, 2, 0};
return true;
case 14: // 14 = 2^3 + 2^2 + 2^1 -> (x << 3) + (x << 2) + (x << 1)
shifts = {3, 2, 1};
return true;
case 15: // 15 = 2^3 + 2^2 + 2^1 + 2^0 -> (x << 3) + (x << 2) + (x << 1) + x
shifts = {3, 2, 1, 0};
return true;
case 17: // 17 = 2^4 + 2^0 -> (x << 4) + x
shifts = {4, 0};
return true;
case 18: // 18 = 2^4 + 2^1 -> (x << 4) + (x << 1)
shifts = {4, 1};
return true;
case 20: // 20 = 2^4 + 2^2 -> (x << 4) + (x << 2)
shifts = {4, 2};
return true;
case 24: // 24 = 2^4 + 2^3 -> (x << 4) + (x << 3)
shifts = {4, 3};
return true;
case 25: // 25 = 2^4 + 2^3 + 2^0 -> (x << 4) + (x << 3) + x
shifts = {4, 3, 0};
return true;
case 100: // 100 = 2^6 + 2^5 + 2^2 -> (x << 6) + (x << 5) + (x << 2)
shifts = {6, 5, 2};
return true;
}
// 通用二进制分解最多4个项避免过度复杂化
if (constant > 0 && constant < 256) {
std::vector<int> binaryShifts;
int temp = constant;
int bit = 0;
while (temp > 0 && binaryShifts.size() < 4) {
if (temp & 1) {
binaryShifts.push_back(bit);
}
temp >>= 1;
bit++;
}
// 只有当项数不超过3个时才使用二进制分解比直接乘法更有效
if (binaryShifts.size() <= 3 && binaryShifts.size() >= 2) {
shifts = binaryShifts;
return true;
}
}
return false;
}
Value* GlobalStrengthReductionContext::createShiftDecomposition(BinaryInst* inst, Value* variable, const std::vector<int>& shifts) {
if (shifts.empty()) return nullptr;
builder->setPosition(inst->getParent(), inst->getParent()->findInstIterator(inst));
Value* result = nullptr;
for (int shift : shifts) {
Value* term;
if (shift == 0) {
// 0位移就是原变量
term = variable;
} else {
// 创建位移指令
term = builder->createBinaryInst(Instruction::kSll, Type::getIntType(), variable, getConstantInt(shift));
}
if (result == nullptr) {
result = term;
} else {
// 累加到结果中
result = builder->createAddInst(result, term);
}
}
return result;
}
bool GlobalStrengthReductionContext::reduceDivision(BinaryInst *inst) {
Value *lhs = inst->getLhs();
Value *rhs = inst->getRhs();
uint32_t constVal;
// x / 2^n = x >> n (对于无符号除法或已知为正数的情况)
if (isConstantInt(rhs, constVal) && constVal > 0 && isPowerOfTwo(constVal)) {
builder->setPosition(inst->getParent(), inst->getParent()->findInstIterator(inst));
int shiftAmount = log2OfPowerOfTwo(constVal);
// 有符号除法校正:(x + (x >> 31) & mask) >> k
int maskValue = constVal - 1;
// x >> 31 (算术右移获取符号位)
Value* signShift = ConstantInteger::get(31);
Value* signBits = builder->createBinaryInst(
Instruction::Kind::kSra, // 算术右移
lhs->getType(),
lhs,
signShift
);
// (x >> 31) & mask
Value* mask = ConstantInteger::get(maskValue);
Value* correction = builder->createBinaryInst(
Instruction::Kind::kAnd,
lhs->getType(),
signBits,
mask
);
// x + correction
Value* corrected = builder->createAddInst(lhs, correction);
// (x + correction) >> k
Value* divShift = ConstantInteger::get(shiftAmount);
Value* shiftInst = builder->createBinaryInst(
Instruction::Kind::kSra, // 算术右移
lhs->getType(),
corrected,
divShift
);
if (DEBUG) {
std::cout << " StrengthReduction: " << inst->getName()
<< " = x / " << constVal << " -> (x + (x >> 31) & mask) >> " << shiftAmount << std::endl;
}
// builder->setPosition(inst->getParent(), inst->getParent()->findInstIterator(inst));
// Value* divisor_minus_1 = ConstantInteger::get(constVal - 1);
// Value* adjusted = builder->createAddInst(lhs, divisor_minus_1);
// Value* shiftInst = builder->createBinaryInst(Instruction::kSra, Type::getIntType(), adjusted, getConstantInt(shiftAmount));
replaceWithOptimized(inst, shiftInst);
strengthReductionCount++;
return true;
}
// x / c = x * magic_number (魔数乘法优化 - 使用libdivide算法)
if (isConstantInt(rhs, constVal) && constVal > 1 && constVal != (uint32_t)(-1)) {
// auto magicPair = computeMulhMagicNumbers(static_cast<int>(constVal));
Value* magicResult = createMagicDivisionLibdivide(inst, static_cast<int>(constVal));
replaceWithOptimized(inst, magicResult);
divisionOptCount++;
return true;
}
return false;
}
bool GlobalStrengthReductionContext::reducePower(CallInst *inst) {
// 检查是否是pow函数调用
Function* callee = inst->getCallee();
if (!callee || callee->getName() != "pow") {
return false;
}
// pow(x, 2) = x * x
if (inst->getNumOperands() >= 2) {
int exponent;
if (isConstantInt(inst->getOperand(1), exponent)) {
if (exponent == 2) {
if (DEBUG) {
std::cout << " StrengthReduction: pow(x, 2) -> x * x" << std::endl;
}
Value* base = inst->getOperand(0);
builder->setPosition(inst->getParent(), inst->getParent()->findInstIterator(inst));
auto mulInst = builder->createMulInst(base, base);
replaceWithOptimized(inst, mulInst);
strengthReductionCount++;
return true;
} else if (exponent >= 3 && exponent <= 8) {
// 对于小的指数,展开为连续乘法
if (DEBUG) {
std::cout << " StrengthReduction: pow(x, " << exponent << ") -> repeated multiplication" << std::endl;
}
Value* base = inst->getOperand(0);
Value* result = base;
builder->setPosition(inst->getParent(), inst->getParent()->findInstIterator(inst));
for (int i = 1; i < exponent; i++) {
result = builder->createMulInst(result, base);
}
replaceWithOptimized(inst, result);
strengthReductionCount++;
return true;
}
}
}
return false;
}
Value* GlobalStrengthReductionContext::createMagicDivisionLibdivide(BinaryInst* divInst, int divisor) {
builder->setPosition(divInst->getParent(), divInst->getParent()->findInstIterator(divInst));
// 使用mulh指令优化任意常数除法
auto [magic, shift] = SysYIROptUtils::computeMulhMagicNumbers(divisor);
// 检查是否无法优化magic == -1, shift == -1 表示失败)
if (magic == -1 && shift == -1) {
if (DEBUG) {
std::cout << "[SR] Cannot optimize division by " << divisor
<< ", keeping original division" << std::endl;
}
// 返回 nullptr 表示无法优化,调用方应该保持原始除法
return nullptr;
}
// 2的幂次方除法可以用移位优化但这不是魔数法的情况这种情况应该不会被分类到这里但是还是做一个保护措施
if ((divisor & (divisor - 1)) == 0 && divisor > 0) {
// 是2的幂次方可以用移位
int shift_amount = 0;
int temp = divisor;
while (temp > 1) {
temp >>= 1;
shift_amount++;
}
Value* shiftConstant = ConstantInteger::get(shift_amount);
// 对于有符号除法,需要先加上除数-1然后再移位为了正确处理负数舍入
Value* divisor_minus_1 = ConstantInteger::get(divisor - 1);
Value* adjusted = builder->createAddInst(divInst->getOperand(0), divisor_minus_1);
return builder->createBinaryInst(
Instruction::Kind::kSra, // 算术右移
divInst->getOperand(0)->getType(),
adjusted,
shiftConstant
);
}
// 创建魔数常量
// 检查魔数是否能放入32位如果不能则不进行优化
if (magic > INT32_MAX || magic < INT32_MIN) {
if (DEBUG) {
std::cout << "[SR] Magic number " << magic << " exceeds 32-bit range, skipping optimization" << std::endl;
}
return nullptr; // 无法优化,保持原始除法
}
Value* magicConstant = ConstantInteger::get((int32_t)magic);
// 检查是否需要ADD_MARKER处理加法调整
bool needAdd = (shift & 0x40) != 0;
int actualShift = shift & 0x3F; // 提取真实的移位量
if (DEBUG) {
std::cout << "[SR] IR Generation: magic=" << magic << ", needAdd=" << needAdd
<< ", actualShift=" << actualShift << std::endl;
}
// 执行高位乘法mulh(x, magic)
Value* mulhResult = builder->createBinaryInst(
Instruction::Kind::kMulh, // 高位乘法
divInst->getOperand(0)->getType(),
divInst->getOperand(0),
magicConstant
);
if (needAdd) {
// ADD_MARKER 情况:需要在移位前加上被除数
// 这对应于 libdivide 的加法调整算法
if (DEBUG) {
std::cout << "[SR] Applying ADD_MARKER: adding dividend before shift" << std::endl;
}
mulhResult = builder->createAddInst(mulhResult, divInst->getOperand(0));
}
if (actualShift > 0) {
// 如果需要额外移位
Value* shiftConstant = ConstantInteger::get(actualShift);
mulhResult = builder->createBinaryInst(
Instruction::Kind::kSra, // 算术右移
divInst->getOperand(0)->getType(),
mulhResult,
shiftConstant
);
}
// 标准的有符号除法符号修正如果被除数为负商需要加1
// 这对所有有符号除法都需要,不管是否可能有负数
Value* isNegative = builder->createICmpLTInst(divInst->getOperand(0), ConstantInteger::get(0));
// 将i1转换为i32负数时为1非负数时为0 ICmpLTInst的结果会默认转化为32位
mulhResult = builder->createAddInst(mulhResult, isNegative);
return mulhResult;
}
// ======================================================================
// 辅助方法
// ======================================================================
bool GlobalStrengthReductionContext::isPowerOfTwo(uint32_t n) {
return n > 0 && (n & (n - 1)) == 0;
}
int GlobalStrengthReductionContext::log2OfPowerOfTwo(uint32_t n) {
int result = 0;
while (n > 1) {
n >>= 1;
result++;
}
return result;
}
bool GlobalStrengthReductionContext::isConstantInt(Value* val, int& constVal) {
if (auto constInt = dynamic_cast<ConstantInteger*>(val)) {
constVal = std::get<int>(constInt->getVal());
return true;
}
return false;
}
bool GlobalStrengthReductionContext::isConstantInt(Value* val, uint32_t& constVal) {
if (auto constInt = dynamic_cast<ConstantInteger*>(val)) {
int signedVal = std::get<int>(constInt->getVal());
if (signedVal >= 0) {
constVal = static_cast<uint32_t>(signedVal);
return true;
}
}
return false;
}
ConstantInteger* GlobalStrengthReductionContext::getConstantInt(int val) {
return ConstantInteger::get(val);
}
bool GlobalStrengthReductionContext::hasOnlyLocalUses(Instruction* inst) {
if (!inst) return true;
// 简单检查:如果指令没有副作用,则认为是本地的
if (sideEffectAnalysis) {
auto sideEffect = sideEffectAnalysis->getInstructionSideEffect(inst);
return sideEffect.type == SideEffectType::NO_SIDE_EFFECT;
}
// 没有副作用分析时,保守处理
return !inst->isCall() && !inst->isStore() && !inst->isLoad();
}
void GlobalStrengthReductionContext::replaceWithOptimized(Instruction* original, Value* replacement) {
if (DEBUG) {
std::cout << " Replacing " << original->getName()
<< " with " << replacement->getName() << std::endl;
}
original->replaceAllUsesWith(replacement);
// 如果替换值是新创建的指令,确保它有合适的名字
// if (auto replInst = dynamic_cast<Instruction*>(replacement)) {
// if (replInst->getName().empty()) {
// replInst->setName(original->getName() + "_opt");
// }
// }
// 删除原指令,让调用者处理
SysYIROptUtils::usedelete(original);
}
} // namespace sysy

View File

@ -3,6 +3,7 @@
#include "Loop.h"
#include "Dom.h"
#include "SideEffectAnalysis.h"
#include "AliasAnalysis.h"
#include "SysYIROptUtils.h"
#include <iostream>
#include <algorithm>
@ -43,6 +44,7 @@ void InductionVariableElimination::getAnalysisUsage(std::set<void*>& analysisDep
analysisDependencies.insert(&LoopCharacteristicsPass::ID);
analysisDependencies.insert(&DominatorTreeAnalysisPass::ID);
analysisDependencies.insert(&SysYSideEffectAnalysisPass::ID);
analysisDependencies.insert(&SysYAliasAnalysisPass::ID);
// 会使失效的分析归纳变量消除会修改IR结构
analysisInvalidations.insert(&LoopCharacteristicsPass::ID);
@ -93,6 +95,18 @@ bool InductionVariableEliminationContext::run(Function* F, AnalysisManager& AM)
}
}
aliasAnalysis = AM.getAnalysisResult<AliasAnalysisResult, SysYAliasAnalysisPass>(F);
if (!aliasAnalysis) {
if (DEBUG) {
std::cout << " AliasAnalysis not available, using conservative approach" << std::endl;
}
// 可以继续执行,但会使用更保守的策略
} else {
if (DEBUG) {
std::cout << " Using AliasAnalysis for memory safety checks" << std::endl;
}
}
// 执行三个阶段的优化
// 阶段1识别死归纳变量
@ -179,9 +193,9 @@ InductionVariableEliminationContext::isDeadInductionVariable(const InductionVarI
return nullptr; // 不是 phi 指令
}
// 检查是否只用于自身更新
if (!isUsedOnlyForSelfUpdate(phiInst, loop)) {
return nullptr; // 有其他用途
// 新的逻辑递归分析整个use-def链判断是否有真实的使用
if (!isPhiInstructionDeadRecursively(phiInst, loop)) {
return nullptr; // 有真实的使用,不能删除
}
// 创建死归纳变量信息
@ -191,9 +205,333 @@ InductionVariableEliminationContext::isDeadInductionVariable(const InductionVarI
return deadIV;
}
bool InductionVariableEliminationContext::isUsedOnlyForSelfUpdate(PhiInst* phiInst, Loop* loop) {
// 检查 phi 指令的所有使用
for (auto use : phiInst->getUses()) {
// 递归分析phi指令及其使用链是否都是死代码
bool InductionVariableEliminationContext::isPhiInstructionDeadRecursively(PhiInst* phiInst, Loop* loop) {
if (DEBUG) {
std::cout << " 递归分析归纳变量 " << phiInst->getName() << " 的完整使用链" << std::endl;
}
// 使用访问集合避免无限递归
std::set<Instruction*> visitedInstructions;
std::set<Instruction*> currentPath; // 用于检测循环依赖
// 核心逻辑:递归分析使用链,寻找任何"逃逸点"
return isInstructionUseChainDeadRecursively(phiInst, loop, visitedInstructions, currentPath);
}
// 递归分析指令的使用链是否都是死代码
bool InductionVariableEliminationContext::isInstructionUseChainDeadRecursively(
Instruction* inst, Loop* loop,
std::set<Instruction*>& visited,
std::set<Instruction*>& currentPath) {
if (DEBUG && visited.size() < 10) { // 限制debug输出
std::cout << " 分析指令 " << inst->getName() << " (" << inst->getKindString() << ")" << std::endl;
}
// 避免无限递归
if (currentPath.count(inst) > 0) {
// 发现循环依赖,这在归纳变量中是正常的,继续分析其他路径
if (DEBUG && visited.size() < 10) {
std::cout << " 发现循环依赖,继续分析其他路径" << std::endl;
}
return true; // 循环依赖本身不是逃逸点
}
if (visited.count(inst) > 0) {
// 已经分析过这个指令
return true; // 假设之前的分析是正确的
}
visited.insert(inst);
currentPath.insert(inst);
// 1. 检查是否有副作用(逃逸点)
if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(inst)) {
if (DEBUG && visited.size() < 10) {
std::cout << " 指令有副作用,是逃逸点" << std::endl;
}
currentPath.erase(inst);
return false; // 有副作用的指令是逃逸点
}
// 1.5. 特殊检查:控制流指令永远不是死代码
auto instKind = inst->getKind();
if (instKind == Instruction::Kind::kCondBr ||
instKind == Instruction::Kind::kBr ||
instKind == Instruction::Kind::kReturn) {
if (DEBUG && visited.size() < 10) {
std::cout << " 控制流指令,是逃逸点" << std::endl;
}
currentPath.erase(inst);
return false; // 控制流指令是逃逸点
}
// 2. 检查指令的所有使用
bool allUsesAreDead = true;
for (auto use : inst->getUses()) {
auto user = use->getUser();
auto* userInst = dynamic_cast<Instruction*>(user);
if (!userInst) {
// 被非指令使用(如函数返回值),是逃逸点
if (DEBUG && visited.size() < 10) {
std::cout << " 被非指令使用,是逃逸点" << std::endl;
}
allUsesAreDead = false;
break;
}
// 检查使用是否在循环外(逃逸点)
if (!loop->contains(userInst->getParent())) {
if (DEBUG && visited.size() < 10) {
std::cout << " 在循环外被 " << userInst->getName() << " 使用,是逃逸点" << std::endl;
}
allUsesAreDead = false;
break;
}
// 特殊检查:如果使用者是循环的退出条件,需要进一步分析
// 对于用于退出条件的归纳变量,需要更谨慎的处理
if (isUsedInLoopExitCondition(userInst, loop)) {
// 修复逻辑:用于循环退出条件的归纳变量通常不应该被消除
// 除非整个循环都可以被证明是完全无用的(这需要更复杂的分析)
if (DEBUG && visited.size() < 10) {
std::cout << " 被用于循环退出条件,是逃逸点(避免破坏循环语义)" << std::endl;
}
allUsesAreDead = false;
break;
}
// 递归分析使用者的使用链
if (!isInstructionUseChainDeadRecursively(userInst, loop, visited, currentPath)) {
allUsesAreDead = false;
break; // 找到逃逸点,不需要继续分析
}
}
currentPath.erase(inst);
if (allUsesAreDead && DEBUG && visited.size() < 10) {
std::cout << " 指令 " << inst->getName() << " 的所有使用都是死代码" << std::endl;
}
return allUsesAreDead;
}
// 检查循环是否有副作用
bool InductionVariableEliminationContext::loopHasSideEffects(Loop* loop) {
// 遍历循环中的所有指令,检查是否有副作用
for (BasicBlock* bb : loop->getBlocks()) {
for (auto& inst : bb->getInstructions()) {
Instruction* instPtr = inst.get();
// 使用副作用分析(如果可用)
if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(instPtr)) {
if (DEBUG) {
std::cout << " 循环中发现有副作用的指令: " << instPtr->getName() << std::endl;
}
return true;
}
// 如果没有副作用分析,使用保守的判断
if (!sideEffectAnalysis) {
auto kind = instPtr->getKind();
// 这些指令通常有副作用
if (kind == Instruction::Kind::kCall ||
kind == Instruction::Kind::kStore ||
kind == Instruction::Kind::kReturn) {
if (DEBUG) {
std::cout << " 循环中发现潜在有副作用的指令: " << instPtr->getName() << std::endl;
}
return true;
}
}
}
}
// 重要修复:检查是否为嵌套循环的外层循环
// 如果当前循环包含其他循环,那么它有潜在的副作用
for (const auto& loop_ptr : loopAnalysis->getAllLoops()) {
Loop* otherLoop = loop_ptr.get();
if(loopAnalysis->getLowestCommonAncestor(otherLoop, loop) == loop) {
if (DEBUG) {
std::cout << " 循环 " << loop->getName() << " 是其他循环的外层循环,视为有副作用" << std::endl;
}
return true; // 外层循环被视为有副作用
}
// if (otherLoop != loop && loop->contains(otherLoop->getHeader())) {
// if (DEBUG) {
// std::cout << " 循环 " << loop->getName() << " 包含子循环 " << otherLoop->getName() << ",视为有副作用" << std::endl;
// }
// return true; // 包含子循环的外层循环被视为有副作用
// }
}
if (DEBUG) {
std::cout << " 循环 " << loop->getName() << " 无副作用" << std::endl;
}
return false; // 循环无副作用
}
// 检查指令是否被用于循环退出条件
bool InductionVariableEliminationContext::isUsedInLoopExitCondition(Instruction* inst, Loop* loop) {
// 检查指令是否被循环的退出条件使用
for (BasicBlock* exitingBB : loop->getExitingBlocks()) {
auto terminatorIt = exitingBB->terminator();
if (terminatorIt != exitingBB->end()) {
Instruction* terminator = terminatorIt->get();
if (terminator) {
// 检查终结指令的操作数
for (size_t i = 0; i < terminator->getNumOperands(); ++i) {
if (terminator->getOperand(i) == inst) {
if (DEBUG) {
std::cout << " 指令 " << inst->getName() << " 用于循环退出条件" << std::endl;
}
return true;
}
}
// 对于条件分支,还需要检查条件指令的操作数
if (terminator->getKind() == Instruction::Kind::kCondBr) {
auto* condBr = dynamic_cast<CondBrInst*>(terminator);
if (condBr) {
Value* condition = condBr->getCondition();
if (condition == inst) {
if (DEBUG) {
std::cout << " 指令 " << inst->getName() << " 是循环条件" << std::endl;
}
return true;
}
// 递归检查条件指令的操作数(比如比较指令)
auto* condInst = dynamic_cast<Instruction*>(condition);
if (condInst) {
for (size_t i = 0; i < condInst->getNumOperands(); ++i) {
if (condInst->getOperand(i) == inst) {
if (DEBUG) {
std::cout << " 指令 " << inst->getName() << " 用于循环条件的操作数" << std::endl;
}
return true;
}
}
}
}
}
}
}
}
return false;
}
// 检查指令的结果是否未被有效使用
bool InductionVariableEliminationContext::isInstructionResultUnused(Instruction* inst, Loop* loop) {
// 检查指令的所有使用
if (inst->getUses().empty()) {
return true; // 没有使用,肯定是未使用
}
for (auto use : inst->getUses()) {
auto user = use->getUser();
auto* userInst = dynamic_cast<Instruction*>(user);
if (!userInst) {
return false; // 被非指令使用,认为是有效使用
}
// 如果在循环外被使用,认为是有效使用
if (!loop->contains(userInst->getParent())) {
return false;
}
// 递归检查使用这个结果的指令是否也是死代码
// 为了避免无限递归,限制递归深度
if (!isInstructionEffectivelyDead(userInst, loop, 3)) {
return false; // 存在有效使用
}
}
return true; // 所有使用都是无效的
}
// 检查store指令是否存储到死地址利用别名分析
bool InductionVariableEliminationContext::isStoreToDeadLocation(StoreInst* store, Loop* loop) {
if (!aliasAnalysis) {
return false; // 没有别名分析保守返回false
}
Value* storePtr = store->getPointer();
// 检查是否存储到局部临时变量且该变量在循环外不被读取
const MemoryLocation* memLoc = aliasAnalysis->getMemoryLocation(storePtr);
if (!memLoc) {
return false; // 无法确定内存位置
}
// 如果是局部数组且只在循环内被访问
if (memLoc->isLocalArray) {
// 检查该内存位置是否在循环外被读取
for (auto* accessInst : memLoc->accessInsts) {
if (accessInst->getKind() == Instruction::Kind::kLoad) {
if (!loop->contains(accessInst->getParent())) {
return false; // 在循环外被读取,不是死存储
}
}
}
if (DEBUG) {
std::cout << " 存储到局部数组且仅在循环内访问" << std::endl;
}
return true; // 存储到仅循环内访问的局部数组
}
return false;
}
// 检查指令是否有效死代码(带递归深度限制)
bool InductionVariableEliminationContext::isInstructionEffectivelyDead(Instruction* inst, Loop* loop, int maxDepth) {
if (maxDepth <= 0) {
return false; // 达到递归深度限制保守返回false
}
// 利用副作用分析
if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(inst)) {
return false; // 有副作用的指令不是死代码
}
// 检查特殊指令类型
switch (inst->getKind()) {
case Instruction::Kind::kStore:
// Store指令可能是死存储
return isStoreToDeadLocation(dynamic_cast<StoreInst*>(inst), loop);
case Instruction::Kind::kCall:
// 函数调用通常有副作用
if (sideEffectAnalysis) {
return !sideEffectAnalysis->hasSideEffect(inst);
}
return false; // 保守地认为函数调用有效果
case Instruction::Kind::kReturn:
case Instruction::Kind::kBr:
case Instruction::Kind::kCondBr:
// 控制流指令不是死代码
return false;
default:
// 其他指令检查其使用是否有效
break;
}
// 检查指令的使用
if (inst->getUses().empty()) {
return true; // 没有使用的纯指令是死代码
}
// 递归检查所有使用
for (auto use : inst->getUses()) {
auto user = use->getUser();
auto* userInst = dynamic_cast<Instruction*>(user);
@ -201,35 +539,180 @@ bool InductionVariableEliminationContext::isUsedOnlyForSelfUpdate(PhiInst* phiIn
return false; // 被非指令使用
}
// 检查使用是否在循环内
if (!loop->contains(userInst->getParent())) {
return false; // 在循环外被使用
}
// 检查是否为自身的更新指令
bool isSelfUpdate = false;
// 检查是否为加法/减法指令(常见的归纳变量更新模式)
if (userInst->getKind() == Instruction::Kind::kAdd ||
userInst->getKind() == Instruction::Kind::kSub) {
auto* binInst = dynamic_cast<BinaryInst*>(userInst);
if (binInst && (binInst->getOperand(0) == phiInst || binInst->getOperand(1) == phiInst)) {
// 检查这个指令的结果是否流回到 phi
for (auto& [incomingBB, incomingVal] : phiInst->getIncomingValues()) {
if (loop->contains(incomingBB) && incomingVal == binInst) {
isSelfUpdate = true;
break;
}
}
}
}
if (!isSelfUpdate) {
return false; // 有非自更新的使用
// 递归检查使用者
if (!isInstructionEffectivelyDead(userInst, loop, maxDepth - 1)) {
return false; // 存在有效使用
}
}
return true; // 只用于自身更新
return true; // 所有使用都是死代码
}
// 原有的函数保持兼容,但现在使用增强的死代码分析
bool InductionVariableEliminationContext::isInstructionDeadOrInternalOnly(Instruction* inst, Loop* loop) {
return isInstructionEffectivelyDead(inst, loop, 5);
}
// 检查store指令是否有后续的load操作
bool InductionVariableEliminationContext::hasSubsequentLoad(StoreInst* store, Loop* loop) {
if (!aliasAnalysis) {
// 没有别名分析,保守地假设有后续读取
return true;
}
Value* storePtr = store->getPointer();
const MemoryLocation* storeLoc = aliasAnalysis->getMemoryLocation(storePtr);
if (!storeLoc) {
// 无法确定内存位置,保守处理
return true;
}
// 在循环中和循环后查找对同一位置的load操作
std::vector<BasicBlock*> blocksToCheck;
// 添加循环内的所有基本块
for (auto* bb : loop->getBlocks()) {
blocksToCheck.push_back(bb);
}
// 添加循环的退出块
auto exitBlocks = loop->getExitBlocks();
for (auto* exitBB : exitBlocks) {
blocksToCheck.push_back(exitBB);
}
// 搜索load操作
for (auto* bb : blocksToCheck) {
for (auto& inst : bb->getInstructions()) {
if (inst->getKind() == Instruction::Kind::kLoad) {
LoadInst* loadInst = static_cast<LoadInst*>(inst.get());
Value* loadPtr = loadInst->getPointer();
const MemoryLocation* loadLoc = aliasAnalysis->getMemoryLocation(loadPtr);
if (loadLoc && aliasAnalysis->queryAlias(storePtr, loadPtr) != AliasType::NO_ALIAS) {
// 找到可能读取同一位置的load操作
if (DEBUG) {
std::cout << " 找到后续load操作: " << loadInst->getName() << std::endl;
}
return true;
}
}
}
}
// 检查是否通过函数调用间接访问
for (auto* bb : blocksToCheck) {
for (auto& inst : bb->getInstructions()) {
if (inst->getKind() == Instruction::Kind::kCall) {
CallInst* callInst = static_cast<CallInst*>(inst.get());
if (callInst && sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(callInst)) {
// 函数调用可能间接读取内存
if (DEBUG) {
std::cout << " 函数调用可能读取内存: " << callInst->getName() << std::endl;
}
return true;
}
}
}
}
if (DEBUG) {
std::cout << " 未找到后续load操作" << std::endl;
}
return false; // 没有找到后续读取
}
// 检查指令是否在循环外有使用
bool InductionVariableEliminationContext::hasUsageOutsideLoop(Instruction* inst, Loop* loop) {
for (auto use : inst->getUses()) {
auto user = use->getUser();
auto* userInst = dynamic_cast<Instruction*>(user);
if (!userInst) {
// 被非指令使用,可能在循环外
return true;
}
if (!loop->contains(userInst->getParent())) {
// 在循环外被使用
if (DEBUG) {
std::cout << " 指令 " << inst->getName() << " 在循环外被 "
<< userInst->getName() << " 使用" << std::endl;
}
return true;
}
}
return false; // 没有循环外使用
}
// 检查store指令是否在循环外有后续的load操作
bool InductionVariableEliminationContext::hasSubsequentLoadOutsideLoop(StoreInst* store, Loop* loop) {
if (!aliasAnalysis) {
// 没有别名分析,保守地假设有后续读取
return true;
}
Value* storePtr = store->getPointer();
// 检查循环的退出块及其后继
auto exitBlocks = loop->getExitBlocks();
std::set<BasicBlock*> visitedBlocks;
for (auto* exitBB : exitBlocks) {
if (hasLoadInSubtree(exitBB, storePtr, visitedBlocks)) {
if (DEBUG) {
std::cout << " 找到循环外的后续load操作" << std::endl;
}
return true;
}
}
return false; // 没有找到循环外的后续读取
}
// 递归检查基本块子树中是否有对指定位置的load操作
bool InductionVariableEliminationContext::hasLoadInSubtree(BasicBlock* bb, Value* ptr, std::set<BasicBlock*>& visited) {
if (visited.count(bb) > 0) {
return false; // 已经访问过,避免无限循环
}
visited.insert(bb);
// 检查当前基本块中的指令
for (auto& inst : bb->getInstructions()) {
if (inst->getKind() == Instruction::Kind::kLoad) {
LoadInst* loadInst = static_cast<LoadInst*>(inst.get());
if (aliasAnalysis && aliasAnalysis->queryAlias(ptr, loadInst->getPointer()) != AliasType::NO_ALIAS) {
return true; // 找到了对相同或别名位置的load
}
} else if (inst->getKind() == Instruction::Kind::kCall) {
// 函数调用可能间接读取内存
CallInst* callInst = static_cast<CallInst*>(inst.get());
if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(callInst)) {
return true; // 保守地认为函数调用可能读取内存
}
}
}
// 递归检查后继基本块(限制深度以避免过度搜索)
static int searchDepth = 0;
if (searchDepth < 10) { // 限制搜索深度
searchDepth++;
for (auto* succ : bb->getSuccessors()) {
if (hasLoadInSubtree(succ, ptr, visited)) {
searchDepth--;
return true;
}
}
searchDepth--;
}
return false;
}
std::vector<Instruction*> InductionVariableEliminationContext::collectRelatedInstructions(

View File

@ -18,62 +18,214 @@ bool LICMContext::hoistInstructions() {
// 1. 先收集所有可外提指令
std::unordered_set<Instruction *> workSet(chars->invariantInsts.begin(), chars->invariantInsts.end());
if (DEBUG) {
std::cout << "LICM: Found " << workSet.size() << " candidate invariant instructions to hoist:" << std::endl;
for (auto *inst : workSet) {
std::cout << " - " << inst->getName() << " (kind: " << static_cast<int>(inst->getKind())
<< ", in BB: " << inst->getParent()->getName() << ")" << std::endl;
}
}
// 2. 计算每个指令被依赖的次数(入度)
std::unordered_map<Instruction *, int> indegree;
std::unordered_map<Instruction *, std::vector<Instruction *>> dependencies; // 记录依赖关系
std::unordered_map<Instruction *, std::vector<Instruction *>> dependents; // 记录被依赖关系
for (auto *inst : workSet) {
indegree[inst] = 0;
dependencies[inst] = {};
dependents[inst] = {};
}
if (DEBUG) {
std::cout << "LICM: Analyzing dependencies between invariant instructions..." << std::endl;
}
for (auto *inst : workSet) {
for (size_t i = 0; i < inst->getNumOperands(); ++i) {
if (auto *dep = dynamic_cast<Instruction *>(inst->getOperand(i))) {
if (workSet.count(dep)) {
indegree[inst]++;
dependencies[inst].push_back(dep);
dependents[dep].push_back(inst);
if (DEBUG) {
std::cout << " Dependency: " << inst->getName() << " depends on " << dep->getName() << std::endl;
}
}
}
}
}
if (DEBUG) {
std::cout << "LICM: Initial indegree analysis:" << std::endl;
for (auto &[inst, deg] : indegree) {
std::cout << " " << inst->getName() << ": indegree=" << deg;
if (deg > 0) {
std::cout << ", depends on: ";
for (auto *dep : dependencies[inst]) {
std::cout << dep->getName() << " ";
}
}
std::cout << std::endl;
}
}
// 3. Kahn拓扑排序
std::vector<Instruction *> sorted;
std::queue<Instruction *> q;
for (auto &[inst, deg] : indegree) {
if (deg == 0)
q.push(inst);
if (DEBUG) {
std::cout << "LICM: Starting topological sort..." << std::endl;
}
for (auto &[inst, deg] : indegree) {
if (deg == 0) {
q.push(inst);
if (DEBUG) {
std::cout << " Initial zero-indegree instruction: " << inst->getName() << std::endl;
}
}
}
int sortStep = 0;
while (!q.empty()) {
auto *inst = q.front();
q.pop();
sorted.push_back(inst);
for (size_t i = 0; i < inst->getNumOperands(); ++i) {
if (auto *dep = dynamic_cast<Instruction *>(inst->getOperand(i))) {
if (workSet.count(dep)) {
indegree[dep]--;
if (indegree[dep] == 0)
q.push(dep);
if (DEBUG) {
std::cout << " Step " << (++sortStep) << ": Processing " << inst->getName() << std::endl;
}
if (DEBUG) {
std::cout << " Reducing indegree of dependents of " << inst->getName() << std::endl;
}
// 正确的拓扑排序当处理一个指令时应该减少其所有使用者dependents的入度
for (auto *dependent : dependents[inst]) {
indegree[dependent]--;
if (DEBUG) {
std::cout << " Reducing indegree of " << dependent->getName() << " to " << indegree[dependent] << std::endl;
}
if (indegree[dependent] == 0) {
q.push(dependent);
if (DEBUG) {
std::cout << " Adding " << dependent->getName() << " to queue (indegree=0)" << std::endl;
}
}
}
}
// 检查是否全部排序,若未全部排序,说明有环(理论上不会)
// 检查是否全部排序,若未全部排序,打印错误信息
// 这可能是因为存在循环依赖或其他问题导致无法完成拓扑排序
if (sorted.size() != workSet.size()) {
if (DEBUG)
std::cerr << "LICM: Topological sort failed, possible dependency cycle." << std::endl;
if (DEBUG) {
std::cout << "LICM: Topological sort failed! Sorted " << sorted.size()
<< " instructions out of " << workSet.size() << " total." << std::endl;
// 找出未被排序的指令(形成循环依赖的指令)
std::unordered_set<Instruction *> remaining;
for (auto *inst : workSet) {
bool found = false;
for (auto *sortedInst : sorted) {
if (inst == sortedInst) {
found = true;
break;
}
}
if (!found) {
remaining.insert(inst);
}
}
std::cout << "LICM: Instructions involved in dependency cycle:" << std::endl;
for (auto *inst : remaining) {
std::cout << " - " << inst->getName() << " (indegree=" << indegree[inst] << ")" << std::endl;
std::cout << " Dependencies within cycle: ";
for (auto *dep : dependencies[inst]) {
if (remaining.count(dep)) {
std::cout << dep->getName() << " ";
}
}
std::cout << std::endl;
std::cout << " Dependents within cycle: ";
for (auto *dependent : dependents[inst]) {
if (remaining.count(dependent)) {
std::cout << dependent->getName() << " ";
}
}
std::cout << std::endl;
}
// 尝试找出一个具体的循环路径
std::cout << "LICM: Attempting to trace a dependency cycle:" << std::endl;
if (!remaining.empty()) {
auto *start = *remaining.begin();
std::unordered_set<Instruction *> visited;
std::vector<Instruction *> path;
std::function<bool(Instruction *)> findCycle = [&](Instruction *current) -> bool {
if (visited.count(current)) {
// 找到环
auto it = std::find(path.begin(), path.end(), current);
if (it != path.end()) {
std::cout << " Cycle found: ";
for (auto cycleIt = it; cycleIt != path.end(); ++cycleIt) {
std::cout << (*cycleIt)->getName() << " -> ";
}
std::cout << current->getName() << std::endl;
return true;
}
return false;
}
visited.insert(current);
path.push_back(current);
for (auto *dep : dependencies[current]) {
if (remaining.count(dep)) {
if (findCycle(dep)) {
return true;
}
}
}
path.pop_back();
return false;
};
findCycle(start);
}
}
return false;
}
// 4. 按拓扑序外提
if (DEBUG) {
std::cout << "LICM: Successfully completed topological sort. Hoisting instructions in order:" << std::endl;
}
for (auto *inst : sorted) {
if (!inst)
continue;
BasicBlock *parent = inst->getParent();
if (parent && loop->contains(parent)) {
if (DEBUG) {
std::cout << " Hoisting " << inst->getName() << " from " << parent->getName()
<< " to preheader " << preheader->getName() << std::endl;
}
auto sourcePos = parent->findInstIterator(inst);
auto targetPos = preheader->terminator();
parent->moveInst(sourcePos, targetPos, preheader);
changed = true;
}
}
if (DEBUG && changed) {
std::cout << "LICM: Successfully hoisted " << sorted.size() << " invariant instructions" << std::endl;
}
return changed;
}
// ---- LICM Pass Implementation ----

View File

@ -1,145 +0,0 @@
#include "../../include/midend/Pass/Optimize/LargeArrayToGlobal.h"
#include "../../IR.h"
#include <unordered_map>
#include <sstream>
#include <string>
namespace sysy {
// Helper function to convert type to string
static std::string typeToString(Type *type) {
if (!type) return "null";
switch (type->getKind()) {
case Type::kInt:
return "int";
case Type::kFloat:
return "float";
case Type::kPointer:
return "ptr";
case Type::kArray: {
auto *arrayType = type->as<ArrayType>();
return "[" + std::to_string(arrayType->getNumElements()) + " x " +
typeToString(arrayType->getElementType()) + "]";
}
default:
return "unknown";
}
}
void *LargeArrayToGlobalPass::ID = &LargeArrayToGlobalPass::ID;
bool LargeArrayToGlobalPass::runOnModule(Module *M, AnalysisManager &AM) {
bool changed = false;
if (!M) {
return false;
}
// Collect all alloca instructions from all functions
std::vector<std::pair<AllocaInst*, Function*>> allocasToConvert;
for (auto &funcPair : M->getFunctions()) {
Function *F = funcPair.second.get();
if (!F || F->getBasicBlocks().begin() == F->getBasicBlocks().end()) {
continue;
}
for (auto &BB : F->getBasicBlocks()) {
for (auto &inst : BB->getInstructions()) {
if (auto *alloca = dynamic_cast<AllocaInst*>(inst.get())) {
Type *allocatedType = alloca->getAllocatedType();
// Calculate the size of the allocated type
unsigned size = calculateTypeSize(allocatedType);
if(DEBUG){
// Debug: print size information
std::cout << "LargeArrayToGlobalPass: Found alloca with size " << size
<< " for type " << typeToString(allocatedType) << std::endl;
}
// Convert arrays of 1KB (1024 bytes) or larger to global variables
if (size >= 1024) {
if(DEBUG)
std::cout << "LargeArrayToGlobalPass: Converting array of size " << size << " to global" << std::endl;
allocasToConvert.emplace_back(alloca, F);
}
}
}
}
}
// Convert the collected alloca instructions to global variables
for (auto [alloca, F] : allocasToConvert) {
convertAllocaToGlobal(alloca, F, M);
changed = true;
}
return changed;
}
unsigned LargeArrayToGlobalPass::calculateTypeSize(Type *type) {
if (!type) return 0;
switch (type->getKind()) {
case Type::kInt:
case Type::kFloat:
return 4;
case Type::kPointer:
return 8;
case Type::kArray: {
auto *arrayType = type->as<ArrayType>();
return arrayType->getNumElements() * calculateTypeSize(arrayType->getElementType());
}
default:
return 0;
}
}
void LargeArrayToGlobalPass::convertAllocaToGlobal(AllocaInst *alloca, Function *F, Module *M) {
Type *allocatedType = alloca->getAllocatedType();
// Create a unique name for the global variable
std::string globalName = generateUniqueGlobalName(alloca, F);
// Create the global variable - GlobalValue expects pointer type
Type *pointerType = Type::getPointerType(allocatedType);
GlobalValue *globalVar = M->createGlobalValue(globalName, pointerType);
if (!globalVar) {
return;
}
// Replace all uses of the alloca with the global variable
alloca->replaceAllUsesWith(globalVar);
// Remove the alloca instruction from its basic block
for (auto &BB : F->getBasicBlocks()) {
auto &instructions = BB->getInstructions();
for (auto it = instructions.begin(); it != instructions.end(); ++it) {
if (it->get() == alloca) {
instructions.erase(it);
break;
}
}
}
}
std::string LargeArrayToGlobalPass::generateUniqueGlobalName(AllocaInst *alloca, Function *F) {
std::string baseName = alloca->getName();
if (baseName.empty()) {
baseName = "array";
}
// Ensure uniqueness by appending function name and counter
static std::unordered_map<std::string, int> nameCounter;
std::string key = F->getName() + "." + baseName;
int counter = nameCounter[key]++;
std::ostringstream oss;
oss << key << "." << counter;
return oss.str();
}
} // namespace sysy

View File

@ -106,187 +106,6 @@ bool StrengthReductionContext::analyzeInductionVariableRange(
return hasNegativePotential;
}
//该实现参考了libdivide的算法
std::pair<int, int> StrengthReductionContext::computeMulhMagicNumbers(int divisor) const {
if (DEBUG) {
std::cout << "\n[SR] ===== Computing magic numbers for divisor " << divisor << " (libdivide algorithm) =====" << std::endl;
}
if (divisor == 0) {
if (DEBUG) std::cout << "[SR] Error: divisor must be != 0" << std::endl;
return {-1, -1};
}
// libdivide 常数
const uint8_t LIBDIVIDE_ADD_MARKER = 0x40;
const uint8_t LIBDIVIDE_NEGATIVE_DIVISOR = 0x80;
// 辅助函数:计算前导零个数
auto count_leading_zeros32 = [](uint32_t val) -> uint32_t {
if (val == 0) return 32;
return __builtin_clz(val);
};
// 辅助函数64位除法返回32位商和余数
auto div_64_32 = [](uint32_t high, uint32_t low, uint32_t divisor, uint32_t* rem) -> uint32_t {
uint64_t dividend = ((uint64_t)high << 32) | low;
uint32_t quotient = dividend / divisor;
*rem = dividend % divisor;
return quotient;
};
if (DEBUG) {
std::cout << "[SR] Input divisor: " << divisor << std::endl;
}
// libdivide_internal_s32_gen 算法实现
int32_t d = divisor;
uint32_t ud = (uint32_t)d;
uint32_t absD = (d < 0) ? -ud : ud;
if (DEBUG) {
std::cout << "[SR] absD = " << absD << std::endl;
}
uint32_t floor_log_2_d = 31 - count_leading_zeros32(absD);
if (DEBUG) {
std::cout << "[SR] floor_log_2_d = " << floor_log_2_d << std::endl;
}
// 检查 absD 是否为2的幂
if ((absD & (absD - 1)) == 0) {
if (DEBUG) {
std::cout << "[SR] " << absD << " 是2的幂使用移位方法" << std::endl;
}
// 对于2的幂我们只使用移位不需要魔数
int shift = floor_log_2_d;
if (d < 0) shift |= 0x80; // 标记负数
if (DEBUG) {
std::cout << "[SR] Power of 2 result: magic=0, shift=" << shift << std::endl;
std::cout << "[SR] ===== End magic computation =====" << std::endl;
}
// 对于我们的目的我们将在IR生成中以不同方式处理2的幂
// 返回特殊标记
return {0, shift};
}
if (DEBUG) {
std::cout << "[SR] " << absD << " is not a power of 2, computing magic number" << std::endl;
}
// 非2的幂除数的魔数计算
uint8_t more;
uint32_t rem, proposed_m;
// 计算 proposed_m = floor(2^(floor_log_2_d + 31) / absD)
proposed_m = div_64_32((uint32_t)1 << (floor_log_2_d - 1), 0, absD, &rem);
const uint32_t e = absD - rem;
if (DEBUG) {
std::cout << "[SR] proposed_m = " << proposed_m << ", rem = " << rem << ", e = " << e << std::endl;
}
// 确定是否需要"加法"版本
const bool branchfree = false; // 使用分支版本
if (!branchfree && e < ((uint32_t)1 << floor_log_2_d)) {
// 这个幂次有效
more = (uint8_t)(floor_log_2_d - 1);
if (DEBUG) {
std::cout << "[SR] Using basic algorithm, shift = " << (int)more << std::endl;
}
} else {
// 我们需要上升一个等级
proposed_m += proposed_m;
const uint32_t twice_rem = rem + rem;
if (twice_rem >= absD || twice_rem < rem) {
proposed_m += 1;
}
more = (uint8_t)(floor_log_2_d | LIBDIVIDE_ADD_MARKER);
if (DEBUG) {
std::cout << "[SR] Using add algorithm, proposed_m = " << proposed_m << ", more = " << (int)more << std::endl;
}
}
proposed_m += 1;
int32_t magic = (int32_t)proposed_m;
// 处理负除数
if (d < 0) {
more |= LIBDIVIDE_NEGATIVE_DIVISOR;
if (!branchfree) {
magic = -magic;
}
if (DEBUG) {
std::cout << "[SR] Negative divisor, magic = " << magic << ", more = " << (int)more << std::endl;
}
}
// 为我们的IR生成提取移位量和标志
int shift = more & 0x3F; // 移除标志保留移位量位0-5
bool need_add = (more & LIBDIVIDE_ADD_MARKER) != 0;
bool is_negative = (more & LIBDIVIDE_NEGATIVE_DIVISOR) != 0;
if (DEBUG) {
std::cout << "[SR] Final result: magic = " << magic << ", more = " << (int)more
<< " (0x" << std::hex << (int)more << std::dec << ")" << std::endl;
std::cout << "[SR] Shift = " << shift << ", need_add = " << need_add
<< ", is_negative = " << is_negative << std::endl;
// Test the magic number using the correct libdivide algorithm
std::cout << "[SR] Testing magic number (libdivide algorithm):" << std::endl;
int test_values[] = {1, 7, 37, 100, 999, -1, -7, -37, -100};
for (int test_val : test_values) {
int64_t quotient;
// 实现正确的libdivide算法
int64_t product = (int64_t)test_val * magic;
int64_t high_bits = product >> 32;
if (need_add) {
// ADD_MARKER情况移位前加上被除数
// 这是libdivide的关键洞察
high_bits += test_val;
quotient = high_bits >> shift;
} else {
// 正常情况:只是移位
quotient = high_bits >> shift;
}
// 符号修正这是libdivide有符号除法的关键部分
// 如果被除数为负商需要加1来匹配C语言的截断除法语义
if (test_val < 0) {
quotient += 1;
}
int expected = test_val / divisor;
bool correct = (quotient == expected);
std::cout << "[SR] " << test_val << " / " << divisor << " = " << quotient
<< " (expected " << expected << ") " << (correct ? "" : "") << std::endl;
}
std::cout << "[SR] ===== End magic computation =====" << std::endl;
}
// 返回魔数、移位量并在移位中编码ADD_MARKER标志
// 我们将使用移位的第6位表示ADD_MARKER第7位表示负数如果需要
int encoded_shift = shift;
if (need_add) {
encoded_shift |= 0x40; // 设置第6位表示ADD_MARKER
if (DEBUG) {
std::cout << "[SR] Encoding ADD_MARKER in shift: " << encoded_shift << std::endl;
}
}
return {magic, encoded_shift};
}
bool LoopStrengthReduction::runOnFunction(Function* F, AnalysisManager& AM) {
if (F->getBasicBlocks().empty()) {
@ -1018,7 +837,7 @@ Value* StrengthReductionContext::generateConstantDivisionReplacement(
IRBuilder* builder
) const {
// 使用mulh指令优化任意常数除法
auto [magic, shift] = computeMulhMagicNumbers(candidate->multiplier);
auto [magic, shift] = SysYIROptUtils::computeMulhMagicNumbers(candidate->multiplier);
// 检查是否无法优化magic == -1, shift == -1 表示失败)
if (magic == -1 && shift == -1) {

View File

@ -70,20 +70,20 @@ void Reg2MemContext::allocateMemoryForSSAValues(Function *func) {
// 1. 为函数参数分配内存
builder->setPosition(entryBlock, entryBlock->begin()); // 确保在入口块的开始位置插入
for (auto arg : func->getArguments()) {
// 默认情况下,将所有参数是提升到内存
if (isPromotableToMemory(arg)) {
// 参数的类型就是 AllocaInst 需要分配的类型
AllocaInst *alloca = builder->createAllocaInst(Type::getPointerType(arg->getType()), arg->getName() + ".reg2mem");
// 将参数值 store 到 alloca 中 (这是 Mem2Reg 逆转的关键一步)
valueToAllocaMap[arg] = alloca;
// for (auto arg : func->getArguments()) {
// // 默认情况下,将所有参数是提升到内存
// if (isPromotableToMemory(arg)) {
// // 参数的类型就是 AllocaInst 需要分配的类型
// AllocaInst *alloca = builder->createAllocaInst(Type::getPointerType(arg->getType()), arg->getName() + ".reg2mem");
// // 将参数值 store 到 alloca 中 (这是 Mem2Reg 逆转的关键一步)
// valueToAllocaMap[arg] = alloca;
// 确保 alloca 位于入口块的顶部,但在所有参数的 store 指令之前
// 通常 alloca 都在 entry block 的最开始
// 这里我们只是创建,并让 builder 决定插入位置 (通常在当前插入点)
// 如果需要严格控制顺序,可能需要手动 insert 到 instruction list
}
}
// // 确保 alloca 位于入口块的顶部,但在所有参数的 store 指令之前
// // 通常 alloca 都在 entry block 的最开始
// // 这里我们只是创建,并让 builder 决定插入位置 (通常在当前插入点)
// // 如果需要严格控制顺序,可能需要手动 insert 到 instruction list
// }
// }
// 2. 为指令结果分配内存
// 遍历所有基本块和指令,找出所有需要分配 Alloca 的指令结果
@ -123,11 +123,11 @@ void Reg2MemContext::allocateMemoryForSSAValues(Function *func) {
}
// 插入所有参数的初始 Store 指令
for (auto arg : func->getArguments()) {
if (valueToAllocaMap.count(arg)) { // 检查是否为其分配了 alloca
builder->createStoreInst(arg, valueToAllocaMap[arg]);
}
}
// for (auto arg : func->getArguments()) {
// if (valueToAllocaMap.count(arg)) { // 检查是否为其分配了 alloca
// builder->createStoreInst(arg, valueToAllocaMap[arg]);
// }
// }
builder->setPosition(entryBlock, entryBlock->terminator());
}

View File

@ -0,0 +1,125 @@
#include "TailCallOpt.h"
#include "IR.h"
#include "IRBuilder.h"
#include "SysYIROptUtils.h"
#include <vector>
// #include <iostream>
#include <algorithm>
namespace sysy {
void *TailCallOpt::ID = (void *)&TailCallOpt::ID;
void TailCallOpt::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID);
analysisInvalidations.insert(&LoopAnalysisPass::ID);
}
bool TailCallOpt::runOnFunction(Function *F, AnalysisManager &AM) {
std::vector<CallInst *> tailCallInsts;
// 遍历函数的所有基本块
for (auto &bb_ptr : F->getBasicBlocks()) {
auto BB = bb_ptr.get();
if (BB->getInstructions().empty()) continue; // 跳过空基本块
auto term_iter = BB->terminator();
if (term_iter == BB->getInstructions().end()) continue; // 没有终结指令则跳过
auto term = (*term_iter).get();
if (!term || !term->isReturn()) continue; // 不是返回指令则跳过
auto retInst = static_cast<ReturnInst *>(term);
Instruction *prevInst = nullptr;
if (BB->getInstructions().size() > 1) {
auto it = term_iter;
--it; // 获取返回指令前的指令
prevInst = (*it).get();
}
if (!prevInst || !prevInst->isCall()) continue; // 前一条不是调用指令则跳过
auto callInst = static_cast<CallInst *>(prevInst);
// 检查是否为尾递归调用:被调用函数与当前函数相同且返回值与调用结果匹配
if (callInst->getCallee() == F) {
// 对于尾递归,返回值应为调用结果或为 void 类型
if (retInst->getReturnValue() == callInst ||
(retInst->getReturnValue() == nullptr && callInst->getType()->isVoid())) {
tailCallInsts.push_back(callInst);
}
}
}
if (tailCallInsts.empty()) {
return false;
}
// 创建一个新的入口基本块,作为循环的前置块
auto original_entry = F->getEntryBlock();
auto new_entry = F->addBasicBlock("tco.entry." + F->getName());
auto loop_header = F->addBasicBlock("tco.loop_header." + F->getName());
// 将原入口块中的所有指令移动到循环头块
loop_header->getInstructions().splice(loop_header->end(), original_entry->getInstructions());
original_entry->setName("tco.pre_header");
// 为函数参数创建 phi 节点
builder->setPosition(loop_header, loop_header->begin());
std::vector<PhiInst *> phis;
auto original_args = F->getArguments();
for (auto &arg : original_args) {
auto phi = builder->createPhiInst(arg->getType(), {}, {}, "tco.phi."+arg->getName());
phis.push_back(phi);
}
// 用 phi 节点替换所有原始参数的使用
for (size_t i = 0; i < original_args.size(); ++i) {
original_args[i]->replaceAllUsesWith(phis[i]);
}
// 设置 phi 节点的输入值
for (size_t i = 0; i < phis.size(); ++i) {
phis[i]->addIncoming(original_args[i], new_entry);
}
// 连接各个基本块
builder->setPosition(original_entry, original_entry->end());
builder->createUncondBrInst(new_entry);
original_entry->addSuccessor(new_entry);
builder->setPosition(new_entry, new_entry->end());
builder->createUncondBrInst(loop_header);
new_entry->addSuccessor(loop_header);
loop_header->addPredecessor(new_entry);
// 处理每一个尾递归调用
for (auto callInst : tailCallInsts) {
auto tail_call_block = callInst->getParent();
// 收集尾递归调用的参数
auto args_range = callInst->getArguments();
std::vector<Value*> args;
std::transform(args_range.begin(), args_range.end(), std::back_inserter(args),
[](auto& use_ptr){ return use_ptr->getValue(); });
// 用新的参数值更新 phi 节点
for (size_t i = 0; i < phis.size(); ++i) {
phis[i]->addIncoming(args[i], tail_call_block);
}
// 移除原有的调用和返回指令
auto term_iter = tail_call_block->terminator();
SysYIROptUtils::usedelete(term_iter);
auto call_iter = tail_call_block->findInstIterator(callInst);
SysYIROptUtils::usedelete(call_iter);
// 添加跳转回循环头块的分支指令
builder->setPosition(tail_call_block, tail_call_block->end());
builder->createUncondBrInst(loop_header);
tail_call_block->addSuccessor(loop_header);
loop_header->addPredecessor(tail_call_block);
}
return true;
}
} // namespace sysy

View File

@ -10,13 +10,15 @@
#include "DCE.h"
#include "Mem2Reg.h"
#include "Reg2Mem.h"
#include "GVN.h"
#include "SCCP.h"
#include "BuildCFG.h"
#include "LargeArrayToGlobal.h"
#include "LoopNormalization.h"
#include "LICM.h"
#include "LoopStrengthReduction.h"
#include "InductionVariableElimination.h"
#include "GlobalStrengthReduction.h"
#include "TailCallOpt.h"
#include "Pass.h"
#include <iostream>
#include <queue>
@ -58,7 +60,7 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
// 注册优化遍
registerOptimizationPass<BuildCFG>();
registerOptimizationPass<LargeArrayToGlobalPass>();
registerOptimizationPass<GVN>();
registerOptimizationPass<SysYDelInstAfterBrPass>();
registerOptimizationPass<SysYDelNoPreBLockPass>();
@ -74,7 +76,10 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
registerOptimizationPass<LICM>(builderIR);
registerOptimizationPass<LoopStrengthReduction>(builderIR);
registerOptimizationPass<InductionVariableElimination>();
registerOptimizationPass<GlobalStrengthReduction>(builderIR);
registerOptimizationPass<Reg2Mem>(builderIR);
registerOptimizationPass<TailCallOpt>(builderIR);
registerOptimizationPass<SCCP>(builderIR);
@ -90,7 +95,6 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
this->clearPasses();
this->addPass(&BuildCFG::ID);
this->addPass(&LargeArrayToGlobalPass::ID);
this->run();
this->clearPasses();
@ -129,6 +133,25 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
printPasses();
}
this->clearPasses();
this->addPass(&GVN::ID);
this->run();
this->clearPasses();
this->addPass(&TailCallOpt::ID);
this->run();
if(DEBUG) {
std::cout << "=== IR After TailCallOpt ===\n";
SysYPrinter printer(moduleIR);
printer.printIR();
}
if(DEBUG) {
std::cout << "=== IR After GVN Optimizations ===\n";
printPasses();
}
this->clearPasses();
this->addPass(&SCCP::ID);
this->run();
@ -140,20 +163,47 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
this->clearPasses();
this->addPass(&LoopNormalizationPass::ID);
this->addPass(&LICM::ID);
this->addPass(&LoopStrengthReduction::ID);
this->addPass(&InductionVariableElimination::ID);
this->run();
if(DEBUG) {
std::cout << "=== IR After Loop Normalization, LICM, and Strength Reduction Optimizations ===\n";
std::cout << "=== IR After Loop Normalization, Induction Variable Elimination ===\n";
printPasses();
}
this->clearPasses();
this->addPass(&LICM::ID);
this->run();
if(DEBUG) {
std::cout << "=== IR After LICM ===\n";
printPasses();
}
// this->clearPasses();
// this->addPass(&LoopStrengthReduction::ID);
// this->run();
if(DEBUG) {
std::cout << "=== IR After Loop Normalization, and Strength Reduction Optimizations ===\n";
printPasses();
}
// // 全局强度削弱优化,包括代数优化和魔数除法
// this->clearPasses();
// this->addPass(&Reg2Mem::ID);
// this->addPass(&GlobalStrengthReduction::ID);
// this->run();
if(DEBUG) {
std::cout << "=== IR After Global Strength Reduction Optimizations ===\n";
printPasses();
}
this->clearPasses();
this->addPass(&Reg2Mem::ID);
this->run();
if(DEBUG) {
std::cout << "=== IR After Reg2Mem Optimizations ===\n";
printPasses();

View File

@ -262,10 +262,12 @@ void SysYIRGenerator::compute() {
}
// 弹出BinaryExpStack的表达式
while(begin < end) {
int count = end - begin;
for (int i = 0; i < count; i++) {
BinaryExpStack.pop_back();
BinaryExpLenStack.back()--;
end--;
}
if (!BinaryExpLenStack.empty()) {
BinaryExpLenStack.back() -= count;
}
// 计算后缀表达式

View File

@ -28,7 +28,7 @@ static string argStopAfter;
static string argInputFile;
static bool argFormat = false; // 目前未使用,但保留
static string argOutputFilename;
static int optLevel = 0; // 优化级别默认为0 (不加-O参数时)
int optLevel = 0; // 优化级别默认为0 (不加-O参数时)
void usage(int code) {
const char *msg = "Usage: sysyc [options] inputfile\n\n"