Compare commits
89 Commits
midend-SCC
...
deploy-202
| Author | SHA1 | Date | |
|---|---|---|---|
| 86c33eac05 | |||
|
|
db00d02494 | ||
|
|
926e765451 | ||
|
|
c4d1e31273 | ||
|
|
de1f74c425 | ||
|
|
3ba12bf320 | ||
|
|
167c2ac2ae | ||
|
|
32684d8255 | ||
| f2477c4af3 | |||
| b1efd481b4 | |||
|
|
676880ca05 | ||
|
|
df50eedaeb | ||
|
|
dcc075b39c | ||
|
|
f7f1cf2b41 | ||
|
|
881c2a9723 | ||
|
|
b5f14d9385 | ||
|
|
72b06c67ca | ||
|
|
4db3cc3fb5 | ||
|
|
17f1bed310 | ||
|
|
b848ffca5a | ||
|
|
603506d142 | ||
|
|
0179c13cf4 | ||
| 7e5f6800b7 | |||
|
|
64ba25a77e | ||
|
|
208d5528b5 | ||
|
|
a269366ac5 | ||
|
|
1b9a7a4827 | ||
| b2c2f3289d | |||
| 0ecd47f0ac | |||
| 6550c8a25b | |||
|
|
f24cc7ec88 | ||
|
|
c8a8bf9a37 | ||
|
|
446a6a6fcb | ||
|
|
d8b004e5e5 | ||
|
|
cd814de495 | ||
|
|
e4ad23a1a5 | ||
|
|
58c8cd53f5 | ||
|
|
ec91a4e259 | ||
|
|
91f755959b | ||
|
|
92c89f7616 | ||
|
|
66047dc6a3 | ||
|
|
22cf18a1d6 | ||
|
|
19a433c94f | ||
|
|
45dfbc8d59 | ||
|
|
f8e423f579 | ||
|
|
5b43f208ac | ||
|
|
845f969c2e | ||
| 9c5d9ea78c | |||
| 0ce742a86e | |||
| f312792fe9 | |||
|
|
32ea24df56 | ||
|
|
a1cf60c420 | ||
|
|
f879a0f521 | ||
|
|
004ef82488 | ||
|
|
8f1d592d4e | ||
|
|
537533ee43 | ||
|
|
bfe218be07 | ||
|
|
384f7c548b | ||
|
|
57fe17dc21 | ||
|
|
e48cddab9f | ||
|
|
aef10b48e8 | ||
|
|
373726b02f | ||
|
|
a0b69f20fb | ||
|
|
999f2c6615 | ||
|
|
1eedb55ca0 | ||
|
|
8fe9867f33 | ||
|
|
166d0fc372 | ||
|
|
873dbf64d0 | ||
|
|
f387aecc03 | ||
|
|
03e88eee70 | ||
|
|
e8699d6d25 | ||
|
|
0727d5a6d8 | ||
|
|
fc7afdbb35 | ||
|
|
bfe2b248cd | ||
|
|
6d60522ce2 | ||
| 807fb3f560 | |||
|
|
82288464c3 | ||
|
|
7e8b90ffd4 | ||
|
|
b3cf3cba29 | ||
|
|
03b62b138f | ||
|
|
8e94f89931 | ||
|
|
b388dc4542 | ||
|
|
48b0aec6c3 | ||
|
|
1fb5cd398d | ||
|
|
877a0f5dc2 | ||
| a3c4d5a2b8 | |||
|
|
39c13c46ec | ||
|
|
dd38bdc133 | ||
| 860ebcd447 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -36,6 +36,7 @@ doxygen
|
||||
|
||||
!/testdata/functional/*.out
|
||||
!/testdata/h_functional/*.out
|
||||
!/testdata/performance/*.out
|
||||
build/
|
||||
.antlr
|
||||
.vscode/
|
||||
|
||||
272
CompilerDesign.md
Normal file
272
CompilerDesign.md
Normal file
@@ -0,0 +1,272 @@
|
||||
# 编译器核心技术与优化详解
|
||||
|
||||
本文档深入剖析 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. 其他优化
|
||||
|
||||
- **LargeArrayToGlobal (`LargeArrayToGlobal.cpp`)**:
|
||||
- **目标**: 防止因大型局部数组导致的栈溢出,并可能改善数据局部性。
|
||||
- **技术**: 遍历函数中的 `alloca` 指令,如果通过 `calculateTypeSize` 计算出其分配的内存大小超过一个阈值(如 1024 字节),则将其转换为一个全局变量。
|
||||
- **实现**: `convertAllocaToGlobal` 函数负责创建一个新的 `GlobalValue`,并调用 `replaceAllUsesWith` 将原 `alloca` 的所有使用者重定向到新的全局变量,最后删除原 `alloca` 指令。
|
||||
|
||||
#### 3.3. 核心分析遍
|
||||
|
||||
为了为优化遍收集信息,最大程度发掘程序优化潜力,我们目前设计并实现了以下关键的分析遍:
|
||||
|
||||
- **支配树分析 (Dominator Tree Analysis)**:
|
||||
- **技术**: 通过计算每个基本块的支配节点,构建出一棵支配树结构。我们在计算支配节点时采用了**逆后序遍历(RPO, Reverse Post Order)**,以保证数据流分析的收敛速度和正确性。在计算直接支配者(Idom, Immediate Dominator)时,采用了经典的**Lengauer-Tarjan(LT)算法**,该算法以高效的并查集和路径压缩技术著称,能够在线性时间内准确计算出每个基本块的直接支配者关系。
|
||||
- **实现**: `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)和过程间优化来进一步提升性能。
|
||||
2732
doc/Doxyfile
2732
doc/Doxyfile
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 346 KiB |
@@ -1,169 +0,0 @@
|
||||
这个头文件定义了一个用于生成中间表示(IR)的数据结构,主要用于编译器前端将抽象语法树(AST)转换为中间代码。以下是文件中定义的主要类和功能的整理和解释:
|
||||
|
||||
---
|
||||
|
||||
### **1. 类型系统(Type System)**
|
||||
#### **1.1 `Type` 类**
|
||||
- **作用**:表示所有基本标量类型(如 `int`、`float`、`void` 等)以及指针类型和函数类型。
|
||||
- **成员**:
|
||||
- `Kind` 枚举:表示类型的种类(如 `kInt`、`kFloat`、`kPointer` 等)。
|
||||
- `kind`:当前类型的种类。
|
||||
- 构造函数:`Type(Kind kind)`,用于初始化类型。
|
||||
- 静态方法:如 `getIntType()`、`getFloatType()` 等,用于获取特定类型的单例对象。
|
||||
- 类型检查方法:如 `isInt()`、`isFloat()` 等,用于检查当前类型是否为某种类型。
|
||||
- `getSize()`:获取类型的大小。
|
||||
- `as<T>()`:将当前类型动态转换为派生类(如 `PointerType` 或 `FunctionType`)。
|
||||
|
||||
#### **1.2 `PointerType` 类**
|
||||
- **作用**:表示指针类型,派生自 `Type`。
|
||||
- **成员**:
|
||||
- `baseType`:指针指向的基础类型。
|
||||
- 静态方法:`get(Type *baseType)`,用于获取指向 `baseType` 的指针类型。
|
||||
- `getBaseType()`:获取指针指向的基础类型。
|
||||
|
||||
#### **1.3 `FunctionType` 类**
|
||||
- **作用**:表示函数类型,派生自 `Type`。
|
||||
- **成员**:
|
||||
- `returnType`:函数的返回类型。
|
||||
- `paramTypes`:函数的参数类型列表。
|
||||
- 静态方法:`get(Type *returnType, const std::vector<Type *> ¶mTypes)`,用于获取函数类型。
|
||||
- `getReturnType()`:获取函数的返回类型。
|
||||
- `getParamTypes()`:获取函数的参数类型列表。
|
||||
|
||||
---
|
||||
|
||||
### **2. 中间表示(IR)**
|
||||
#### **2.1 `Value` 类**
|
||||
- **作用**:表示 IR 中的所有值(如指令、常量、参数等)。
|
||||
- **成员**:
|
||||
- `Kind` 枚举:表示值的种类(如 `kAdd`、`kSub`、`kConstant` 等)。
|
||||
- `kind`:当前值的种类。
|
||||
- `type`:值的类型。
|
||||
- `name`:值的名称。
|
||||
- `uses`:值的用途列表(表示哪些指令使用了该值)。
|
||||
- 构造函数:`Value(Kind kind, Type *type, const std::string &name)`。
|
||||
- 类型检查方法:如 `isInt()`、`isFloat()` 等。
|
||||
- `getUses()`:获取值的用途列表。
|
||||
- `replaceAllUsesWith(Value *value)`:将该值的所有用途替换为另一个值。
|
||||
- `print(std::ostream &os)`:打印值的表示。
|
||||
|
||||
#### **2.2 `ConstantValue` 类**
|
||||
- **作用**:表示编译时常量(如整数常量、浮点数常量)。
|
||||
- **成员**:
|
||||
- `iScalar` 和 `fScalar`:分别存储整数和浮点数常量的值。
|
||||
- 静态方法:`get(int value)` 和 `get(float value)`,用于获取常量值。
|
||||
- `getInt()` 和 `getFloat()`:获取常量的值。
|
||||
|
||||
#### **2.3 `Argument` 类**
|
||||
- **作用**:表示函数或基本块的参数。
|
||||
- **成员**:
|
||||
- `block`:参数所属的基本块。
|
||||
- `index`:参数的索引。
|
||||
- 构造函数:`Argument(Type *type, BasicBlock *block, int index, const std::string &name)`。
|
||||
- `getParent()`:获取参数所属的基本块。
|
||||
- `getIndex()`:获取参数的索引。
|
||||
|
||||
#### **2.4 `BasicBlock` 类**
|
||||
- **作用**:表示基本块,包含一系列指令。
|
||||
- **成员**:
|
||||
- `parent`:基本块所属的函数。
|
||||
- `instructions`:基本块中的指令列表。
|
||||
- `arguments`:基本块的参数列表。
|
||||
- `successors` 和 `predecessors`:基本块的后继和前驱列表。
|
||||
- 构造函数:`BasicBlock(Function *parent, const std::string &name)`。
|
||||
- `getParent()`:获取基本块所属的函数。
|
||||
- `getInstructions()`:获取基本块中的指令列表。
|
||||
- `createArgument()`:为基本块创建一个参数。
|
||||
|
||||
#### **2.5 `Instruction` 类**
|
||||
- **作用**:表示 IR 中的指令,派生自 `User`。
|
||||
- **成员**:
|
||||
- `Kind` 枚举:表示指令的种类(如 `kAdd`、`kSub`、`kLoad` 等)。
|
||||
- `kind`:当前指令的种类。
|
||||
- `parent`:指令所属的基本块。
|
||||
- 构造函数:`Instruction(Kind kind, Type *type, BasicBlock *parent, const std::string &name)`。
|
||||
- `getParent()`:获取指令所属的基本块。
|
||||
- `getFunction()`:获取指令所属的函数。
|
||||
- 指令分类方法:如 `isBinary()`、`isUnary()`、`isMemory()` 等。
|
||||
|
||||
#### **2.6 `User` 类**
|
||||
- **作用**:表示使用其他值的指令或全局值,派生自 `Value`。
|
||||
- **成员**:
|
||||
- `operands`:指令的操作数列表。
|
||||
- 构造函数:`User(Kind kind, Type *type, const std::string &name)`。
|
||||
- `getOperand(int index)`:获取指定索引的操作数。
|
||||
- `addOperand(Value *value)`:添加一个操作数。
|
||||
- `replaceOperand(int index, Value *value)`:替换指定索引的操作数。
|
||||
|
||||
#### **2.7 具体指令类**
|
||||
- **`CallInst`**:表示函数调用指令。
|
||||
- **`UnaryInst`**:表示一元操作指令(如取反、类型转换)。
|
||||
- **`BinaryInst`**:表示二元操作指令(如加法、减法)。
|
||||
- **`ReturnInst`**:表示返回指令。
|
||||
- **`UncondBrInst`**:表示无条件跳转指令。
|
||||
- **`CondBrInst`**:表示条件跳转指令。
|
||||
- **`AllocaInst`**:表示栈内存分配指令。
|
||||
- **`LoadInst`**:表示从内存加载值的指令。
|
||||
- **`StoreInst`**:表示将值存储到内存的指令。
|
||||
|
||||
---
|
||||
|
||||
### **3. 模块和函数**
|
||||
#### **3.1 `Function` 类**
|
||||
- **作用**:表示函数,包含多个基本块。
|
||||
- **成员**:
|
||||
- `parent`:函数所属的模块。
|
||||
- `blocks`:函数中的基本块列表。
|
||||
- 构造函数:`Function(Module *parent, Type *type, const std::string &name)`。
|
||||
- `getReturnType()`:获取函数的返回类型。
|
||||
- `getParamTypes()`:获取函数的参数类型列表。
|
||||
- `addBasicBlock()`:为函数添加一个基本块。
|
||||
|
||||
#### **3.2 `GlobalValue` 类**
|
||||
- **作用**:表示全局变量或常量。
|
||||
- **成员**:
|
||||
- `parent`:全局值所属的模块。
|
||||
- `hasInit`:是否有初始化值。
|
||||
- `isConst`:是否是常量。
|
||||
- 构造函数:`GlobalValue(Module *parent, Type *type, const std::string &name, const std::vector<Value *> &dims, Value *init)`。
|
||||
- `init()`:获取全局值的初始化值。
|
||||
|
||||
#### **3.3 `Module` 类**
|
||||
- **作用**:表示整个编译单元(如一个源文件)。
|
||||
- **成员**:
|
||||
- `children`:模块中的所有值(如函数、全局变量)。
|
||||
- `functions`:模块中的函数列表。
|
||||
- `globals`:模块中的全局变量列表。
|
||||
- `createFunction()`:创建一个函数。
|
||||
- `createGlobalValue()`:创建一个全局变量。
|
||||
- `getFunction()`:获取指定名称的函数。
|
||||
- `getGlobalValue()`:获取指定名称的全局变量。
|
||||
|
||||
---
|
||||
|
||||
### **4. 工具类**
|
||||
#### **4.1 `Use` 类**
|
||||
- **作用**:表示值与其使用者之间的关系。
|
||||
- **成员**:
|
||||
- `index`:值在使用者操作数列表中的索引。
|
||||
- `user`:使用者。
|
||||
- `value`:被使用的值。
|
||||
- 构造函数:`Use(int index, User *user, Value *value)`。
|
||||
- `getValue()`:获取被使用的值。
|
||||
|
||||
#### **4.2 `range` 类**
|
||||
- **作用**:封装迭代器对 `[begin, end)`,用于遍历容器。
|
||||
- **成员**:
|
||||
- `begin()` 和 `end()`:返回范围的起始和结束迭代器。
|
||||
- `size()`:返回范围的大小。
|
||||
- `empty()`:判断范围是否为空。
|
||||
|
||||
---
|
||||
|
||||
### **5. 总结**
|
||||
- **类型系统**:`Type`、`PointerType`、`FunctionType` 用于表示 IR 中的类型。
|
||||
- **中间表示**:`Value`、`ConstantValue`、`Instruction` 等用于表示 IR 中的值和指令。
|
||||
- **模块和函数**:`Module`、`Function`、`GlobalValue` 用于组织 IR 的结构。
|
||||
- **工具类**:`Use` 和 `range` 用于辅助实现 IR 的数据结构和遍历。
|
||||
|
||||
这个头文件定义了一个完整的 IR 数据结构,适用于编译器前端将 AST 转换为中间代码,并支持后续的优化和目标代码生成。
|
||||
@@ -1,156 +0,0 @@
|
||||
`IRBuilder.h` 文件定义了一个 `IRBuilder` 类,用于简化中间表示(IR)的构建过程。`IRBuilder` 提供了创建各种 IR 指令的便捷方法,并将这些指令插入到指定的基本块中。以下是对文件中主要内容的整理和解释:
|
||||
|
||||
---
|
||||
|
||||
### **1. `IRBuilder` 类的作用**
|
||||
`IRBuilder` 是一个工具类,用于在生成中间表示(IR)时简化指令的创建和插入操作。它的主要功能包括:
|
||||
- 提供创建各种 IR 指令的工厂方法。
|
||||
- 将创建的指令插入到指定的基本块中。
|
||||
- 支持在基本块的任意位置插入指令。
|
||||
|
||||
---
|
||||
|
||||
### **2. 主要成员**
|
||||
|
||||
#### **2.1 成员变量**
|
||||
- **`block`**:当前操作的基本块。
|
||||
- **`position`**:当前操作的插入位置(基本块中的迭代器)。
|
||||
|
||||
#### **2.2 构造函数**
|
||||
- **默认构造函数**:`IRBuilder()`。
|
||||
- **带参数的构造函数**:
|
||||
- `IRBuilder(BasicBlock *block)`:初始化 `IRBuilder`,并设置当前基本块和插入位置(默认在基本块末尾)。
|
||||
- `IRBuilder(BasicBlock *block, BasicBlock::iterator position)`:初始化 `IRBuilder`,并设置当前基本块和插入位置。
|
||||
|
||||
#### **2.3 设置方法**
|
||||
- **`setPosition(BasicBlock *block, BasicBlock::iterator position)`**:设置当前基本块和插入位置。
|
||||
- **`setPosition(BasicBlock::iterator position)`**:设置当前插入位置。
|
||||
|
||||
#### **2.4 获取方法**
|
||||
- **`getBasicBlock()`**:获取当前基本块。
|
||||
- **`getPosition()`**:获取当前插入位置。
|
||||
|
||||
---
|
||||
|
||||
### **3. 指令创建方法**
|
||||
`IRBuilder` 提供了多种工厂方法,用于创建不同类型的 IR 指令。这些方法会将创建的指令插入到当前基本块的指定位置。
|
||||
|
||||
#### **3.1 函数调用指令**
|
||||
- **`createCallInst(Function *callee, const std::vector<Value *> &args, const std::string &name)`**:
|
||||
- 创建一个函数调用指令。
|
||||
- 参数:
|
||||
- `callee`:被调用的函数。
|
||||
- `args`:函数参数列表。
|
||||
- `name`:指令的名称(可选)。
|
||||
- 返回:`CallInst*`。
|
||||
|
||||
#### **3.2 一元操作指令**
|
||||
- **`createUnaryInst(Instruction::Kind kind, Type *type, Value *operand, const std::string &name)`**:
|
||||
- 创建一个一元操作指令(如取反、类型转换)。
|
||||
- 参数:
|
||||
- `kind`:指令的类型(如 `kNeg`、`kFtoI` 等)。
|
||||
- `type`:指令的结果类型。
|
||||
- `operand`:操作数。
|
||||
- `name`:指令的名称(可选)。
|
||||
- 返回:`UnaryInst*`。
|
||||
|
||||
- **具体一元操作指令**:
|
||||
- `createNegInst(Value *operand, const std::string &name)`:创建整数取反指令。
|
||||
- `createNotInst(Value *operand, const std::string &name)`:创建逻辑取反指令。
|
||||
- `createFtoIInst(Value *operand, const std::string &name)`:创建浮点数转整数指令。
|
||||
- `createFNegInst(Value *operand, const std::string &name)`:创建浮点数取反指令。
|
||||
- `createIToFInst(Value *operand, const std::string &name)`:创建整数转浮点数指令。
|
||||
|
||||
#### **3.3 二元操作指令**
|
||||
- **`createBinaryInst(Instruction::Kind kind, Type *type, Value *lhs, Value *rhs, const std::string &name)`**:
|
||||
- 创建一个二元操作指令(如加法、减法)。
|
||||
- 参数:
|
||||
- `kind`:指令的类型(如 `kAdd`、`kSub` 等)。
|
||||
- `type`:指令的结果类型。
|
||||
- `lhs` 和 `rhs`:左操作数和右操作数。
|
||||
- `name`:指令的名称(可选)。
|
||||
- 返回:`BinaryInst*`。
|
||||
|
||||
- **具体二元操作指令**:
|
||||
- 整数运算:
|
||||
- `createAddInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数加法指令。
|
||||
- `createSubInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数减法指令。
|
||||
- `createMulInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数乘法指令。
|
||||
- `createDivInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数除法指令。
|
||||
- `createRemInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数取余指令。
|
||||
- 整数比较:
|
||||
- `createICmpEQInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数相等比较指令。
|
||||
- `createICmpNEInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数不等比较指令。
|
||||
- `createICmpLTInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数小于比较指令。
|
||||
- `createICmpLEInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数小于等于比较指令。
|
||||
- `createICmpGTInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数大于比较指令。
|
||||
- `createICmpGEInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数大于等于比较指令。
|
||||
- 浮点数运算:
|
||||
- `createFAddInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数加法指令。
|
||||
- `createFSubInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数减法指令。
|
||||
- `createFMulInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数乘法指令。
|
||||
- `createFDivInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数除法指令。
|
||||
- `createFRemInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数取余指令。
|
||||
- 浮点数比较:
|
||||
- `createFCmpEQInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数相等比较指令。
|
||||
- `createFCmpNEInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数不等比较指令。
|
||||
- `createFCmpLTInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数小于比较指令。
|
||||
- `createFCmpLEInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数小于等于比较指令。
|
||||
- `createFCmpGTInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数大于比较指令。
|
||||
- `createFCmpGEInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数大于等于比较指令。
|
||||
|
||||
#### **3.4 控制流指令**
|
||||
- **`createReturnInst(Value *value)`**:
|
||||
- 创建返回指令。
|
||||
- 参数:
|
||||
- `value`:返回值(可选)。
|
||||
- 返回:`ReturnInst*`。
|
||||
|
||||
- **`createUncondBrInst(BasicBlock *block, std::vector<Value *> args)`**:
|
||||
- 创建无条件跳转指令。
|
||||
- 参数:
|
||||
- `block`:目标基本块。
|
||||
- `args`:跳转参数(可选)。
|
||||
- 返回:`UncondBrInst*`。
|
||||
|
||||
- **`createCondBrInst(Value *condition, BasicBlock *thenBlock, BasicBlock *elseBlock, const std::vector<Value *> &thenArgs, const std::vector<Value *> &elseArgs)`**:
|
||||
- 创建条件跳转指令。
|
||||
- 参数:
|
||||
- `condition`:跳转条件。
|
||||
- `thenBlock`:条件为真时的目标基本块。
|
||||
- `elseBlock`:条件为假时的目标基本块。
|
||||
- `thenArgs` 和 `elseArgs`:跳转参数(可选)。
|
||||
- 返回:`CondBrInst*`。
|
||||
|
||||
#### **3.5 内存操作指令**
|
||||
- **`createAllocaInst(Type *type, const std::vector<Value *> &dims, const std::string &name)`**:
|
||||
- 创建栈内存分配指令。
|
||||
- 参数:
|
||||
- `type`:分配的类型。
|
||||
- `dims`:数组维度(可选)。
|
||||
- `name`:指令的名称(可选)。
|
||||
- 返回:`AllocaInst*`。
|
||||
|
||||
- **`createLoadInst(Value *pointer, const std::vector<Value *> &indices, const std::string &name)`**:
|
||||
- 创建加载指令。
|
||||
- 参数:
|
||||
- `pointer`:指针值。
|
||||
- `indices`:数组索引(可选)。
|
||||
- `name`:指令的名称(可选)。
|
||||
- 返回:`LoadInst*`。
|
||||
|
||||
- **`createStoreInst(Value *value, Value *pointer, const std::vector<Value *> &indices, const std::string &name)`**:
|
||||
- 创建存储指令。
|
||||
- 参数:
|
||||
- `value`:要存储的值。
|
||||
- `pointer`:指针值。
|
||||
- `indices`:数组索引(可选)。
|
||||
- `name`:指令的名称(可选)。
|
||||
- 返回:`StoreInst*`。
|
||||
|
||||
---
|
||||
|
||||
### **4. 总结**
|
||||
- `IRBuilder` 是一个用于简化 IR 构建的工具类,提供了创建各种 IR 指令的工厂方法。
|
||||
- 通过 `IRBuilder`,可以方便地在指定基本块的任意位置插入指令。
|
||||
- 该类的设计使得 IR 的生成更加模块化和易于维护。
|
||||
@@ -1,121 +0,0 @@
|
||||
这个 `IR.cpp` 文件实现了 `IR.h` 中定义的中间表示(IR)数据结构的功能。它包含了类型系统、值、指令、基本块、函数和模块的具体实现,以及一些辅助函数用于打印 IR 的内容。以下是对文件中主要内容的整理和解释:
|
||||
|
||||
---
|
||||
|
||||
### **1. 辅助函数**
|
||||
#### **1.1 `interleave` 函数**
|
||||
- **作用**:用于在输出流中插入分隔符(如逗号)来打印容器中的元素。
|
||||
- **示例**:
|
||||
```cpp
|
||||
interleave(os, container, ", ");
|
||||
```
|
||||
|
||||
#### **1.2 打印函数**
|
||||
- **`printVarName`**:打印变量名,全局变量以 `@` 开头,局部变量以 `%` 开头。
|
||||
- **`printBlockName`**:打印基本块名,以 `^` 开头。
|
||||
- **`printFunctionName`**:打印函数名,以 `@` 开头。
|
||||
- **`printOperand`**:打印操作数,如果是常量则直接打印值,否则打印变量名。
|
||||
|
||||
---
|
||||
|
||||
### **2. 类型系统**
|
||||
#### **2.1 `Type` 类的实现**
|
||||
- **静态方法**:
|
||||
- `getIntType()`、`getFloatType()`、`getVoidType()`、`getLabelType()`:返回对应类型的单例对象。
|
||||
- `getPointerType(Type *baseType)`:返回指向 `baseType` 的指针类型。
|
||||
- `getFunctionType(Type *returnType, const vector<Type *> ¶mTypes)`:返回函数类型。
|
||||
- **`getSize()`**:返回类型的大小(如 `int` 和 `float` 为 4 字节,指针为 8 字节)。
|
||||
- **`print()`**:打印类型的表示。
|
||||
|
||||
#### **2.2 `PointerType` 类的实现**
|
||||
- **静态方法**:
|
||||
- `get(Type *baseType)`:返回指向 `baseType` 的指针类型,使用 `std::map` 缓存已创建的指针类型。
|
||||
- **`getBaseType()`**:返回指针指向的基础类型。
|
||||
|
||||
#### **2.3 `FunctionType` 类的实现**
|
||||
- **静态方法**:
|
||||
- `get(Type *returnType, const vector<Type *> ¶mTypes)`:返回函数类型,使用 `std::set` 缓存已创建的函数类型。
|
||||
- **`getReturnType()`** 和 `getParamTypes()`:分别返回函数的返回类型和参数类型列表。
|
||||
|
||||
---
|
||||
|
||||
### **3. 值(Value)**
|
||||
#### **3.1 `Value` 类的实现**
|
||||
- **`replaceAllUsesWith(Value *value)`**:将该值的所有用途替换为另一个值。
|
||||
- **`isConstant()`**:判断值是否为常量(包括常量值、全局值和函数)。
|
||||
|
||||
#### **3.2 `ConstantValue` 类的实现**
|
||||
- **静态方法**:
|
||||
- `get(int value)` 和 `get(float value)`:返回整数或浮点数常量,使用 `std::map` 缓存已创建的常量。
|
||||
- **`getInt()` 和 `getFloat()`**:返回常量的值。
|
||||
- **`print()`**:打印常量的值。
|
||||
|
||||
#### **3.3 `Argument` 类的实现**
|
||||
- **构造函数**:初始化参数的类型、所属基本块和索引。
|
||||
- **`print()`**:打印参数的表示。
|
||||
|
||||
---
|
||||
|
||||
### **4. 基本块(BasicBlock)**
|
||||
#### **4.1 `BasicBlock` 类的实现**
|
||||
- **构造函数**:初始化基本块的名称和所属函数。
|
||||
- **`print()`**:打印基本块的表示,包括参数和指令。
|
||||
|
||||
---
|
||||
|
||||
### **5. 指令(Instruction)**
|
||||
#### **5.1 `Instruction` 类的实现**
|
||||
- **构造函数**:初始化指令的类型、所属基本块和名称。
|
||||
- **`print()`**:由具体指令类实现。
|
||||
|
||||
#### **5.2 具体指令类的实现**
|
||||
- **`CallInst`**:表示函数调用指令。
|
||||
- **`print()`**:打印函数调用的表示。
|
||||
- **`UnaryInst`**:表示一元操作指令(如取反、类型转换)。
|
||||
- **`print()`**:打印一元操作的表示。
|
||||
- **`BinaryInst`**:表示二元操作指令(如加法、减法)。
|
||||
- **`print()`**:打印二元操作的表示。
|
||||
- **`ReturnInst`**:表示返回指令。
|
||||
- **`print()`**:打印返回指令的表示。
|
||||
- **`UncondBrInst`**:表示无条件跳转指令。
|
||||
- **`print()`**:打印无条件跳转的表示。
|
||||
- **`CondBrInst`**:表示条件跳转指令。
|
||||
- **`print()`**:打印条件跳转的表示。
|
||||
- **`AllocaInst`**:表示栈内存分配指令。
|
||||
- **`print()`**:打印内存分配的表示。
|
||||
- **`LoadInst`**:表示从内存加载值的指令。
|
||||
- **`print()`**:打印加载指令的表示。
|
||||
- **`StoreInst`**:表示将值存储到内存的指令。
|
||||
- **`print()`**:打印存储指令的表示。
|
||||
|
||||
---
|
||||
|
||||
### **6. 函数(Function)**
|
||||
#### **6.1 `Function` 类的实现**
|
||||
- **构造函数**:初始化函数的名称、返回类型和参数类型。
|
||||
- **`print()`**:打印函数的表示,包括基本块和指令。
|
||||
|
||||
---
|
||||
|
||||
### **7. 模块(Module)**
|
||||
#### **7.1 `Module` 类的实现**
|
||||
- **`print()`**:打印模块的表示,包括所有函数和全局变量。
|
||||
|
||||
---
|
||||
|
||||
### **8. 用户(User)**
|
||||
#### **8.1 `User` 类的实现**
|
||||
- **`setOperand(int index, Value *value)`**:设置指定索引的操作数。
|
||||
- **`replaceOperand(int index, Value *value)`**:替换指定索引的操作数,并更新用途列表。
|
||||
|
||||
---
|
||||
|
||||
### **9. 总结**
|
||||
- **类型系统**:实现了 `Type`、`PointerType` 和 `FunctionType`,用于表示 IR 中的类型。
|
||||
- **值**:实现了 `Value`、`ConstantValue` 和 `Argument`,用于表示 IR 中的值和参数。
|
||||
- **基本块**:实现了 `BasicBlock`,用于组织指令。
|
||||
- **指令**:实现了多种具体指令类(如 `CallInst`、`BinaryInst` 等),用于表示 IR 中的操作。
|
||||
- **函数和模块**:实现了 `Function` 和 `Module`,用于组织 IR 的结构。
|
||||
- **打印功能**:通过 `print()` 方法,可以将 IR 的内容输出为可读的文本格式。
|
||||
|
||||
这个文件是编译器中间表示的核心实现,能够将抽象语法树(AST)转换为中间代码,并支持后续的优化和目标代码生成。
|
||||
20878
doc/n1124.pdf
20878
doc/n1124.pdf
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -60,11 +60,7 @@ display_file_content() {
|
||||
# 清理临时文件的函数
|
||||
clean_tmp() {
|
||||
echo "正在清理临时目录: ${TMP_DIR}"
|
||||
rm -rf "${TMP_DIR}"/*.s \
|
||||
"${TMP_DIR}"/*_sysyc_riscv64 \
|
||||
"${TMP_DIR}"/*_sysyc_riscv64.actual_out \
|
||||
"${TMP_DIR}"/*_sysyc_riscv64.expected_stdout \
|
||||
"${TMP_DIR}"/*_sysyc_riscv64.o
|
||||
rm -rf "${TMP_DIR}"/*
|
||||
echo "清理完成。"
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ QEMU_RISCV64="qemu-riscv64"
|
||||
# --- 初始化变量 ---
|
||||
EXECUTE_MODE=false
|
||||
CLEAN_MODE=false
|
||||
OPTIMIZE_FLAG="" # 用于存储 -O1 标志
|
||||
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
|
||||
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
|
||||
EXEC_TIMEOUT=5 # qemu 自动化执行超时 (秒)
|
||||
@@ -39,6 +40,7 @@ show_help() {
|
||||
echo "选项:"
|
||||
echo " -e, --executable 编译为可执行文件并运行测试 (必须)。"
|
||||
echo " -c, --clean 清理 tmp 临时目录下的所有文件。"
|
||||
echo " -O1 启用 sysyc 的 -O1 优化。"
|
||||
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 10)。"
|
||||
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
||||
echo " -et N 设置 qemu 自动化执行超时为 N 秒 (默认: 5)。"
|
||||
@@ -68,66 +70,64 @@ display_file_content() {
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# --- 参数解析 ---
|
||||
# 从参数中分离出 .sy 文件和选项
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
-e|--executable)
|
||||
EXECUTE_MODE=true
|
||||
;;
|
||||
-c|--clean)
|
||||
CLEAN_MODE=true
|
||||
shift
|
||||
;;
|
||||
-sct|-gct|-et|-ml|--max-lines)
|
||||
# 选项和其值将在下一个循环中处理
|
||||
;;
|
||||
-h|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
-*)
|
||||
# 检查是否是带值的选项
|
||||
if ! [[ ${args_processed+x} ]]; then
|
||||
args_processed=true # 标记已处理过参数
|
||||
# 重新处理所有参数
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-sct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-gct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-et) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
*.sy) SY_FILES+=("$1") ;;
|
||||
-e|--executable) ;; # 已在外部处理
|
||||
*) if ! [[ "$1" =~ ^[0-9]+$ ]]; then echo "未知选项或无效文件: $1"; show_help; exit 1; fi ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
fi
|
||||
;;
|
||||
*.sy)
|
||||
if [[ -f "$arg" ]]; then
|
||||
SY_FILES+=("$arg")
|
||||
else
|
||||
echo "警告: 文件不存在,已忽略: $arg"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
# 使用标准的 while 循环来健壮地处理任意顺序的参数
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-e|--executable)
|
||||
EXECUTE_MODE=true
|
||||
shift # 消耗选项
|
||||
;;
|
||||
-c|--clean)
|
||||
CLEAN_MODE=true
|
||||
shift # 消耗选项
|
||||
;;
|
||||
-O1)
|
||||
OPTIMIZE_FLAG="-O1"
|
||||
shift # 消耗选项
|
||||
;;
|
||||
-sct)
|
||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift 2; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi
|
||||
;;
|
||||
-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
|
||||
;;
|
||||
-h|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
-*) # 未知选项
|
||||
echo "未知选项: $1"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
*) # 其他参数被视为文件路径
|
||||
if [[ -f "$1" && "$1" == *.sy ]]; then
|
||||
SY_FILES+=("$1")
|
||||
else
|
||||
echo "警告: 无效文件或不是 .sy 文件,已忽略: $1"
|
||||
fi
|
||||
shift # 消耗文件参数
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
if ${CLEAN_MODE}; then
|
||||
echo "检测到 -c/--clean 选项,正在清空 ${TMP_DIR}..."
|
||||
if [ -d "${TMP_DIR}" ]; then
|
||||
# 使用 * 而不是 . 来确保只删除内容,不删除目录本身
|
||||
# 忽略 rm 可能因目录为空而报告的错误
|
||||
rm -rf "${TMP_DIR}"/* 2>/dev/null
|
||||
echo "清理完成。"
|
||||
else
|
||||
echo "临时目录 ${TMP_DIR} 不存在,无需清理。"
|
||||
fi
|
||||
|
||||
# 如果只提供了 -c 选项而没有其他 .sy 文件,则在清理后退出
|
||||
if [ ${#SY_FILES[@]} -eq 0 ] && ! ${EXECUTE_MODE}; then
|
||||
exit 0
|
||||
fi
|
||||
@@ -150,6 +150,7 @@ mkdir -p "${TMP_DIR}"
|
||||
TOTAL_CASES=${#SY_FILES[@]}
|
||||
|
||||
echo "SysY 单例测试运行器启动..."
|
||||
if [ -n "$OPTIMIZE_FLAG" ]; then echo "优化等级: ${OPTIMIZE_FLAG}"; fi
|
||||
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
|
||||
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
|
||||
echo ""
|
||||
@@ -170,9 +171,21 @@ for sy_file in "${SY_FILES[@]}"; do
|
||||
echo "======================================================================"
|
||||
echo "正在处理: ${sy_file}"
|
||||
|
||||
# --- 本次修改点: 拷贝源文件到 tmp 目录 ---
|
||||
echo " 拷贝源文件到 ${TMP_DIR}..."
|
||||
cp "${sy_file}" "${TMP_DIR}/$(basename "${sy_file}")"
|
||||
if [ -f "${input_file}" ]; then
|
||||
cp "${input_file}" "${TMP_DIR}/$(basename "${input_file}")"
|
||||
fi
|
||||
if [ -f "${output_reference_file}" ]; then
|
||||
cp "${output_reference_file}" "${TMP_DIR}/$(basename "${output_reference_file}")"
|
||||
fi
|
||||
|
||||
# 步骤 1: sysyc 编译
|
||||
echo " 使用 sysyc 编译 (超时 ${SYSYC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" > "${ir_file}"
|
||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" ${OPTIMIZE_FLAG} -o "${assembly_file}"
|
||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" ${OPTIMIZE_FLAG} > "${ir_file}"
|
||||
# timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s asmd "${sy_file}" > "${assembly_debug_file}" 2>&1
|
||||
SYSYC_STATUS=$?
|
||||
if [ $SYSYC_STATUS -eq 124 ]; then
|
||||
echo -e "\e[31m错误: SysY 编译 ${sy_file} IR超时\e[0m"
|
||||
@@ -181,12 +194,10 @@ for sy_file in "${SY_FILES[@]}"; do
|
||||
echo -e "\e[31m错误: SysY 编译 ${sy_file} IR失败,退出码: ${SYSYC_STATUS}\e[0m"
|
||||
is_passed=0
|
||||
fi
|
||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file}"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "\e[31m错误: SysY 编译失败或超时。\e[0m"
|
||||
is_passed=0
|
||||
fi
|
||||
# timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s asmd "${sy_file}" > "${assembly_debug_file}" 2>&1
|
||||
|
||||
# 步骤 2: GCC 编译
|
||||
if [ "$is_passed" -eq 1 ]; then
|
||||
@@ -218,7 +229,6 @@ for sy_file in "${SY_FILES[@]}"; do
|
||||
is_passed=0
|
||||
else
|
||||
if [ -f "${output_reference_file}" ]; then
|
||||
# 此处逻辑与 runit.sh 相同
|
||||
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
|
||||
if [[ "$LAST_LINE_TRIMMED" =~ ^[-+]?[0-9]+$ ]]; then
|
||||
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
|
||||
@@ -226,7 +236,6 @@ for sy_file in "${SY_FILES[@]}"; do
|
||||
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
|
||||
if [ "$ACTUAL_RETURN_CODE" -ne "$EXPECTED_RETURN_CODE" ]; then echo -e "\e[31m 返回码测试失败: 期望 ${EXPECTED_RETURN_CODE}, 实际 ${ACTUAL_RETURN_CODE}\e[0m"; is_passed=0; fi
|
||||
|
||||
# --- 本次修改点: 使用 tr 删除所有空白字符后再比较 ---
|
||||
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"
|
||||
is_passed=0
|
||||
@@ -235,7 +244,6 @@ for sy_file in "${SY_FILES[@]}"; do
|
||||
echo -e " \e[36m----------------\e[0m"
|
||||
fi
|
||||
else
|
||||
# --- 本次修改点: 使用 tr 删除所有空白字符后再比较 ---
|
||||
if diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
|
||||
echo -e "\e[32m 标准输出测试成功。\e[0m"
|
||||
else
|
||||
|
||||
@@ -16,12 +16,13 @@ SYSYC="${BUILD_BIN_DIR}/sysyc"
|
||||
GCC_RISCV64="riscv64-linux-gnu-gcc"
|
||||
QEMU_RISCV64="qemu-riscv64"
|
||||
|
||||
# --- 新增功能: 初始化变量 ---
|
||||
EXECUTE_MODE=false
|
||||
OPTIMIZE_FLAG="" # 用于存储 -O1 标志
|
||||
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
|
||||
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
|
||||
EXEC_TIMEOUT=5 # qemu 执行超时 (秒)
|
||||
MAX_OUTPUT_LINES=50 # 对比失败时显示的最大行数
|
||||
TEST_SETS=() # 用于存储要运行的测试集
|
||||
TOTAL_CASES=0
|
||||
PASSED_CASES=0
|
||||
FAILED_CASES_LIST="" # 用于存储未通过的测例列表
|
||||
@@ -34,6 +35,8 @@ show_help() {
|
||||
echo "选项:"
|
||||
echo " -e, --executable 编译为可执行文件并运行测试。"
|
||||
echo " -c, --clean 清理 'tmp' 目录下的所有生成文件。"
|
||||
echo " -O1 启用 sysyc 的 -O1 优化。"
|
||||
echo " -set [f|h|p|all]... 指定要运行的测试集 (functional, h_functional, performance)。可多选,默认为 all。"
|
||||
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 10)。"
|
||||
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
||||
echo " -et N 设置 qemu 执行超时为 N 秒 (默认: 5)。"
|
||||
@@ -77,22 +80,34 @@ while [[ "$#" -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-e|--executable)
|
||||
EXECUTE_MODE=true
|
||||
shift
|
||||
;;
|
||||
-c|--clean)
|
||||
clean_tmp
|
||||
exit 0
|
||||
;;
|
||||
-O1)
|
||||
OPTIMIZE_FLAG="-O1"
|
||||
shift
|
||||
;;
|
||||
-set)
|
||||
shift # 移过 '-set'
|
||||
while [[ "$#" -gt 0 && ! "$1" =~ ^- ]]; do
|
||||
TEST_SETS+=("$1")
|
||||
shift
|
||||
done
|
||||
;;
|
||||
-sct)
|
||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi
|
||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift 2; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi
|
||||
;;
|
||||
-gct)
|
||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi
|
||||
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; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi
|
||||
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; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi
|
||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi
|
||||
;;
|
||||
-h|--help)
|
||||
show_help
|
||||
@@ -104,11 +119,36 @@ while [[ "$#" -gt 0 ]]; do
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# --- 本次修改点: 根据 -set 参数构建查找路径 ---
|
||||
declare -A SET_MAP
|
||||
SET_MAP[f]="functional"
|
||||
SET_MAP[h]="h_functional"
|
||||
SET_MAP[p]="performance"
|
||||
|
||||
SEARCH_PATHS=()
|
||||
|
||||
if [ ${#TEST_SETS[@]} -eq 0 ] || [[ " ${TEST_SETS[@]} " =~ " all " ]]; then
|
||||
SEARCH_PATHS+=("${TESTDATA_DIR}")
|
||||
else
|
||||
for set in "${TEST_SETS[@]}"; do
|
||||
if [[ -v SET_MAP[$set] ]]; then
|
||||
SEARCH_PATHS+=("${TESTDATA_DIR}/${SET_MAP[$set]}")
|
||||
else
|
||||
echo -e "\e[33m警告: 未知的测试集 '$set',已忽略。\e[0m"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ ${#SEARCH_PATHS[@]} -eq 0 ]; then
|
||||
echo -e "\e[31m错误: 没有找到有效的测试集目录,测试中止。\e[0m"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "SysY 测试运行器启动..."
|
||||
echo "输入目录: ${TESTDATA_DIR}"
|
||||
if [ -n "$OPTIMIZE_FLAG" ]; then echo "优化等级: ${OPTIMIZE_FLAG}"; fi
|
||||
echo "输入目录: ${SEARCH_PATHS[@]}"
|
||||
echo "临时目录: ${TMP_DIR}"
|
||||
echo "执行模式: ${EXECUTE_MODE}"
|
||||
if ${EXECUTE_MODE}; then
|
||||
@@ -117,11 +157,13 @@ if ${EXECUTE_MODE}; then
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- 修改点: 查找所有 .sy 文件并按文件名前缀数字排序 ---
|
||||
sy_files=$(find "${TESTDATA_DIR}" -name "*.sy" | sort -V)
|
||||
sy_files=$(find "${SEARCH_PATHS[@]}" -name "*.sy" | sort -V)
|
||||
if [ -z "$sy_files" ]; then
|
||||
echo "在指定目录中未找到任何 .sy 文件。"
|
||||
exit 0
|
||||
fi
|
||||
TOTAL_CASES=$(echo "$sy_files" | wc -w)
|
||||
|
||||
# --- 修复: 使用 here-string (<<<) 代替管道 (|) 来避免子 shell 问题 ---
|
||||
while IFS= read -r sy_file; do
|
||||
is_passed=1 # 1 表示通过, 0 表示失败
|
||||
|
||||
@@ -135,10 +177,8 @@ while IFS= read -r sy_file; do
|
||||
output_actual_file="${TMP_DIR}/${output_base_name}_sysyc_riscv64.actual_out"
|
||||
|
||||
echo "正在处理: $(basename "$sy_file") (路径: ${relative_path_no_ext}.sy)"
|
||||
|
||||
# 步骤 1: 使用 sysyc 编译 .sy 到 .s
|
||||
echo " 使用 sysyc 编译 (超时 ${SYSYC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file}"
|
||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file}" ${OPTIMIZE_FLAG}
|
||||
SYSYC_STATUS=$?
|
||||
if [ $SYSYC_STATUS -eq 124 ]; then
|
||||
echo -e "\e[31m错误: SysY 编译 ${sy_file} 超时\e[0m"
|
||||
@@ -148,9 +188,7 @@ while IFS= read -r sy_file; do
|
||||
is_passed=0
|
||||
fi
|
||||
|
||||
# 只有当 EXECUTE_MODE 为 true 且上一步成功时才继续
|
||||
if ${EXECUTE_MODE} && [ "$is_passed" -eq 1 ]; then
|
||||
# 步骤 2: 使用 riscv64-linux-gnu-gcc 编译 .s 到可执行文件
|
||||
echo " 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
|
||||
GCC_STATUS=$?
|
||||
@@ -172,7 +210,6 @@ while IFS= read -r sy_file; do
|
||||
continue
|
||||
fi
|
||||
|
||||
# 步骤 3, 4, 5: 只有当编译都成功时才执行
|
||||
if [ "$is_passed" -eq 1 ]; then
|
||||
echo " 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
|
||||
|
||||
@@ -204,7 +241,6 @@ while IFS= read -r sy_file; do
|
||||
is_passed=0
|
||||
fi
|
||||
|
||||
# --- 本次修改点: 使用 tr 删除所有空白字符后再比较 ---
|
||||
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"
|
||||
is_passed=0
|
||||
@@ -217,7 +253,6 @@ while IFS= read -r sy_file; do
|
||||
echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"
|
||||
fi
|
||||
|
||||
# --- 本次修改点: 使用 tr 删除所有空白字符后再比较 ---
|
||||
if diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
|
||||
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
|
||||
else
|
||||
|
||||
@@ -5,12 +5,16 @@ add_library(riscv64_backend_lib STATIC
|
||||
RISCv64ISel.cpp
|
||||
RISCv64LLIR.cpp
|
||||
RISCv64RegAlloc.cpp
|
||||
RISCv64LinearScan.cpp
|
||||
RISCv64BasicBlockAlloc.cpp
|
||||
Handler/CalleeSavedHandler.cpp
|
||||
Handler/LegalizeImmediates.cpp
|
||||
Handler/PrologueEpilogueInsertion.cpp
|
||||
Handler/EliminateFrameIndices.cpp
|
||||
Optimize/Peephole.cpp
|
||||
Optimize/PostRA_Scheduler.cpp
|
||||
Optimize/PreRA_Scheduler.cpp
|
||||
Optimize/DivStrengthReduction.cpp
|
||||
)
|
||||
|
||||
# 包含后端模块所需的头文件路径
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "CalleeSavedHandler.h"
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
@@ -12,112 +14,38 @@ bool CalleeSavedHandler::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
}
|
||||
|
||||
void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
// 此 Pass 负责分析、分配栈空间并插入 callee-saved 寄存器的保存/恢复指令。
|
||||
// 它通过与 FrameInfo 协作,确保为 callee-saved 寄存器分配的空间与局部变量/溢出槽的空间不冲突。
|
||||
// 这样做可以使生成的 sd/ld 指令能被后续的优化 Pass (如 PostRA-Scheduler) 处理。
|
||||
|
||||
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
||||
std::set<PhysicalReg> used_callee_saved;
|
||||
|
||||
// 1. 扫描所有指令,找出被使用的s寄存器 (s1-s11)
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
for (auto& instr : mbb->getInstructions()) {
|
||||
for (auto& op : instr->getOperands()) {
|
||||
auto check_and_insert_reg = [&](RegOperand* reg_op) {
|
||||
if (!reg_op->isVirtual()) {
|
||||
PhysicalReg preg = reg_op->getPReg();
|
||||
if (preg >= PhysicalReg::S1 && preg <= PhysicalReg::S11) {
|
||||
used_callee_saved.insert(preg);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
check_and_insert_reg(static_cast<RegOperand*>(op.get()));
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
check_and_insert_reg(static_cast<MemOperand*>(op.get())->getBase());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const std::set<PhysicalReg>& used_callee_saved = frame_info.used_callee_saved_regs;
|
||||
|
||||
if (used_callee_saved.empty()) {
|
||||
frame_info.callee_saved_size = 0; // 确保大小被初始化
|
||||
return; // 无需操作
|
||||
frame_info.callee_saved_size = 0;
|
||||
frame_info.callee_saved_regs_to_store.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 计算为 callee-saved 寄存器分配的栈空间
|
||||
// 这里的关键是,偏移的基准点要在局部变量和溢出槽之下。
|
||||
int callee_saved_size = used_callee_saved.size() * 8;
|
||||
frame_info.callee_saved_size = callee_saved_size; // 将大小存入 FrameInfo
|
||||
|
||||
// 3. 计算无冲突的栈偏移
|
||||
// 栈向下增长,所以偏移是负数。
|
||||
// ra/s0 占用 -8 和 -16。局部变量和溢出区在它们之下。callee-saved 区在更下方。
|
||||
// 我们使用相对于 s0 的偏移。s0 将指向栈顶 (sp + total_size)。
|
||||
int base_offset = -16 - frame_info.locals_size - frame_info.spill_size;
|
||||
|
||||
// 为了栈帧布局确定性,对寄存器进行排序
|
||||
std::vector<PhysicalReg> sorted_regs(used_callee_saved.begin(), used_callee_saved.end());
|
||||
std::sort(sorted_regs.begin(), sorted_regs.end());
|
||||
|
||||
// 4. 在函数序言插入保存指令
|
||||
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
|
||||
auto& entry_instrs = entry_block->getInstructions();
|
||||
auto prologue_end = entry_instrs.begin();
|
||||
|
||||
// 找到序言结束的位置(通常是addi s0, sp, size之后,但为了让优化器看到,我们插在更前面)
|
||||
// 合理的位置是在 IR 指令开始之前,即在任何非序言指令(如第一个标签)之前。
|
||||
// 为简单起见,我们直接插入到块的开头,后续重排 pass 会处理。
|
||||
// (更优的实现会寻找一个特定的插入点)
|
||||
|
||||
int current_offset = base_offset;
|
||||
for (PhysicalReg reg : sorted_regs) {
|
||||
auto sd = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
||||
sd->addOperand(std::make_unique<RegOperand>(reg));
|
||||
sd->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0), // 基址为帧指针 s0
|
||||
std::make_unique<ImmOperand>(current_offset)
|
||||
));
|
||||
// 从头部插入,但要放在函数标签之后
|
||||
entry_instrs.insert(entry_instrs.begin() + 1, std::move(sd));
|
||||
current_offset -= 8;
|
||||
// 1. 计算被调用者保存寄存器所需的总空间大小
|
||||
// s0 总是由 PEI Pass 单独处理,这里不计入大小,但要确保它在列表中
|
||||
int size = 0;
|
||||
std::set<PhysicalReg> regs_to_save = used_callee_saved;
|
||||
if (regs_to_save.count(PhysicalReg::S0)) {
|
||||
regs_to_save.erase(PhysicalReg::S0);
|
||||
}
|
||||
size = regs_to_save.size() * 8; // 每个寄存器占8字节 (64-bit)
|
||||
frame_info.callee_saved_size = size;
|
||||
|
||||
// 5. 在函数结尾(ret之前)插入恢复指令,使用反向遍历来避免迭代器失效
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
// 使用手动控制的反向循环
|
||||
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
|
||||
if ((*it)->getOpcode() == RVOpcodes::RET) {
|
||||
// 1. 创建一个临时vector来存储所有需要插入的恢复指令
|
||||
std::vector<std::unique_ptr<MachineInstr>> restore_instrs;
|
||||
|
||||
int current_offset_load = base_offset;
|
||||
// 以相同的顺序(例如 s1, s2, ...)创建恢复指令
|
||||
for (PhysicalReg reg : sorted_regs) {
|
||||
auto ld = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
||||
ld->addOperand(std::make_unique<RegOperand>(reg));
|
||||
ld->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(current_offset_load)
|
||||
));
|
||||
restore_instrs.push_back(std::move(ld));
|
||||
current_offset_load -= 8;
|
||||
}
|
||||
// 2. 创建一个有序的、需要保存的寄存器列表,以便后续 Pass 确定地生成代码
|
||||
// s0 不应包含在此列表中,因为它由 PEI Pass 特殊处理
|
||||
std::vector<PhysicalReg> sorted_regs(regs_to_save.begin(), regs_to_save.end());
|
||||
std::sort(sorted_regs.begin(), sorted_regs.end(), [](PhysicalReg a, PhysicalReg b){
|
||||
return static_cast<int>(a) < static_cast<int>(b);
|
||||
});
|
||||
frame_info.callee_saved_regs_to_store = sorted_regs;
|
||||
|
||||
// 2. 使用 make_move_iterator 一次性将所有恢复指令插入到 RET 指令之前
|
||||
// 这可以高效地转移指令的所有权,并且只让迭代器失效一次。
|
||||
if (!restore_instrs.empty()) {
|
||||
mbb->getInstructions().insert(it,
|
||||
std::make_move_iterator(restore_instrs.begin()),
|
||||
std::make_move_iterator(restore_instrs.end())
|
||||
);
|
||||
}
|
||||
|
||||
// 找到了RET并处理完毕后,就可以跳出内层循环,继续寻找下一个基本块
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 3. 更新栈帧总大小。
|
||||
// 这是初步计算,PEI Pass 会进行最终的对齐。
|
||||
frame_info.total_size = frame_info.locals_size +
|
||||
frame_info.spill_size +
|
||||
frame_info.callee_saved_size;
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
} // namespace sysy
|
||||
|
||||
235
src/backend/RISCv64/Handler/EliminateFrameIndices.cpp
Normal file
235
src/backend/RISCv64/Handler/EliminateFrameIndices.cpp
Normal file
@@ -0,0 +1,235 @@
|
||||
#include "EliminateFrameIndices.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// getTypeSizeInBytes 是一个通用辅助函数,保持不变
|
||||
unsigned EliminateFrameIndicesPass::getTypeSizeInBytes(Type* type) {
|
||||
if (!type) {
|
||||
assert(false && "Cannot get size of a null 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() * getTypeSizeInBytes(arrayType->getElementType());
|
||||
}
|
||||
default:
|
||||
assert(false && "Unsupported type for size calculation.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void EliminateFrameIndicesPass::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
||||
Function* F = mfunc->getFunc();
|
||||
RISCv64ISel* isel = mfunc->getISel();
|
||||
|
||||
// 在这里处理栈传递的参数,以便在寄存器分配前就将数据流显式化,修复溢出逻辑的BUG。
|
||||
|
||||
// 2. 只为局部变量(AllocaInst)分配栈空间和计算偏移量
|
||||
// 局部变量从 s0 下方(负偏移量)开始分配,紧接着为 ra 和 s0 预留的16字节之后
|
||||
int local_var_offset = 16;
|
||||
|
||||
if(F) { // 确保函数指针有效
|
||||
for (auto& bb : F->getBasicBlocks()) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (auto alloca = dynamic_cast<AllocaInst*>(inst.get())) {
|
||||
Type* allocated_type = alloca->getType()->as<PointerType>()->getBaseType();
|
||||
int size = getTypeSizeInBytes(allocated_type);
|
||||
|
||||
// 优化栈帧大小:对于大数组使用4字节对齐,小对象使用8字节对齐
|
||||
if (size >= 256) { // 大数组优化
|
||||
size = (size + 3) & ~3; // 4字节对齐
|
||||
} else {
|
||||
size = (size + 7) & ~7; // 8字节对齐
|
||||
}
|
||||
if (size == 0) size = 4; // 最小4字节
|
||||
|
||||
local_var_offset += size;
|
||||
unsigned alloca_vreg = isel->getVReg(alloca);
|
||||
// 局部变量使用相对于s0的负向偏移
|
||||
frame_info.alloca_offsets[alloca_vreg] = -local_var_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 记录仅由AllocaInst分配的局部变量的总大小
|
||||
frame_info.locals_size = local_var_offset - 16;
|
||||
// 记录局部变量区域分配结束的最终偏移量
|
||||
frame_info.locals_end_offset = -local_var_offset;
|
||||
|
||||
// 在函数入口为所有栈传递的参数插入load指令
|
||||
// 这个步骤至关重要:它在寄存器分配之前,为这些参数的vreg创建了明确的“定义(def)”指令。
|
||||
// 这解决了在高寄存器压力下,当这些vreg被溢出时,`rewriteProgram`找不到其定义点而崩溃的问题。
|
||||
if (F && isel && !mfunc->getBlocks().empty()) {
|
||||
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
|
||||
std::vector<std::unique_ptr<MachineInstr>> arg_load_instrs;
|
||||
|
||||
// 步骤 3.1: 生成所有加载栈参数的指令,暂存起来
|
||||
int arg_idx = 0;
|
||||
for (Argument* arg : F->getArguments()) {
|
||||
// 根据ABI,前8个整型/指针参数通过寄存器传递,这里只处理超出部分。
|
||||
if (arg_idx >= 8) {
|
||||
// 计算参数在调用者栈帧中的位置,该位置相对于被调用者的帧指针s0是正向偏移。
|
||||
// 第9个参数(arg_idx=8)位于 0(s0),第10个(arg_idx=9)位于 8(s0),以此类推。
|
||||
int offset = (arg_idx - 8) * 8;
|
||||
unsigned arg_vreg = isel->getVReg(arg);
|
||||
Type* arg_type = arg->getType();
|
||||
|
||||
// 根据参数类型选择正确的加载指令
|
||||
RVOpcodes load_op;
|
||||
if (arg_type->isFloat()) {
|
||||
load_op = RVOpcodes::FLW; // 单精度浮点
|
||||
} else if (arg_type->isPointer()) {
|
||||
load_op = RVOpcodes::LD; // 64位指针
|
||||
} else {
|
||||
load_op = RVOpcodes::LW; // 32位整数
|
||||
}
|
||||
|
||||
// 创建加载指令: lw/ld/flw vreg, offset(s0)
|
||||
auto load_instr = std::make_unique<MachineInstr>(load_op);
|
||||
load_instr->addOperand(std::make_unique<RegOperand>(arg_vreg));
|
||||
load_instr->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0), // 基址为帧指针
|
||||
std::make_unique<ImmOperand>(offset)
|
||||
));
|
||||
arg_load_instrs.push_back(std::move(load_instr));
|
||||
}
|
||||
arg_idx++;
|
||||
}
|
||||
|
||||
//仅当有需要加载的栈参数时,才执行插入逻辑
|
||||
if (!arg_load_instrs.empty()) {
|
||||
auto& entry_instrs = entry_block->getInstructions();
|
||||
auto insertion_point = entry_instrs.begin(); // 默认插入点为块的开头
|
||||
auto last_arg_save_it = entry_instrs.end();
|
||||
|
||||
// 步骤 3.2: 寻找一个安全的插入点。
|
||||
// 遍历入口块的指令,找到最后一条保存“寄存器传递参数”的伪指令。
|
||||
// 这样可以确保我们在所有 a0-a7 参数被保存之后,才执行可能覆盖它们的加载指令。
|
||||
for (auto it = entry_instrs.begin(); it != entry_instrs.end(); ++it) {
|
||||
MachineInstr* instr = it->get();
|
||||
// 寻找代表保存参数到栈的伪指令
|
||||
if (instr->getOpcode() == RVOpcodes::FRAME_STORE_W ||
|
||||
instr->getOpcode() == RVOpcodes::FRAME_STORE_D ||
|
||||
instr->getOpcode() == RVOpcodes::FRAME_STORE_F) {
|
||||
|
||||
// 检查被保存的值是否是寄存器参数 (arg_no < 8)
|
||||
auto& operands = instr->getOperands();
|
||||
if (operands.empty() || operands[0]->getKind() != MachineOperand::KIND_REG) continue;
|
||||
|
||||
unsigned src_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
|
||||
Value* ir_value = isel->getVRegValueMap().count(src_vreg) ? isel->getVRegValueMap().at(src_vreg) : nullptr;
|
||||
|
||||
if (auto ir_arg = dynamic_cast<Argument*>(ir_value)) {
|
||||
if (ir_arg->getIndex() < 8) {
|
||||
last_arg_save_it = it; // 找到了一个保存寄存器参数的指令,更新位置
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果找到了这样的保存指令,我们的插入点就在它之后
|
||||
if (last_arg_save_it != entry_instrs.end()) {
|
||||
insertion_point = std::next(last_arg_save_it);
|
||||
}
|
||||
|
||||
// 步骤 3.3: 在计算出的安全位置,一次性插入所有新创建的参数加载指令
|
||||
entry_instrs.insert(insertion_point,
|
||||
std::make_move_iterator(arg_load_instrs.begin()),
|
||||
std::make_move_iterator(arg_load_instrs.end()));
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 遍历所有机器指令,将访问局部变量的伪指令展开为真实指令
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
RVOpcodes opcode = instr_ptr->getOpcode();
|
||||
|
||||
if (opcode == RVOpcodes::FRAME_LOAD_W || opcode == RVOpcodes::FRAME_LOAD_D || opcode == RVOpcodes::FRAME_LOAD_F) {
|
||||
RVOpcodes real_load_op;
|
||||
if (opcode == RVOpcodes::FRAME_LOAD_W) real_load_op = RVOpcodes::LW;
|
||||
else if (opcode == RVOpcodes::FRAME_LOAD_D) real_load_op = RVOpcodes::LD;
|
||||
else real_load_op = RVOpcodes::FLW;
|
||||
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
unsigned dest_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
|
||||
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
|
||||
int offset = frame_info.alloca_offsets.at(alloca_vreg);
|
||||
auto addr_vreg = isel->getNewVReg(Type::getPointerType(Type::getIntType()));
|
||||
|
||||
// 展开为: addi addr_vreg, s0, offset
|
||||
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
addi->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
addi->addOperand(std::make_unique<ImmOperand>(offset));
|
||||
new_instructions.push_back(std::move(addi));
|
||||
|
||||
// 展开为: lw/ld/flw dest_vreg, 0(addr_vreg)
|
||||
auto load_instr = std::make_unique<MachineInstr>(real_load_op);
|
||||
load_instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
load_instr->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(addr_vreg),
|
||||
std::make_unique<ImmOperand>(0)));
|
||||
new_instructions.push_back(std::move(load_instr));
|
||||
|
||||
} else if (opcode == RVOpcodes::FRAME_STORE_W || opcode == RVOpcodes::FRAME_STORE_D || opcode == RVOpcodes::FRAME_STORE_F) {
|
||||
RVOpcodes real_store_op;
|
||||
if (opcode == RVOpcodes::FRAME_STORE_W) real_store_op = RVOpcodes::SW;
|
||||
else if (opcode == RVOpcodes::FRAME_STORE_D) real_store_op = RVOpcodes::SD;
|
||||
else real_store_op = RVOpcodes::FSW;
|
||||
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
unsigned src_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
|
||||
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
|
||||
int offset = frame_info.alloca_offsets.at(alloca_vreg);
|
||||
auto addr_vreg = isel->getNewVReg(Type::getPointerType(Type::getIntType()));
|
||||
|
||||
// 展开为: addi addr_vreg, s0, offset
|
||||
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
addi->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
addi->addOperand(std::make_unique<ImmOperand>(offset));
|
||||
new_instructions.push_back(std::move(addi));
|
||||
|
||||
// 展开为: sw/sd/fsw src_vreg, 0(addr_vreg)
|
||||
auto store_instr = std::make_unique<MachineInstr>(real_store_op);
|
||||
store_instr->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
store_instr->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(addr_vreg),
|
||||
std::make_unique<ImmOperand>(0)));
|
||||
new_instructions.push_back(std::move(store_instr));
|
||||
|
||||
} else if (instr_ptr->getOpcode() == RVOpcodes::FRAME_ADDR) {
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
unsigned dest_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
|
||||
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
|
||||
int offset = frame_info.alloca_offsets.at(alloca_vreg);
|
||||
|
||||
// 将 `frame_addr rd, rs` 展开为 `addi rd, s0, offset`
|
||||
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
addi->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
addi->addOperand(std::make_unique<ImmOperand>(offset));
|
||||
new_instructions.push_back(std::move(addi));
|
||||
|
||||
} else {
|
||||
new_instructions.push_back(std::move(instr_ptr));
|
||||
}
|
||||
}
|
||||
mbb->getInstructions() = std::move(new_instructions);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@@ -52,6 +52,8 @@ void LegalizeImmediatesPass::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
case RVOpcodes::ADDI:
|
||||
case RVOpcodes::ADDIW: {
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
// 确保操作数足够多,以防万一
|
||||
if (operands.size() < 3) break;
|
||||
auto imm_op = static_cast<ImmOperand*>(operands.back().get());
|
||||
|
||||
if (!isLegalImmediate(imm_op->getValue())) {
|
||||
@@ -73,7 +75,7 @@ void LegalizeImmediatesPass::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
add->addOperand(std::move(rd_op));
|
||||
add->addOperand(std::move(rs1_op));
|
||||
add->addOperand(std::make_unique<RegOperand>(TEMP_REG));
|
||||
|
||||
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << " New sequence:\n ";
|
||||
temp_printer.printInstruction(li.get(), true);
|
||||
@@ -92,7 +94,8 @@ 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::SB: case RVOpcodes::SH: case RVOpcodes::SW: case RVOpcodes::SD:
|
||||
case RVOpcodes::FLW: case RVOpcodes::FSW: {
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
auto mem_op = static_cast<MemOperand*>(operands.back().get());
|
||||
auto offset_op = mem_op->getOffset();
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
#include "PrologueEpilogueInsertion.h"
|
||||
#include "RISCv64LLIR.h" // 假设包含了 PhysicalReg, RVOpcodes 等定义
|
||||
#include "RISCv64ISel.h"
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
@@ -6,33 +11,75 @@ char PrologueEpilogueInsertionPass::ID = 0;
|
||||
|
||||
void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
||||
Function* F = mfunc->getFunc();
|
||||
RISCv64ISel* isel = mfunc->getISel();
|
||||
|
||||
// 完全遵循 AsmPrinter 中的计算逻辑
|
||||
// 1. 清理 KEEPALIVE 伪指令
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
auto& instrs = mbb->getInstructions();
|
||||
instrs.erase(
|
||||
std::remove_if(instrs.begin(), instrs.end(),
|
||||
[](const std::unique_ptr<MachineInstr>& instr) {
|
||||
return instr->getOpcode() == RVOpcodes::PSEUDO_KEEPALIVE;
|
||||
}
|
||||
),
|
||||
instrs.end()
|
||||
);
|
||||
}
|
||||
|
||||
// 2. 确定需要保存的被调用者保存寄存器 (callee-saved)
|
||||
auto& vreg_to_preg_map = frame_info.vreg_to_preg_map;
|
||||
std::set<PhysicalReg> used_callee_saved_regs_set;
|
||||
const auto& callee_saved_int = getCalleeSavedIntRegs();
|
||||
const auto& callee_saved_fp = getCalleeSavedFpRegs();
|
||||
|
||||
for (const auto& pair : vreg_to_preg_map) {
|
||||
PhysicalReg preg = pair.second;
|
||||
bool is_int_cs = std::find(callee_saved_int.begin(), callee_saved_int.end(), preg) != callee_saved_int.end();
|
||||
bool is_fp_cs = std::find(callee_saved_fp.begin(), callee_saved_fp.end(), preg) != callee_saved_fp.end();
|
||||
if ((is_int_cs && preg != PhysicalReg::S0) || is_fp_cs) {
|
||||
used_callee_saved_regs_set.insert(preg);
|
||||
}
|
||||
}
|
||||
frame_info.callee_saved_regs_to_store.assign(
|
||||
used_callee_saved_regs_set.begin(), used_callee_saved_regs_set.end()
|
||||
);
|
||||
std::sort(frame_info.callee_saved_regs_to_store.begin(), frame_info.callee_saved_regs_to_store.end());
|
||||
frame_info.callee_saved_size = frame_info.callee_saved_regs_to_store.size() * 8;
|
||||
|
||||
// 3. 计算最终的栈帧总大小,包含栈溢出保护
|
||||
int total_stack_size = frame_info.locals_size +
|
||||
frame_info.spill_size +
|
||||
frame_info.callee_saved_size +
|
||||
16; // 为 ra 和 s0 固定的16字节
|
||||
16;
|
||||
|
||||
// 栈溢出保护:增加最大栈帧大小以容纳大型数组
|
||||
const int MAX_STACK_FRAME_SIZE = 8192; // 8KB to handle large arrays like 256*4*2 = 2048 bytes
|
||||
if (total_stack_size > MAX_STACK_FRAME_SIZE) {
|
||||
// 如果仍然超过限制,尝试优化对齐方式
|
||||
std::cerr << "Warning: Stack frame size " << total_stack_size
|
||||
<< " exceeds recommended limit " << MAX_STACK_FRAME_SIZE << " for function "
|
||||
<< mfunc->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 优化:减少对齐开销,使用16字节对齐而非更大的对齐
|
||||
int aligned_stack_size = (total_stack_size + 15) & ~15;
|
||||
frame_info.total_size = aligned_stack_size;
|
||||
|
||||
// 只有在需要分配栈空间时才生成指令
|
||||
if (aligned_stack_size > 0) {
|
||||
// --- 1. 插入序言 ---
|
||||
// --- 4. 插入完整的序言 ---
|
||||
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
|
||||
auto& entry_instrs = entry_block->getInstructions();
|
||||
|
||||
std::vector<std::unique_ptr<MachineInstr>> prologue_instrs;
|
||||
|
||||
// 严格按照 AsmPrinter 的打印顺序来创建和组织指令
|
||||
// 1. addi sp, sp, -aligned_stack_size
|
||||
// 4.1. 分配栈帧
|
||||
auto alloc_stack = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
alloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
alloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
alloc_stack->addOperand(std::make_unique<ImmOperand>(-aligned_stack_size));
|
||||
prologue_instrs.push_back(std::move(alloc_stack));
|
||||
|
||||
// 2. sd ra, (aligned_stack_size - 8)(sp)
|
||||
// 4.2. 保存 ra 和 s0
|
||||
auto save_ra = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
||||
save_ra->addOperand(std::make_unique<RegOperand>(PhysicalReg::RA));
|
||||
save_ra->addOperand(std::make_unique<MemOperand>(
|
||||
@@ -40,8 +87,6 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
|
||||
std::make_unique<ImmOperand>(aligned_stack_size - 8)
|
||||
));
|
||||
prologue_instrs.push_back(std::move(save_ra));
|
||||
|
||||
// 3. sd s0, (aligned_stack_size - 16)(sp)
|
||||
auto save_fp = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
||||
save_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
save_fp->addOperand(std::make_unique<MemOperand>(
|
||||
@@ -50,33 +95,55 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
|
||||
));
|
||||
prologue_instrs.push_back(std::move(save_fp));
|
||||
|
||||
// 4. addi s0, sp, aligned_stack_size
|
||||
// 4.3. 设置新的帧指针 s0
|
||||
auto set_fp = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
set_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
set_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
set_fp->addOperand(std::make_unique<ImmOperand>(aligned_stack_size));
|
||||
prologue_instrs.push_back(std::move(set_fp));
|
||||
|
||||
// 确定插入点(在函数名标签之后)
|
||||
auto insert_pos = entry_instrs.begin();
|
||||
// [重要] 这里我们不再需要跳过LABEL,因为AsmPrinter将不再打印函数名标签
|
||||
// 第一个基本块的标签就是函数入口
|
||||
|
||||
// 一次性将所有序言指令插入
|
||||
if (!prologue_instrs.empty()) {
|
||||
entry_instrs.insert(insert_pos,
|
||||
std::make_move_iterator(prologue_instrs.begin()),
|
||||
std::make_move_iterator(prologue_instrs.end()));
|
||||
// 4.4. 保存所有使用到的被调用者保存寄存器
|
||||
int next_available_offset = -(16 + frame_info.locals_size + frame_info.spill_size);
|
||||
for (const auto& reg : frame_info.callee_saved_regs_to_store) {
|
||||
// 改为“先更新,后使用”逻辑
|
||||
next_available_offset -= 8; // 先为当前寄存器分配下一个可用槽位
|
||||
RVOpcodes store_op = isFPR(reg) ? RVOpcodes::FSD : RVOpcodes::SD;
|
||||
auto save_cs_reg = std::make_unique<MachineInstr>(store_op);
|
||||
save_cs_reg->addOperand(std::make_unique<RegOperand>(reg));
|
||||
save_cs_reg->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(next_available_offset) // 使用新计算出的正确偏移
|
||||
));
|
||||
prologue_instrs.push_back(std::move(save_cs_reg));
|
||||
// 不再需要在循环末尾递减
|
||||
}
|
||||
|
||||
// --- 2. 插入尾声 ---
|
||||
// 4.5. 将所有生成的序言指令一次性插入到函数入口
|
||||
entry_instrs.insert(entry_instrs.begin(),
|
||||
std::make_move_iterator(prologue_instrs.begin()),
|
||||
std::make_move_iterator(prologue_instrs.end()));
|
||||
|
||||
// --- 5. 插入完整的尾声 ---
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
|
||||
if ((*it)->getOpcode() == RVOpcodes::RET) {
|
||||
std::vector<std::unique_ptr<MachineInstr>> epilogue_instrs;
|
||||
|
||||
// 5.1. 恢复被调用者保存寄存器
|
||||
int next_available_offset_restore = -(16 + frame_info.locals_size + frame_info.spill_size);
|
||||
for (const auto& reg : frame_info.callee_saved_regs_to_store) {
|
||||
next_available_offset_restore -= 8; // 为下一个寄存器准备偏移
|
||||
RVOpcodes load_op = isFPR(reg) ? RVOpcodes::FLD : RVOpcodes::LD;
|
||||
auto restore_cs_reg = std::make_unique<MachineInstr>(load_op);
|
||||
restore_cs_reg->addOperand(std::make_unique<RegOperand>(reg));
|
||||
restore_cs_reg->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(next_available_offset_restore) // 使用当前偏移
|
||||
));
|
||||
epilogue_instrs.push_back(std::move(restore_cs_reg));
|
||||
}
|
||||
|
||||
// 同样严格按照 AsmPrinter 的打印顺序
|
||||
// 1. ld ra, (aligned_stack_size - 8)(sp)
|
||||
// 5.2. 恢复 ra 和 s0
|
||||
auto restore_ra = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
||||
restore_ra->addOperand(std::make_unique<RegOperand>(PhysicalReg::RA));
|
||||
restore_ra->addOperand(std::make_unique<MemOperand>(
|
||||
@@ -84,8 +151,6 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
|
||||
std::make_unique<ImmOperand>(aligned_stack_size - 8)
|
||||
));
|
||||
epilogue_instrs.push_back(std::move(restore_ra));
|
||||
|
||||
// 2. ld s0, (aligned_stack_size - 16)(sp)
|
||||
auto restore_fp = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
||||
restore_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
restore_fp->addOperand(std::make_unique<MemOperand>(
|
||||
@@ -94,19 +159,18 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
|
||||
));
|
||||
epilogue_instrs.push_back(std::move(restore_fp));
|
||||
|
||||
// 3. addi sp, sp, aligned_stack_size
|
||||
// 5.3. 释放栈帧
|
||||
auto dealloc_stack = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
dealloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
dealloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
dealloc_stack->addOperand(std::make_unique<ImmOperand>(aligned_stack_size));
|
||||
epilogue_instrs.push_back(std::move(dealloc_stack));
|
||||
|
||||
if (!epilogue_instrs.empty()) {
|
||||
mbb->getInstructions().insert(it,
|
||||
std::make_move_iterator(epilogue_instrs.begin()),
|
||||
std::make_move_iterator(epilogue_instrs.end()));
|
||||
}
|
||||
// 处理完一个基本块中的RET后,迭代器已失效,需跳出
|
||||
// 将尾声指令插入到 RET 指令之前
|
||||
mbb->getInstructions().insert(it,
|
||||
std::make_move_iterator(epilogue_instrs.begin()),
|
||||
std::make_move_iterator(epilogue_instrs.end()));
|
||||
|
||||
goto next_block;
|
||||
}
|
||||
}
|
||||
|
||||
282
src/backend/RISCv64/Optimize/DivStrengthReduction.cpp
Normal file
282
src/backend/RISCv64/Optimize/DivStrengthReduction.cpp
Normal file
@@ -0,0 +1,282 @@
|
||||
#include "DivStrengthReduction.h"
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
char DivStrengthReduction::ID = 0;
|
||||
|
||||
bool DivStrengthReduction::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
// This pass works on MachineFunction level, not IR level
|
||||
return false;
|
||||
}
|
||||
|
||||
void DivStrengthReduction::runOnMachineFunction(MachineFunction *mfunc) {
|
||||
if (!mfunc)
|
||||
return;
|
||||
|
||||
bool debug = false; // Set to true for debugging
|
||||
if (debug)
|
||||
std::cout << "Running DivStrengthReduction optimization..." << std::endl;
|
||||
|
||||
int next_temp_reg = 1000;
|
||||
auto createTempReg = [&]() -> int {
|
||||
return next_temp_reg++;
|
||||
};
|
||||
|
||||
struct MagicInfo {
|
||||
int64_t magic;
|
||||
int shift;
|
||||
};
|
||||
|
||||
auto computeMagic = [](int64_t d, bool is_32bit) -> MagicInfo {
|
||||
int word_size = is_32bit ? 32 : 64;
|
||||
uint64_t ad = std::abs(d);
|
||||
|
||||
if (ad == 0) return {0, 0};
|
||||
|
||||
int l = std::floor(std::log2(ad));
|
||||
if ((ad & (ad - 1)) == 0) { // power of 2
|
||||
l = 0; // special case for power of 2, shift will be calculated differently
|
||||
}
|
||||
|
||||
__int128_t one = 1;
|
||||
__int128_t num;
|
||||
int total_shift;
|
||||
|
||||
if (is_32bit) {
|
||||
total_shift = 31 + l;
|
||||
num = one << total_shift;
|
||||
} else {
|
||||
total_shift = 63 + l;
|
||||
num = one << total_shift;
|
||||
}
|
||||
|
||||
__int128_t den = ad;
|
||||
int64_t magic = (num / den) + 1;
|
||||
|
||||
return {magic, total_shift};
|
||||
};
|
||||
|
||||
auto isPowerOfTwo = [](int64_t n) -> bool {
|
||||
return n > 0 && (n & (n - 1)) == 0;
|
||||
};
|
||||
|
||||
auto getPowerOfTwoExponent = [](int64_t n) -> int {
|
||||
if (n <= 0 || (n & (n - 1)) != 0) return -1;
|
||||
int shift = 0;
|
||||
while (n > 1) {
|
||||
n >>= 1;
|
||||
shift++;
|
||||
}
|
||||
return shift;
|
||||
};
|
||||
|
||||
struct InstructionReplacement {
|
||||
size_t index;
|
||||
size_t count_to_erase;
|
||||
std::vector<std::unique_ptr<MachineInstr>> newInstrs;
|
||||
};
|
||||
|
||||
for (auto &mbb_uptr : mfunc->getBlocks()) {
|
||||
auto &mbb = *mbb_uptr;
|
||||
auto &instrs = mbb.getInstructions();
|
||||
std::vector<InstructionReplacement> replacements;
|
||||
|
||||
for (size_t i = 0; i < instrs.size(); ++i) {
|
||||
auto *instr = instrs[i].get();
|
||||
|
||||
bool is_32bit = (instr->getOpcode() == RVOpcodes::DIVW);
|
||||
|
||||
if (instr->getOpcode() != RVOpcodes::DIV && !is_32bit) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (instr->getOperands().size() != 3) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto *dst_op = instr->getOperands()[0].get();
|
||||
auto *src1_op = instr->getOperands()[1].get();
|
||||
auto *src2_op = instr->getOperands()[2].get();
|
||||
|
||||
int64_t divisor = 0;
|
||||
bool const_divisor_found = false;
|
||||
size_t instructions_to_replace = 1;
|
||||
|
||||
if (src2_op->getKind() == MachineOperand::KIND_IMM) {
|
||||
divisor = static_cast<ImmOperand *>(src2_op)->getValue();
|
||||
const_divisor_found = true;
|
||||
} else if (src2_op->getKind() == MachineOperand::KIND_REG) {
|
||||
if (i > 0) {
|
||||
auto *prev_instr = instrs[i - 1].get();
|
||||
if (prev_instr->getOpcode() == RVOpcodes::LI && prev_instr->getOperands().size() == 2) {
|
||||
auto *li_dst_op = prev_instr->getOperands()[0].get();
|
||||
auto *li_imm_op = prev_instr->getOperands()[1].get();
|
||||
if (li_dst_op->getKind() == MachineOperand::KIND_REG && li_imm_op->getKind() == MachineOperand::KIND_IMM) {
|
||||
auto *div_reg_op = static_cast<RegOperand *>(src2_op);
|
||||
auto *li_dst_reg_op = static_cast<RegOperand *>(li_dst_op);
|
||||
if (div_reg_op->isVirtual() && li_dst_reg_op->isVirtual() &&
|
||||
div_reg_op->getVRegNum() == li_dst_reg_op->getVRegNum()) {
|
||||
divisor = static_cast<ImmOperand *>(li_imm_op)->getValue();
|
||||
const_divisor_found = true;
|
||||
instructions_to_replace = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!const_divisor_found) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto *dst_reg = static_cast<RegOperand *>(dst_op);
|
||||
auto *src1_reg = static_cast<RegOperand *>(src1_op);
|
||||
|
||||
if (divisor == 0) continue;
|
||||
|
||||
std::vector<std::unique_ptr<MachineInstr>> newInstrs;
|
||||
|
||||
if (divisor == 1) {
|
||||
auto moveInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::ADDW : RVOpcodes::ADD);
|
||||
moveInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
|
||||
moveInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
|
||||
moveInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||
newInstrs.push_back(std::move(moveInstr));
|
||||
}
|
||||
else if (divisor == -1) {
|
||||
auto negInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SUBW : RVOpcodes::SUB);
|
||||
negInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
|
||||
negInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||
negInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
|
||||
newInstrs.push_back(std::move(negInstr));
|
||||
}
|
||||
else if (isPowerOfTwo(std::abs(divisor))) {
|
||||
int shift = getPowerOfTwoExponent(std::abs(divisor));
|
||||
int temp_reg = createTempReg();
|
||||
|
||||
auto sraSignInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SRAIW : RVOpcodes::SRAI);
|
||||
sraSignInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
sraSignInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
|
||||
sraSignInstr->addOperand(std::make_unique<ImmOperand>(is_32bit ? 31 : 63));
|
||||
newInstrs.push_back(std::move(sraSignInstr));
|
||||
|
||||
auto srlInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SRLIW : RVOpcodes::SRLI);
|
||||
srlInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
srlInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
srlInstr->addOperand(std::make_unique<ImmOperand>((is_32bit ? 32 : 64) - shift));
|
||||
newInstrs.push_back(std::move(srlInstr));
|
||||
|
||||
auto addInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::ADDW : RVOpcodes::ADD);
|
||||
addInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
addInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
|
||||
addInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
newInstrs.push_back(std::move(addInstr));
|
||||
|
||||
auto sraInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SRAIW : RVOpcodes::SRAI);
|
||||
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
sraInstr->addOperand(std::make_unique<ImmOperand>(shift));
|
||||
newInstrs.push_back(std::move(sraInstr));
|
||||
|
||||
if (divisor < 0) {
|
||||
auto negInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SUBW : RVOpcodes::SUB);
|
||||
negInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
|
||||
negInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||
negInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
newInstrs.push_back(std::move(negInstr));
|
||||
} else {
|
||||
auto moveInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::ADDW : RVOpcodes::ADD);
|
||||
moveInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
|
||||
moveInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
moveInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||
newInstrs.push_back(std::move(moveInstr));
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto magic_info = computeMagic(divisor, is_32bit);
|
||||
int magic_reg = createTempReg();
|
||||
int temp_reg = createTempReg();
|
||||
|
||||
auto loadInstr = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
loadInstr->addOperand(std::make_unique<RegOperand>(magic_reg));
|
||||
loadInstr->addOperand(std::make_unique<ImmOperand>(magic_info.magic));
|
||||
newInstrs.push_back(std::move(loadInstr));
|
||||
|
||||
if (is_32bit) {
|
||||
auto mulInstr = std::make_unique<MachineInstr>(RVOpcodes::MUL);
|
||||
mulInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
mulInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
|
||||
mulInstr->addOperand(std::make_unique<RegOperand>(magic_reg));
|
||||
newInstrs.push_back(std::move(mulInstr));
|
||||
|
||||
auto sraInstr = std::make_unique<MachineInstr>(RVOpcodes::SRAI);
|
||||
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
sraInstr->addOperand(std::make_unique<ImmOperand>(magic_info.shift));
|
||||
newInstrs.push_back(std::move(sraInstr));
|
||||
} else {
|
||||
auto mulhInstr = std::make_unique<MachineInstr>(RVOpcodes::MULH);
|
||||
mulhInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
mulhInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
|
||||
mulhInstr->addOperand(std::make_unique<RegOperand>(magic_reg));
|
||||
newInstrs.push_back(std::move(mulhInstr));
|
||||
|
||||
int post_shift = magic_info.shift - 63;
|
||||
if (post_shift > 0) {
|
||||
auto sraInstr = std::make_unique<MachineInstr>(RVOpcodes::SRAI);
|
||||
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
sraInstr->addOperand(std::make_unique<ImmOperand>(post_shift));
|
||||
newInstrs.push_back(std::move(sraInstr));
|
||||
}
|
||||
}
|
||||
|
||||
int sign_reg = createTempReg();
|
||||
auto sraSignInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SRAIW : RVOpcodes::SRAI);
|
||||
sraSignInstr->addOperand(std::make_unique<RegOperand>(sign_reg));
|
||||
sraSignInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
|
||||
sraSignInstr->addOperand(std::make_unique<ImmOperand>(is_32bit ? 31 : 63));
|
||||
newInstrs.push_back(std::move(sraSignInstr));
|
||||
|
||||
auto subInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SUBW : RVOpcodes::SUB);
|
||||
subInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
subInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
subInstr->addOperand(std::make_unique<RegOperand>(sign_reg));
|
||||
newInstrs.push_back(std::move(subInstr));
|
||||
|
||||
if (divisor < 0) {
|
||||
auto negInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SUBW : RVOpcodes::SUB);
|
||||
negInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
|
||||
negInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||
negInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
newInstrs.push_back(std::move(negInstr));
|
||||
} else {
|
||||
auto moveInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::ADDW : RVOpcodes::ADD);
|
||||
moveInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
|
||||
moveInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
moveInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||
newInstrs.push_back(std::move(moveInstr));
|
||||
}
|
||||
}
|
||||
|
||||
if (!newInstrs.empty()) {
|
||||
size_t start_index = i;
|
||||
if (instructions_to_replace == 2) {
|
||||
start_index = i - 1;
|
||||
}
|
||||
replacements.push_back({start_index, instructions_to_replace, std::move(newInstrs)});
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = replacements.rbegin(); it != replacements.rend(); ++it) {
|
||||
instrs.erase(instrs.begin() + it->index, instrs.begin() + it->index + it->count_to_erase);
|
||||
instrs.insert(instrs.begin() + it->index,
|
||||
std::make_move_iterator(it->newInstrs.begin()),
|
||||
std::make_move_iterator(it->newInstrs.end()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "PostRA_Scheduler.h"
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#define MAX_SCHEDULING_BLOCK_SIZE 10000 // 限制调度块大小,避免过大导致性能问题
|
||||
|
||||
namespace sysy {
|
||||
@@ -10,374 +10,407 @@ namespace sysy {
|
||||
char PostRA_Scheduler::ID = 0;
|
||||
|
||||
// 检查指令是否是加载指令 (LW, LD)
|
||||
bool isLoadInstr(MachineInstr* instr) {
|
||||
RVOpcodes opcode = instr->getOpcode();
|
||||
return opcode == RVOpcodes::LW || opcode == RVOpcodes::LD ||
|
||||
opcode == RVOpcodes::LH || opcode == RVOpcodes::LB ||
|
||||
opcode == RVOpcodes::LHU || opcode == RVOpcodes::LBU ||
|
||||
opcode == RVOpcodes::LWU;
|
||||
bool isLoadInstr(MachineInstr *instr) {
|
||||
RVOpcodes opcode = instr->getOpcode();
|
||||
return opcode == RVOpcodes::LW || opcode == RVOpcodes::LD ||
|
||||
opcode == RVOpcodes::LH || opcode == RVOpcodes::LB ||
|
||||
opcode == RVOpcodes::LHU || opcode == RVOpcodes::LBU ||
|
||||
opcode == RVOpcodes::LWU;
|
||||
}
|
||||
|
||||
// 检查指令是否是存储指令 (SW, SD)
|
||||
bool isStoreInstr(MachineInstr* instr) {
|
||||
RVOpcodes opcode = instr->getOpcode();
|
||||
return opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
|
||||
opcode == RVOpcodes::SH || opcode == RVOpcodes::SB;
|
||||
bool isStoreInstr(MachineInstr *instr) {
|
||||
RVOpcodes opcode = instr->getOpcode();
|
||||
return opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
|
||||
opcode == RVOpcodes::SH || opcode == RVOpcodes::SB;
|
||||
}
|
||||
|
||||
// 检查指令是否为控制流指令
|
||||
bool isControlFlowInstr(MachineInstr* instr) {
|
||||
RVOpcodes opcode = instr->getOpcode();
|
||||
return opcode == RVOpcodes::RET || opcode == RVOpcodes::J ||
|
||||
opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
||||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
||||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
|
||||
opcode == RVOpcodes::CALL;
|
||||
bool isControlFlowInstr(MachineInstr *instr) {
|
||||
RVOpcodes opcode = instr->getOpcode();
|
||||
return opcode == RVOpcodes::RET || opcode == RVOpcodes::J ||
|
||||
opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
||||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
||||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
|
||||
opcode == RVOpcodes::CALL;
|
||||
}
|
||||
|
||||
// 获取指令定义的寄存器 - 修复版本
|
||||
std::set<PhysicalReg> getDefinedRegisters(MachineInstr* instr) {
|
||||
std::set<PhysicalReg> defined_regs;
|
||||
RVOpcodes opcode = instr->getOpcode();
|
||||
|
||||
// 特殊处理CALL指令
|
||||
if (opcode == RVOpcodes::CALL) {
|
||||
// CALL指令可能定义返回值寄存器
|
||||
if (!instr->getOperands().empty() &&
|
||||
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
defined_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
}
|
||||
return defined_regs;
|
||||
}
|
||||
|
||||
// 存储指令不定义寄存器
|
||||
if (isStoreInstr(instr)) {
|
||||
return defined_regs;
|
||||
}
|
||||
|
||||
// 分支指令不定义寄存器
|
||||
if (opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
||||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
||||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
|
||||
opcode == RVOpcodes::J || opcode == RVOpcodes::RET) {
|
||||
return defined_regs;
|
||||
}
|
||||
|
||||
// 对于其他指令,第一个寄存器操作数通常是定义的
|
||||
if (!instr->getOperands().empty() &&
|
||||
// 预计算指令信息的缓存
|
||||
static std::unordered_map<MachineInstr *, InstrRegInfo> instr_info_cache;
|
||||
|
||||
// 获取指令定义的寄存器 - 优化版本
|
||||
std::unordered_set<PhysicalReg> getDefinedRegisters(MachineInstr *instr) {
|
||||
std::unordered_set<PhysicalReg> defined_regs;
|
||||
RVOpcodes opcode = instr->getOpcode();
|
||||
|
||||
// 特殊处理CALL指令
|
||||
if (opcode == RVOpcodes::CALL) {
|
||||
// CALL指令可能定义返回值寄存器
|
||||
if (!instr->getOperands().empty() &&
|
||||
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
defined_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
auto reg_op =
|
||||
static_cast<RegOperand *>(instr->getOperands().front().get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
defined_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
}
|
||||
|
||||
return defined_regs;
|
||||
}
|
||||
|
||||
// 存储指令不定义寄存器
|
||||
if (isStoreInstr(instr)) {
|
||||
return defined_regs;
|
||||
}
|
||||
|
||||
// 分支指令不定义寄存器
|
||||
if (opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
||||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
||||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
|
||||
opcode == RVOpcodes::J || opcode == RVOpcodes::RET) {
|
||||
return defined_regs;
|
||||
}
|
||||
|
||||
// 对于其他指令,第一个寄存器操作数通常是定义的
|
||||
if (!instr->getOperands().empty() &&
|
||||
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand *>(instr->getOperands().front().get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
defined_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
}
|
||||
|
||||
return defined_regs;
|
||||
}
|
||||
|
||||
// 获取指令使用的寄存器 - 修复版本
|
||||
std::set<PhysicalReg> getUsedRegisters(MachineInstr* instr) {
|
||||
std::set<PhysicalReg> used_regs;
|
||||
RVOpcodes opcode = instr->getOpcode();
|
||||
|
||||
// 特殊处理CALL指令
|
||||
if (opcode == RVOpcodes::CALL) {
|
||||
bool first_reg_skipped = false;
|
||||
for (const auto& op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
if (!first_reg_skipped) {
|
||||
first_reg_skipped = true;
|
||||
continue; // 跳过返回值寄存器
|
||||
}
|
||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
used_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
}
|
||||
// 获取指令使用的寄存器 - 优化版本
|
||||
std::unordered_set<PhysicalReg> getUsedRegisters(MachineInstr *instr) {
|
||||
std::unordered_set<PhysicalReg> used_regs;
|
||||
RVOpcodes opcode = instr->getOpcode();
|
||||
|
||||
// 特殊处理CALL指令
|
||||
if (opcode == RVOpcodes::CALL) {
|
||||
bool first_reg_skipped = false;
|
||||
for (const auto &op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
if (!first_reg_skipped) {
|
||||
first_reg_skipped = true;
|
||||
continue; // 跳过返回值寄存器
|
||||
}
|
||||
return used_regs;
|
||||
}
|
||||
|
||||
// 对于存储指令,所有寄存器操作数都是使用的
|
||||
if (isStoreInstr(instr)) {
|
||||
for (const auto& op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
used_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto mem_op = static_cast<MemOperand*>(op.get());
|
||||
if (!mem_op->getBase()->isVirtual()) {
|
||||
used_regs.insert(mem_op->getBase()->getPReg());
|
||||
}
|
||||
}
|
||||
}
|
||||
return used_regs;
|
||||
}
|
||||
|
||||
// 对于分支指令,所有寄存器操作数都是使用的
|
||||
if (opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
||||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
||||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU) {
|
||||
for (const auto& op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
used_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
}
|
||||
}
|
||||
return used_regs;
|
||||
}
|
||||
|
||||
// 对于其他指令,除了第一个寄存器操作数(通常是定义),其余都是使用的
|
||||
bool first_reg = true;
|
||||
for (const auto& op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
if (first_reg) {
|
||||
first_reg = false;
|
||||
continue; // 跳过第一个寄存器(定义)
|
||||
}
|
||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
used_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto mem_op = static_cast<MemOperand*>(op.get());
|
||||
if (!mem_op->getBase()->isVirtual()) {
|
||||
used_regs.insert(mem_op->getBase()->getPReg());
|
||||
}
|
||||
auto reg_op = static_cast<RegOperand *>(op.get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
used_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
}
|
||||
}
|
||||
return used_regs;
|
||||
}
|
||||
|
||||
// 对于存储指令,所有寄存器操作数都是使用的
|
||||
if (isStoreInstr(instr)) {
|
||||
for (const auto &op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand *>(op.get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
used_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto mem_op = static_cast<MemOperand *>(op.get());
|
||||
if (!mem_op->getBase()->isVirtual()) {
|
||||
used_regs.insert(mem_op->getBase()->getPReg());
|
||||
}
|
||||
}
|
||||
}
|
||||
return used_regs;
|
||||
}
|
||||
|
||||
// 对于分支指令,所有寄存器操作数都是使用的
|
||||
if (opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
||||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
||||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU) {
|
||||
for (const auto &op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand *>(op.get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
used_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
}
|
||||
}
|
||||
return used_regs;
|
||||
}
|
||||
|
||||
// 对于其他指令,除了第一个寄存器操作数(通常是定义),其余都是使用的
|
||||
bool first_reg = true;
|
||||
for (const auto &op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
if (first_reg) {
|
||||
first_reg = false;
|
||||
continue; // 跳过第一个寄存器(定义)
|
||||
}
|
||||
auto reg_op = static_cast<RegOperand *>(op.get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
used_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto mem_op = static_cast<MemOperand *>(op.get());
|
||||
if (!mem_op->getBase()->isVirtual()) {
|
||||
used_regs.insert(mem_op->getBase()->getPReg());
|
||||
}
|
||||
}
|
||||
}
|
||||
return used_regs;
|
||||
}
|
||||
|
||||
// 获取内存访问的基址和偏移
|
||||
struct MemoryAccess {
|
||||
PhysicalReg base_reg;
|
||||
int64_t offset;
|
||||
bool valid;
|
||||
|
||||
MemoryAccess() : valid(false) {}
|
||||
MemoryAccess(PhysicalReg base, int64_t off) : base_reg(base), offset(off), valid(true) {}
|
||||
};
|
||||
|
||||
MemoryAccess getMemoryAccess(MachineInstr* instr) {
|
||||
if (!isLoadInstr(instr) && !isStoreInstr(instr)) {
|
||||
return MemoryAccess();
|
||||
}
|
||||
|
||||
// 查找内存操作数
|
||||
for (const auto& op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto mem_op = static_cast<MemOperand*>(op.get());
|
||||
if (!mem_op->getBase()->isVirtual()) {
|
||||
return MemoryAccess(mem_op->getBase()->getPReg(), mem_op->getOffset()->getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MemoryAccess getMemoryAccess(MachineInstr *instr) {
|
||||
if (!isLoadInstr(instr) && !isStoreInstr(instr)) {
|
||||
return MemoryAccess();
|
||||
}
|
||||
|
||||
// 查找内存操作数
|
||||
for (const auto &op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto mem_op = static_cast<MemOperand *>(op.get());
|
||||
if (!mem_op->getBase()->isVirtual()) {
|
||||
return MemoryAccess(mem_op->getBase()->getPReg(),
|
||||
mem_op->getOffset()->getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MemoryAccess();
|
||||
}
|
||||
|
||||
// 检查内存依赖 - 加强版本
|
||||
bool hasMemoryDependency(MachineInstr* instr1, MachineInstr* instr2) {
|
||||
// 如果都不是内存指令,没有内存依赖
|
||||
if (!isLoadInstr(instr1) && !isStoreInstr(instr1) &&
|
||||
!isLoadInstr(instr2) && !isStoreInstr(instr2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MemoryAccess mem1 = getMemoryAccess(instr1);
|
||||
MemoryAccess mem2 = getMemoryAccess(instr2);
|
||||
|
||||
if (!mem1.valid || !mem2.valid) {
|
||||
// 如果无法确定内存访问模式,保守地认为存在依赖
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果访问相同的内存位置
|
||||
if (mem1.base_reg == mem2.base_reg && mem1.offset == mem2.offset) {
|
||||
// Store->Load: RAW依赖
|
||||
// Load->Store: WAR依赖
|
||||
// Store->Store: WAW依赖
|
||||
return isStoreInstr(instr1) || isStoreInstr(instr2);
|
||||
}
|
||||
|
||||
// 不同内存位置通常没有依赖,但为了安全起见,
|
||||
// 如果涉及store指令,我们需要更保守
|
||||
if (isStoreInstr(instr1) && isLoadInstr(instr2)) {
|
||||
// 保守处理:不同store和load之间可能有别名
|
||||
return false; // 这里可以根据需要调整策略
|
||||
}
|
||||
|
||||
// 预计算指令信息
|
||||
InstrRegInfo &getInstrInfo(MachineInstr *instr) {
|
||||
auto it = instr_info_cache.find(instr);
|
||||
if (it != instr_info_cache.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
InstrRegInfo &info = instr_info_cache[instr];
|
||||
info.defined_regs = getDefinedRegisters(instr);
|
||||
info.used_regs = getUsedRegisters(instr);
|
||||
info.is_load = isLoadInstr(instr);
|
||||
info.is_store = isStoreInstr(instr);
|
||||
info.is_control_flow = isControlFlowInstr(instr);
|
||||
info.mem_access = getMemoryAccess(instr);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
// 检查内存依赖 - 优化版本
|
||||
bool hasMemoryDependency(const InstrRegInfo &info1, const InstrRegInfo &info2) {
|
||||
// 如果都不是内存指令,没有内存依赖
|
||||
if (!info1.is_load && !info1.is_store && !info2.is_load && !info2.is_store) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const MemoryAccess &mem1 = info1.mem_access;
|
||||
const MemoryAccess &mem2 = info2.mem_access;
|
||||
|
||||
if (!mem1.valid || !mem2.valid) {
|
||||
// 如果无法确定内存访问模式,保守地认为存在依赖
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果访问相同的内存位置
|
||||
if (mem1.base_reg == mem2.base_reg && mem1.offset == mem2.offset) {
|
||||
// Store->Load: RAW依赖
|
||||
// Load->Store: WAR依赖
|
||||
// Store->Store: WAW依赖
|
||||
return info1.is_store || info2.is_store;
|
||||
}
|
||||
|
||||
// 不同内存位置通常没有依赖,但为了安全起见,
|
||||
// 如果涉及store指令,我们需要更保守
|
||||
if (info1.is_store && info2.is_load) {
|
||||
// 保守处理:不同store和load之间可能有别名
|
||||
return false; // 这里可以根据需要调整策略
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查两个指令之间是否存在依赖关系 - 修复版本
|
||||
bool hasDependency(MachineInstr* instr1, MachineInstr* instr2) {
|
||||
// 检查RAW依赖:instr1定义的寄存器是否被instr2使用
|
||||
auto defined_regs1 = getDefinedRegisters(instr1);
|
||||
auto used_regs2 = getUsedRegisters(instr2);
|
||||
|
||||
for (const auto& reg : defined_regs1) {
|
||||
if (used_regs2.find(reg) != used_regs2.end()) {
|
||||
return true; // RAW依赖 - instr2读取instr1写入的值
|
||||
}
|
||||
// 检查两个指令之间是否存在依赖关系 - 优化版本
|
||||
bool hasDependency(MachineInstr *instr1, MachineInstr *instr2) {
|
||||
const InstrRegInfo &info1 = getInstrInfo(instr1);
|
||||
const InstrRegInfo &info2 = getInstrInfo(instr2);
|
||||
|
||||
// 检查RAW依赖:instr1定义的寄存器是否被instr2使用
|
||||
for (const auto ® : info1.defined_regs) {
|
||||
if (info2.used_regs.find(reg) != info2.used_regs.end()) {
|
||||
return true; // RAW依赖 - instr2读取instr1写入的值
|
||||
}
|
||||
|
||||
// 检查WAR依赖:instr1使用的寄存器是否被instr2定义
|
||||
auto used_regs1 = getUsedRegisters(instr1);
|
||||
auto defined_regs2 = getDefinedRegisters(instr2);
|
||||
|
||||
for (const auto& reg : used_regs1) {
|
||||
if (defined_regs2.find(reg) != defined_regs2.end()) {
|
||||
return true; // WAR依赖 - instr2覆盖instr1需要的值
|
||||
}
|
||||
}
|
||||
|
||||
// 检查WAR依赖:instr1使用的寄存器是否被instr2定义
|
||||
for (const auto ® : info1.used_regs) {
|
||||
if (info2.defined_regs.find(reg) != info2.defined_regs.end()) {
|
||||
return true; // WAR依赖 - instr2覆盖instr1需要的值
|
||||
}
|
||||
|
||||
// 检查WAW依赖:两个指令定义相同寄存器
|
||||
for (const auto& reg : defined_regs1) {
|
||||
if (defined_regs2.find(reg) != defined_regs2.end()) {
|
||||
return true; // WAW依赖 - 两条指令写入同一寄存器
|
||||
}
|
||||
}
|
||||
|
||||
// 检查WAW依赖:两个指令定义相同寄存器
|
||||
for (const auto ® : info1.defined_regs) {
|
||||
if (info2.defined_regs.find(reg) != info2.defined_regs.end()) {
|
||||
return true; // WAW依赖 - 两条指令写入同一寄存器
|
||||
}
|
||||
|
||||
// 检查内存依赖
|
||||
if (hasMemoryDependency(instr1, instr2)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 检查内存依赖
|
||||
if (hasMemoryDependency(info1, info2)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否可以安全地将instr1和instr2交换位置 - 优化版本
|
||||
bool canSwapInstructions(MachineInstr *instr1, MachineInstr *instr2) {
|
||||
const InstrRegInfo &info1 = getInstrInfo(instr1);
|
||||
const InstrRegInfo &info2 = getInstrInfo(instr2);
|
||||
|
||||
// 不能移动控制流指令
|
||||
if (info1.is_control_flow || info2.is_control_flow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查双向依赖关系
|
||||
return !hasDependency(instr1, instr2) && !hasDependency(instr2, instr1);
|
||||
}
|
||||
|
||||
// 检查是否可以安全地将instr1和instr2交换位置
|
||||
bool canSwapInstructions(MachineInstr* instr1, MachineInstr* instr2) {
|
||||
// 不能移动控制流指令
|
||||
if (isControlFlowInstr(instr1) || isControlFlowInstr(instr2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查双向依赖关系
|
||||
return !hasDependency(instr1, instr2) && !hasDependency(instr2, instr1);
|
||||
}
|
||||
// 新增:验证调度结果的正确性 - 优化版本
|
||||
void validateSchedule(const std::vector<MachineInstr *> &instr_list) {
|
||||
for (int i = 0; i < (int)instr_list.size(); i++) {
|
||||
for (int j = i + 1; j < (int)instr_list.size(); j++) {
|
||||
MachineInstr *earlier = instr_list[i];
|
||||
MachineInstr *later = instr_list[j];
|
||||
|
||||
// 新增:验证调度结果的正确性
|
||||
void validateSchedule(const std::vector<MachineInstr*>& instr_list) {
|
||||
for (int i = 0; i < (int)instr_list.size(); i++) {
|
||||
for (int j = i + 1; j < (int)instr_list.size(); j++) {
|
||||
MachineInstr* earlier = instr_list[i];
|
||||
MachineInstr* later = instr_list[j];
|
||||
|
||||
// 检查是否存在被违反的依赖关系
|
||||
auto defined_regs = getDefinedRegisters(earlier);
|
||||
auto used_regs = getUsedRegisters(later);
|
||||
|
||||
// 检查RAW依赖
|
||||
for (const auto& reg : defined_regs) {
|
||||
if (used_regs.find(reg) != used_regs.end()) {
|
||||
// 这是正常的依赖关系,earlier应该在later之前
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查内存依赖
|
||||
if (hasMemoryDependency(earlier, later)) {
|
||||
MemoryAccess mem1 = getMemoryAccess(earlier);
|
||||
MemoryAccess mem2 = getMemoryAccess(later);
|
||||
|
||||
if (mem1.valid && mem2.valid &&
|
||||
mem1.base_reg == mem2.base_reg && mem1.offset == mem2.offset) {
|
||||
if (isStoreInstr(earlier) && isLoadInstr(later)) {
|
||||
// Store->Load依赖,顺序正确
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
const InstrRegInfo &info_earlier = getInstrInfo(earlier);
|
||||
const InstrRegInfo &info_later = getInstrInfo(later);
|
||||
|
||||
// 检查是否存在被违反的依赖关系
|
||||
// 检查RAW依赖
|
||||
for (const auto ® : info_earlier.defined_regs) {
|
||||
if (info_later.used_regs.find(reg) != info_later.used_regs.end()) {
|
||||
// 这是正常的依赖关系,earlier应该在later之前
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 在基本块内对指令进行调度优化 - 完全重写版本
|
||||
void scheduleBlock(MachineBasicBlock* mbb) {
|
||||
auto& instructions = mbb->getInstructions();
|
||||
if (instructions.size() <= 1) return;
|
||||
if (instructions.size() > MAX_SCHEDULING_BLOCK_SIZE) {
|
||||
return; // 跳过超大块,防止卡住
|
||||
}
|
||||
|
||||
std::vector<MachineInstr*> instr_list;
|
||||
for (auto& instr : instructions) {
|
||||
instr_list.push_back(instr.get());
|
||||
}
|
||||
|
||||
// 使用更严格的调度策略,避免破坏依赖关系
|
||||
bool changed = true;
|
||||
int max_iterations = 10; // 限制迭代次数避免死循环
|
||||
int iteration = 0;
|
||||
|
||||
while (changed && iteration < max_iterations) {
|
||||
changed = false;
|
||||
iteration++;
|
||||
|
||||
for (int i = 0; i < (int)instr_list.size() - 1; i++) {
|
||||
MachineInstr* instr1 = instr_list[i];
|
||||
MachineInstr* instr2 = instr_list[i + 1];
|
||||
|
||||
// 只进行非常保守的优化
|
||||
bool should_swap = false;
|
||||
|
||||
// 策略1: 将load指令提前,减少load-use延迟
|
||||
if (isLoadInstr(instr2) && !isLoadInstr(instr1) && !isStoreInstr(instr1)) {
|
||||
should_swap = canSwapInstructions(instr1, instr2);
|
||||
}
|
||||
// 策略2: 将非关键store指令延后,为其他指令让路
|
||||
else if (isStoreInstr(instr1) && !isLoadInstr(instr2) && !isStoreInstr(instr2)) {
|
||||
should_swap = canSwapInstructions(instr1, instr2);
|
||||
}
|
||||
|
||||
if (should_swap) {
|
||||
std::swap(instr_list[i], instr_list[i + 1]);
|
||||
changed = true;
|
||||
|
||||
// 调试输出
|
||||
// std::cout << "Swapped instructions at positions " << i << " and " << (i+1) << std::endl;
|
||||
}
|
||||
// 检查内存依赖
|
||||
if (hasMemoryDependency(info_earlier, info_later)) {
|
||||
const MemoryAccess &mem1 = info_earlier.mem_access;
|
||||
const MemoryAccess &mem2 = info_later.mem_access;
|
||||
|
||||
if (mem1.valid && mem2.valid && mem1.base_reg == mem2.base_reg &&
|
||||
mem1.offset == mem2.offset) {
|
||||
if (info_earlier.is_store && info_later.is_load) {
|
||||
// Store->Load依赖,顺序正确
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 验证调度结果的正确性
|
||||
validateSchedule(instr_list);
|
||||
|
||||
// 将调度后的指令顺序写回
|
||||
std::map<MachineInstr*, std::unique_ptr<MachineInstr>> instr_map;
|
||||
for (auto& instr : instructions) {
|
||||
instr_map[instr.get()] = std::move(instr);
|
||||
}
|
||||
|
||||
instructions.clear();
|
||||
for (auto instr : instr_list) {
|
||||
instructions.push_back(std::move(instr_map[instr]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PostRA_Scheduler::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
// 这个函数在IR级别运行,但我们需要在机器指令级别运行
|
||||
// 所以我们返回false,表示没有对IR进行修改
|
||||
return false;
|
||||
// 在基本块内对指令进行调度优化 - 优化版本
|
||||
void scheduleBlock(MachineBasicBlock *mbb) {
|
||||
auto &instructions = mbb->getInstructions();
|
||||
if (instructions.size() <= 1)
|
||||
return;
|
||||
if (instructions.size() > MAX_SCHEDULING_BLOCK_SIZE) {
|
||||
return; // 跳过超大块,防止卡住
|
||||
}
|
||||
|
||||
// 清理缓存,避免无效指针
|
||||
instr_info_cache.clear();
|
||||
|
||||
std::vector<MachineInstr *> instr_list;
|
||||
instr_list.reserve(instructions.size()); // 预分配容量
|
||||
for (auto &instr : instructions) {
|
||||
instr_list.push_back(instr.get());
|
||||
}
|
||||
|
||||
// 预计算所有指令的信息
|
||||
for (auto *instr : instr_list) {
|
||||
getInstrInfo(instr);
|
||||
}
|
||||
|
||||
// 使用更严格的调度策略,避免破坏依赖关系
|
||||
bool changed = true;
|
||||
int max_iterations = 10; // 限制迭代次数避免死循环
|
||||
int iteration = 0;
|
||||
|
||||
while (changed && iteration < max_iterations) {
|
||||
changed = false;
|
||||
iteration++;
|
||||
|
||||
for (int i = 0; i < (int)instr_list.size() - 1; i++) {
|
||||
MachineInstr *instr1 = instr_list[i];
|
||||
MachineInstr *instr2 = instr_list[i + 1];
|
||||
|
||||
const InstrRegInfo &info1 = getInstrInfo(instr1);
|
||||
const InstrRegInfo &info2 = getInstrInfo(instr2);
|
||||
|
||||
// 只进行非常保守的优化
|
||||
bool should_swap = false;
|
||||
|
||||
// 策略1: 将load指令提前,减少load-use延迟
|
||||
if (info2.is_load && !info1.is_load && !info1.is_store) {
|
||||
should_swap = canSwapInstructions(instr1, instr2);
|
||||
}
|
||||
// 策略2: 将非关键store指令延后,为其他指令让路
|
||||
else if (info1.is_store && !info2.is_load && !info2.is_store) {
|
||||
should_swap = canSwapInstructions(instr1, instr2);
|
||||
}
|
||||
|
||||
if (should_swap) {
|
||||
std::swap(instr_list[i], instr_list[i + 1]);
|
||||
changed = true;
|
||||
|
||||
// 调试输出
|
||||
// std::cout << "Swapped instructions at positions " << i << " and " <<
|
||||
// (i+1) << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 验证调度结果的正确性
|
||||
validateSchedule(instr_list);
|
||||
|
||||
// 将调度后的指令顺序写回
|
||||
std::unordered_map<MachineInstr *, std::unique_ptr<MachineInstr>> instr_map;
|
||||
instr_map.reserve(instructions.size()); // 预分配容量
|
||||
for (auto &instr : instructions) {
|
||||
instr_map[instr.get()] = std::move(instr);
|
||||
}
|
||||
|
||||
instructions.clear();
|
||||
instructions.reserve(instr_list.size()); // 预分配容量
|
||||
for (auto instr : instr_list) {
|
||||
instructions.push_back(std::move(instr_map[instr]));
|
||||
}
|
||||
}
|
||||
|
||||
bool PostRA_Scheduler::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
// 这个函数在IR级别运行,但我们需要在机器指令级别运行
|
||||
// 所以我们返回false,表示没有对IR进行修改
|
||||
return false;
|
||||
}
|
||||
|
||||
void PostRA_Scheduler::runOnMachineFunction(MachineFunction *mfunc) {
|
||||
// std::cout << "Running Post-RA Local Scheduler... " << std::endl;
|
||||
|
||||
// 遍历每个机器基本块
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
scheduleBlock(mbb.get());
|
||||
}
|
||||
// std::cout << "Running Post-RA Local Scheduler... " << std::endl;
|
||||
|
||||
// 遍历每个机器基本块
|
||||
for (auto &mbb : mfunc->getBlocks()) {
|
||||
scheduleBlock(mbb.get());
|
||||
}
|
||||
|
||||
// 清理全局缓存
|
||||
instr_info_cache.clear();
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "PreRA_Scheduler.h"
|
||||
#include "RISCv64LLIR.h"
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#define MAX_SCHEDULING_BLOCK_SIZE 1000 // 严格限制调度块大小
|
||||
@@ -66,9 +66,44 @@ static bool hasMemoryAccess(MachineInstr *instr) {
|
||||
return isLoadInstr(instr) || isStoreInstr(instr);
|
||||
}
|
||||
|
||||
// 获取指令定义的虚拟寄存器
|
||||
static std::set<unsigned> getDefinedVirtualRegisters(MachineInstr *instr) {
|
||||
std::set<unsigned> defined_regs;
|
||||
// 获取内存访问位置信息
|
||||
struct MemoryLocation {
|
||||
unsigned base_reg;
|
||||
int64_t offset;
|
||||
bool is_valid;
|
||||
|
||||
MemoryLocation() : base_reg(0), offset(0), is_valid(false) {}
|
||||
MemoryLocation(unsigned base, int64_t off)
|
||||
: base_reg(base), offset(off), is_valid(true) {}
|
||||
|
||||
bool operator==(const MemoryLocation &other) const {
|
||||
return is_valid && other.is_valid && base_reg == other.base_reg &&
|
||||
offset == other.offset;
|
||||
}
|
||||
};
|
||||
|
||||
// 缓存指令分析信息
|
||||
struct InstrInfo {
|
||||
std::unordered_set<unsigned> defined_regs;
|
||||
std::unordered_set<unsigned> used_regs;
|
||||
MemoryLocation mem_location;
|
||||
bool is_load;
|
||||
bool is_store;
|
||||
bool is_terminator;
|
||||
bool is_call;
|
||||
bool has_side_effect;
|
||||
bool has_memory_access;
|
||||
|
||||
InstrInfo() : is_load(false), is_store(false), is_terminator(false),
|
||||
is_call(false), has_side_effect(false), has_memory_access(false) {}
|
||||
};
|
||||
|
||||
// 指令信息缓存
|
||||
static std::unordered_map<MachineInstr*, InstrInfo> instr_info_cache;
|
||||
|
||||
// 获取指令定义的虚拟寄存器 - 优化版本
|
||||
static std::unordered_set<unsigned> getDefinedVirtualRegisters(MachineInstr *instr) {
|
||||
std::unordered_set<unsigned> defined_regs;
|
||||
RVOpcodes opcode = instr->getOpcode();
|
||||
|
||||
// CALL指令可能定义返回值寄存器
|
||||
@@ -101,9 +136,9 @@ static std::set<unsigned> getDefinedVirtualRegisters(MachineInstr *instr) {
|
||||
return defined_regs;
|
||||
}
|
||||
|
||||
// 获取指令使用的虚拟寄存器
|
||||
static std::set<unsigned> getUsedVirtualRegisters(MachineInstr *instr) {
|
||||
std::set<unsigned> used_regs;
|
||||
// 获取指令使用的虚拟寄存器 - 优化版本
|
||||
static std::unordered_set<unsigned> getUsedVirtualRegisters(MachineInstr *instr) {
|
||||
std::unordered_set<unsigned> used_regs;
|
||||
RVOpcodes opcode = instr->getOpcode();
|
||||
|
||||
// CALL指令:跳过第一个操作数(返回值),其余为参数
|
||||
@@ -164,22 +199,6 @@ static std::set<unsigned> getUsedVirtualRegisters(MachineInstr *instr) {
|
||||
return used_regs;
|
||||
}
|
||||
|
||||
// 获取内存访问位置信息
|
||||
struct MemoryLocation {
|
||||
unsigned base_reg;
|
||||
int64_t offset;
|
||||
bool is_valid;
|
||||
|
||||
MemoryLocation() : base_reg(0), offset(0), is_valid(false) {}
|
||||
MemoryLocation(unsigned base, int64_t off)
|
||||
: base_reg(base), offset(off), is_valid(true) {}
|
||||
|
||||
bool operator==(const MemoryLocation &other) const {
|
||||
return is_valid && other.is_valid && base_reg == other.base_reg &&
|
||||
offset == other.offset;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取内存访问位置
|
||||
static MemoryLocation getMemoryLocation(MachineInstr *instr) {
|
||||
if (!isLoadInstr(instr) && !isStoreInstr(instr)) {
|
||||
@@ -199,6 +218,27 @@ static MemoryLocation getMemoryLocation(MachineInstr *instr) {
|
||||
return MemoryLocation();
|
||||
}
|
||||
|
||||
// 预计算并缓存指令信息
|
||||
static const InstrInfo& getInstrInfo(MachineInstr *instr) {
|
||||
auto it = instr_info_cache.find(instr);
|
||||
if (it != instr_info_cache.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
InstrInfo& info = instr_info_cache[instr];
|
||||
info.defined_regs = getDefinedVirtualRegisters(instr);
|
||||
info.used_regs = getUsedVirtualRegisters(instr);
|
||||
info.mem_location = getMemoryLocation(instr);
|
||||
info.is_load = isLoadInstr(instr);
|
||||
info.is_store = isStoreInstr(instr);
|
||||
info.is_terminator = isTerminatorInstr(instr);
|
||||
info.is_call = isCallInstr(instr);
|
||||
info.has_side_effect = hasSideEffect(instr);
|
||||
info.has_memory_access = hasMemoryAccess(instr);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
// 检查两个内存位置是否可能别名
|
||||
static bool mayAlias(const MemoryLocation &loc1, const MemoryLocation &loc2) {
|
||||
if (!loc1.is_valid || !loc2.is_valid) {
|
||||
@@ -214,30 +254,28 @@ static bool mayAlias(const MemoryLocation &loc1, const MemoryLocation &loc2) {
|
||||
return loc1.offset == loc2.offset;
|
||||
}
|
||||
|
||||
// 检查两个指令之间是否存在数据依赖
|
||||
// 检查两个指令之间是否存在数据依赖 - 优化版本
|
||||
static bool hasDataDependency(MachineInstr *first, MachineInstr *second) {
|
||||
auto defined_regs_first = getDefinedVirtualRegisters(first);
|
||||
auto used_regs_first = getUsedVirtualRegisters(first);
|
||||
auto defined_regs_second = getDefinedVirtualRegisters(second);
|
||||
auto used_regs_second = getUsedVirtualRegisters(second);
|
||||
const InstrInfo& info_first = getInstrInfo(first);
|
||||
const InstrInfo& info_second = getInstrInfo(second);
|
||||
|
||||
// RAW依赖: second读取first写入的寄存器
|
||||
for (const auto ® : defined_regs_first) {
|
||||
if (used_regs_second.count(reg)) {
|
||||
for (const auto ® : info_first.defined_regs) {
|
||||
if (info_second.used_regs.find(reg) != info_second.used_regs.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// WAR依赖: second写入first读取的寄存器
|
||||
for (const auto ® : used_regs_first) {
|
||||
if (defined_regs_second.count(reg)) {
|
||||
for (const auto ® : info_first.used_regs) {
|
||||
if (info_second.defined_regs.find(reg) != info_second.defined_regs.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// WAW依赖: 两个指令写入同一寄存器
|
||||
for (const auto ® : defined_regs_first) {
|
||||
if (defined_regs_second.count(reg)) {
|
||||
for (const auto ® : info_first.defined_regs) {
|
||||
if (info_second.defined_regs.find(reg) != info_second.defined_regs.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -245,40 +283,41 @@ static bool hasDataDependency(MachineInstr *first, MachineInstr *second) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查两个指令之间是否存在内存依赖
|
||||
// 检查两个指令之间是否存在内存依赖 - 优化版本
|
||||
static bool hasMemoryDependency(MachineInstr *first, MachineInstr *second) {
|
||||
bool first_accesses_memory = isLoadInstr(first) || isStoreInstr(first);
|
||||
bool second_accesses_memory = isLoadInstr(second) || isStoreInstr(second);
|
||||
const InstrInfo& info_first = getInstrInfo(first);
|
||||
const InstrInfo& info_second = getInstrInfo(second);
|
||||
|
||||
if (!first_accesses_memory || !second_accesses_memory) {
|
||||
if (!info_first.has_memory_access || !info_second.has_memory_access) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 如果至少有一个是存储指令,需要检查别名
|
||||
if (isStoreInstr(first) || isStoreInstr(second)) {
|
||||
MemoryLocation loc1 = getMemoryLocation(first);
|
||||
MemoryLocation loc2 = getMemoryLocation(second);
|
||||
return mayAlias(loc1, loc2);
|
||||
if (info_first.is_store || info_second.is_store) {
|
||||
return mayAlias(info_first.mem_location, info_second.mem_location);
|
||||
}
|
||||
|
||||
return false; // 两个加载指令之间没有依赖
|
||||
}
|
||||
|
||||
// 检查两个指令之间是否存在控制依赖
|
||||
// 检查两个指令之间是否存在控制依赖 - 优化版本
|
||||
static bool hasControlDependency(MachineInstr *first, MachineInstr *second) {
|
||||
const InstrInfo& info_first = getInstrInfo(first);
|
||||
const InstrInfo& info_second = getInstrInfo(second);
|
||||
|
||||
// 终结指令与任何其他指令都有控制依赖
|
||||
if (isTerminatorInstr(first)) {
|
||||
if (info_first.is_terminator) {
|
||||
return true; // first是终结指令,second不能移动到first之前
|
||||
}
|
||||
|
||||
if (isTerminatorInstr(second)) {
|
||||
if (info_second.is_terminator) {
|
||||
return false; // second是终结指令,可以保持在后面
|
||||
}
|
||||
|
||||
// CALL指令具有控制副作用,但可以参与有限的调度
|
||||
if (isCallInstr(first) || isCallInstr(second)) {
|
||||
if (info_first.is_call || info_second.is_call) {
|
||||
// CALL指令之间保持顺序
|
||||
if (isCallInstr(first) && isCallInstr(second)) {
|
||||
if (info_first.is_call && info_second.is_call) {
|
||||
return true;
|
||||
}
|
||||
// 其他情况允许调度(通过数据依赖控制)
|
||||
@@ -287,7 +326,7 @@ static bool hasControlDependency(MachineInstr *first, MachineInstr *second) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 综合检查两个指令是否可以交换
|
||||
// 综合检查两个指令是否可以交换 - 优化版本
|
||||
static bool canSwapInstructions(MachineInstr *first, MachineInstr *second) {
|
||||
// 检查所有类型的依赖
|
||||
if (hasDataDependency(first, second) || hasDataDependency(second, first)) {
|
||||
@@ -306,15 +345,17 @@ static bool canSwapInstructions(MachineInstr *first, MachineInstr *second) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 找到基本块中的调度边界
|
||||
// 找到基本块中的调度边界 - 优化版本
|
||||
static std::vector<size_t>
|
||||
findSchedulingBoundaries(const std::vector<MachineInstr *> &instrs) {
|
||||
std::vector<size_t> boundaries;
|
||||
boundaries.reserve(instrs.size() / 10); // 预估边界数量
|
||||
boundaries.push_back(0); // 起始边界
|
||||
|
||||
for (size_t i = 0; i < instrs.size(); i++) {
|
||||
const InstrInfo& info = getInstrInfo(instrs[i]);
|
||||
// 终结指令前后都是边界
|
||||
if (isTerminatorInstr(instrs[i])) {
|
||||
if (info.is_terminator) {
|
||||
if (i > 0)
|
||||
boundaries.push_back(i);
|
||||
if (i + 1 < instrs.size())
|
||||
@@ -333,7 +374,7 @@ findSchedulingBoundaries(const std::vector<MachineInstr *> &instrs) {
|
||||
return boundaries;
|
||||
}
|
||||
|
||||
// 在单个调度区域内进行指令调度
|
||||
// 在单个调度区域内进行指令调度 - 优化版本
|
||||
static void scheduleRegion(std::vector<MachineInstr *> &instrs, size_t start,
|
||||
size_t end) {
|
||||
if (end - start <= 1) {
|
||||
@@ -347,7 +388,8 @@ static void scheduleRegion(std::vector<MachineInstr *> &instrs, size_t start,
|
||||
|
||||
// 简单的调度算法:只尝试将加载指令尽可能前移
|
||||
for (size_t i = start + 1; i < end; i++) {
|
||||
if (isLoadInstr(instrs[i])) {
|
||||
const InstrInfo& info = getInstrInfo(instrs[i]);
|
||||
if (info.is_load) {
|
||||
// 尝试将加载指令向前移动
|
||||
for (size_t j = i; j > start; j--) {
|
||||
// 检查是否可以与前一条指令交换
|
||||
@@ -369,12 +411,21 @@ static void scheduleBlock(MachineBasicBlock *mbb) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 清理缓存,避免无效指针
|
||||
instr_info_cache.clear();
|
||||
|
||||
// 构建指令列表
|
||||
std::vector<MachineInstr *> instr_list;
|
||||
instr_list.reserve(instructions.size()); // 预分配容量
|
||||
for (auto &instr : instructions) {
|
||||
instr_list.push_back(instr.get());
|
||||
}
|
||||
|
||||
// 预计算所有指令信息
|
||||
for (auto* instr : instr_list) {
|
||||
getInstrInfo(instr);
|
||||
}
|
||||
|
||||
// 找到调度边界
|
||||
std::vector<size_t> boundaries = findSchedulingBoundaries(instr_list);
|
||||
|
||||
@@ -386,12 +437,14 @@ static void scheduleBlock(MachineBasicBlock *mbb) {
|
||||
}
|
||||
|
||||
// 重建指令序列
|
||||
std::map<MachineInstr *, std::unique_ptr<MachineInstr>> instr_map;
|
||||
std::unordered_map<MachineInstr *, std::unique_ptr<MachineInstr>> instr_map;
|
||||
instr_map.reserve(instructions.size()); // 预分配容量
|
||||
for (auto &instr : instructions) {
|
||||
instr_map[instr.get()] = std::move(instr);
|
||||
}
|
||||
|
||||
instructions.clear();
|
||||
instructions.reserve(instr_list.size()); // 预分配容量
|
||||
for (auto *instr : instr_list) {
|
||||
instructions.push_back(std::move(instr_map[instr]));
|
||||
}
|
||||
@@ -405,6 +458,9 @@ void PreRA_Scheduler::runOnMachineFunction(MachineFunction *mfunc) {
|
||||
for (auto &mbb : mfunc->getBlocks()) {
|
||||
scheduleBlock(mbb.get());
|
||||
}
|
||||
|
||||
// 清理全局缓存
|
||||
instr_info_cache.clear();
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@@ -1,20 +1,10 @@
|
||||
#include "RISCv64AsmPrinter.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include <stdexcept>
|
||||
|
||||
#include <sstream>
|
||||
#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:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
RISCv64AsmPrinter::RISCv64AsmPrinter(MachineFunction* mfunc) : MFunc(mfunc) {}
|
||||
|
||||
@@ -54,7 +44,7 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
|
||||
case RVOpcodes::ADD: *OS << "add "; break; case RVOpcodes::ADDI: *OS << "addi "; break;
|
||||
case RVOpcodes::ADDW: *OS << "addw "; break; case RVOpcodes::ADDIW: *OS << "addiw "; break;
|
||||
case RVOpcodes::SUB: *OS << "sub "; break; case RVOpcodes::SUBW: *OS << "subw "; break;
|
||||
case RVOpcodes::MUL: *OS << "mul "; break; case RVOpcodes::MULW: *OS << "mulw "; break;
|
||||
case RVOpcodes::MUL: *OS << "mul "; break; case RVOpcodes::MULW: *OS << "mulw "; break; case RVOpcodes::MULH: *OS << "mulh "; break;
|
||||
case RVOpcodes::DIV: *OS << "div "; break; case RVOpcodes::DIVW: *OS << "divw "; break;
|
||||
case RVOpcodes::REM: *OS << "rem "; break; case RVOpcodes::REMW: *OS << "remw "; break;
|
||||
case RVOpcodes::XOR: *OS << "xor "; break; case RVOpcodes::XORI: *OS << "xori "; break;
|
||||
@@ -73,7 +63,9 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
|
||||
case RVOpcodes::LHU: *OS << "lhu "; break; case RVOpcodes::LBU: *OS << "lbu "; break;
|
||||
case RVOpcodes::SW: *OS << "sw "; break; case RVOpcodes::SH: *OS << "sh "; break;
|
||||
case RVOpcodes::SB: *OS << "sb "; break; case RVOpcodes::LD: *OS << "ld "; break;
|
||||
case RVOpcodes::SD: *OS << "sd "; 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::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;
|
||||
@@ -82,8 +74,23 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
|
||||
case RVOpcodes::LI: *OS << "li "; break; case RVOpcodes::LA: *OS << "la "; break;
|
||||
case RVOpcodes::MV: *OS << "mv "; break; case RVOpcodes::NEG: *OS << "neg "; break;
|
||||
case RVOpcodes::NEGW: *OS << "negw "; break; case RVOpcodes::SEQZ: *OS << "seqz "; break;
|
||||
case RVOpcodes::SNEZ: *OS << "snez "; break;
|
||||
case RVOpcodes::CALL: { // [核心修改] 为CALL指令添加特殊处理逻辑
|
||||
case RVOpcodes::SNEZ: *OS << "snez "; break;
|
||||
case RVOpcodes::FADD_S: *OS << "fadd.s "; break;
|
||||
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::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 ";
|
||||
// 遍历所有操作数,只寻找并打印函数名标签
|
||||
for (const auto& op : instr->getOperands()) {
|
||||
@@ -117,6 +124,15 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
|
||||
// It should have been eliminated by RegAlloc
|
||||
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
||||
*OS << "frame_addr "; break;
|
||||
case RVOpcodes::FRAME_LOAD_F:
|
||||
if (!debug) throw std::runtime_error("FRAME_LOAD_F not eliminated before AsmPrinter");
|
||||
*OS << "frame_load_f "; break;
|
||||
case RVOpcodes::FRAME_STORE_F:
|
||||
if (!debug) throw std::runtime_error("FRAME_STORE_F not eliminated before AsmPrinter");
|
||||
*OS << "frame_store_f "; break;
|
||||
case RVOpcodes::PSEUDO_KEEPALIVE:
|
||||
if (!debug) throw std::runtime_error("PSEUDO_KEEPALIVE not eliminated before AsmPrinter");
|
||||
*OS << "keepalive "; break;
|
||||
default:
|
||||
throw std::runtime_error("Unknown opcode in AsmPrinter");
|
||||
}
|
||||
@@ -206,4 +222,30 @@ std::string RISCv64AsmPrinter::regToString(PhysicalReg reg) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string RISCv64AsmPrinter::formatInstr(const MachineInstr* instr) {
|
||||
if (!instr) return "(null instr)";
|
||||
|
||||
// 使用 stringstream 作为临时的输出目标
|
||||
std::stringstream ss;
|
||||
|
||||
// 关键: 临时将类成员 'OS' 指向我们的 stringstream
|
||||
std::ostream* old_os = this->OS;
|
||||
this->OS = &ss;
|
||||
|
||||
// 修正: 调用正确的内部打印函数 printMachineInstr
|
||||
printInstruction(const_cast<MachineInstr*>(instr), false);
|
||||
|
||||
// 恢复旧的 ostream 指针
|
||||
this->OS = old_os;
|
||||
|
||||
// 获取stringstream的内容并做一些清理
|
||||
std::string result = ss.str();
|
||||
size_t endpos = result.find_last_not_of(" \t\n\r");
|
||||
if (std::string::npos != endpos) {
|
||||
result = result.substr(0, endpos + 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@@ -1,10 +1,14 @@
|
||||
#include "RISCv64Backend.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include "RISCv64RegAlloc.h"
|
||||
#include "RISCv64LinearScan.h"
|
||||
#include "RISCv64BasicBlockAlloc.h"
|
||||
#include "RISCv64AsmPrinter.h"
|
||||
#include "RISCv64Passes.h"
|
||||
#include <sstream>
|
||||
|
||||
#include <future>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
namespace sysy {
|
||||
|
||||
// 顶层入口
|
||||
@@ -12,29 +16,96 @@ std::string RISCv64CodeGen::code_gen() {
|
||||
return module_gen();
|
||||
}
|
||||
|
||||
// 模块级代码生成
|
||||
unsigned RISCv64CodeGen::getTypeSizeInBytes(Type* type) {
|
||||
if (!type) {
|
||||
assert(false && "Cannot get size of a null type.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (type->getKind()) {
|
||||
// 对于SysY语言,基本类型int和float都占用4字节
|
||||
case Type::kInt:
|
||||
case Type::kFloat:
|
||||
return 4;
|
||||
|
||||
// 指针类型在RISC-V 64位架构下占用8字节
|
||||
// 虽然SysY没有'int*'语法,但数组变量在IR层面本身就是指针类型
|
||||
case Type::kPointer:
|
||||
return 8;
|
||||
|
||||
// 数组类型的总大小 = 元素数量 * 单个元素的大小
|
||||
case Type::kArray: {
|
||||
auto arrayType = type->as<ArrayType>();
|
||||
// 递归调用以计算元素大小
|
||||
return arrayType->getNumElements() * getTypeSizeInBytes(arrayType->getElementType());
|
||||
}
|
||||
|
||||
// 其他类型,如Void, Label等不占用栈空间,或者不应该出现在这里
|
||||
default:
|
||||
// 如果遇到未处理的类型,触发断言,方便调试
|
||||
// assert(false && "Unsupported type for size calculation.");
|
||||
return 0; // 对于像Label或Void这样的类型,返回0是合理的
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void printInitializer(std::stringstream& ss, const ValueCounter& init_values) {
|
||||
for (size_t i = 0; i < init_values.getValues().size(); ++i) {
|
||||
auto val = init_values.getValues()[i];
|
||||
auto count = init_values.getNumbers()[i];
|
||||
if (auto constant = dynamic_cast<ConstantValue*>(val)) {
|
||||
for (unsigned j = 0; j < count; ++j) {
|
||||
if (constant->isInt()) {
|
||||
ss << " .word " << constant->getInt() << "\n";
|
||||
} else {
|
||||
float f = constant->getFloat();
|
||||
uint32_t float_bits = *(uint32_t*)&f;
|
||||
ss << " .word " << float_bits << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string RISCv64CodeGen::module_gen() {
|
||||
std::stringstream ss;
|
||||
|
||||
// --- [新逻辑] 步骤1:将全局变量分为.data和.bss两组 ---
|
||||
// --- 步骤1:将全局变量(GlobalValue)分为.data和.bss两组 ---
|
||||
std::vector<GlobalValue*> data_globals;
|
||||
std::vector<GlobalValue*> bss_globals;
|
||||
|
||||
for (const auto& global_ptr : module->getGlobals()) {
|
||||
GlobalValue* global = global_ptr.get();
|
||||
|
||||
// 使用更健壮的逻辑来判断是否为大型零初始化数组
|
||||
bool is_all_zeros = true;
|
||||
const auto& init_values = global->getInitValues();
|
||||
|
||||
// 判断是否为大型零初始化数组,以便放入.bss段
|
||||
bool is_large_zero_array = false;
|
||||
// 规则:初始化列表只有一项,且该项是值为0的整数,且数量大于一个阈值(例如16)
|
||||
if (init_values.getValues().size() == 1) {
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(init_values.getValues()[0])) {
|
||||
if (const_val->isInt() && const_val->getInt() == 0 && init_values.getNumbers()[0] > 16) {
|
||||
is_large_zero_array = true;
|
||||
// 检查初始化值是否全部为0
|
||||
if (init_values.getValues().empty()) {
|
||||
// 如果 ValueCounter 为空,GlobalValue 的构造函数会确保它是零初始化的
|
||||
is_all_zeros = true;
|
||||
} else {
|
||||
for (auto val : init_values.getValues()) {
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(val)) {
|
||||
if (!const_val->isZero()) {
|
||||
is_all_zeros = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// 如果初始值包含非常量(例如,另一个全局变量的地址),则不认为是纯零初始化
|
||||
is_all_zeros = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 使用 getTypeSizeInBytes 检查总大小是否超过阈值 (16个整数 = 64字节)
|
||||
Type* allocated_type = global->getType()->as<PointerType>()->getBaseType();
|
||||
unsigned total_size = getTypeSizeInBytes(allocated_type);
|
||||
|
||||
bool is_large_zero_array = is_all_zeros && (total_size > 64);
|
||||
|
||||
if (is_large_zero_array) {
|
||||
bss_globals.push_back(global);
|
||||
} else {
|
||||
@@ -42,91 +113,209 @@ std::string RISCv64CodeGen::module_gen() {
|
||||
}
|
||||
}
|
||||
|
||||
// --- [新逻辑] 步骤2:生成 .bss 段的代码 ---
|
||||
// --- 步骤2:生成 .bss 段的代码 ---
|
||||
if (!bss_globals.empty()) {
|
||||
ss << ".bss\n"; // 切换到 .bss 段
|
||||
ss << ".bss\n";
|
||||
for (GlobalValue* global : bss_globals) {
|
||||
// 获取数组总大小(元素个数 * 元素大小)
|
||||
// 在SysY中,我们假设元素都是4字节(int或float)
|
||||
unsigned count = global->getInitValues().getNumbers()[0];
|
||||
unsigned total_size = count * 4;
|
||||
Type* allocated_type = global->getType()->as<PointerType>()->getBaseType();
|
||||
unsigned total_size = getTypeSizeInBytes(allocated_type);
|
||||
|
||||
ss << " .align 3\n"; // 8字节对齐 (2^3)
|
||||
ss << " .align 3\n";
|
||||
ss << ".globl " << global->getName() << "\n";
|
||||
ss << ".type " << global->getName() << ", @object\n";
|
||||
ss << ".size " << global->getName() << ", " << total_size << "\n";
|
||||
ss << global->getName() << ":\n";
|
||||
// 使用 .space 指令来预留指定大小的零填充空间
|
||||
ss << " .space " << total_size << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// --- [旧逻辑保留] 步骤3:生成 .data 段的代码 ---
|
||||
if (!data_globals.empty()) {
|
||||
ss << ".data\n"; // 切换到 .data 段
|
||||
// --- 步骤3:生成 .data 段的代码 ---
|
||||
if (!data_globals.empty() || !module->getConsts().empty()) {
|
||||
ss << ".data\n";
|
||||
|
||||
// a. 处理普通的全局变量 (GlobalValue)
|
||||
for (GlobalValue* global : data_globals) {
|
||||
Type* allocated_type = global->getType()->as<PointerType>()->getBaseType();
|
||||
unsigned total_size = getTypeSizeInBytes(allocated_type);
|
||||
|
||||
ss << " .align 3\n";
|
||||
ss << ".globl " << global->getName() << "\n";
|
||||
ss << ".type " << global->getName() << ", @object\n";
|
||||
ss << ".size " << global->getName() << ", " << total_size << "\n";
|
||||
ss << global->getName() << ":\n";
|
||||
bool is_all_zeros = true;
|
||||
const auto& init_values = global->getInitValues();
|
||||
// 使用您原有的逻辑来处理显式初始化的值
|
||||
for (size_t i = 0; i < init_values.getValues().size(); ++i) {
|
||||
auto val = init_values.getValues()[i];
|
||||
auto count = init_values.getNumbers()[i];
|
||||
if (auto constant = dynamic_cast<ConstantValue*>(val)) {
|
||||
for (unsigned j = 0; j < count; ++j) {
|
||||
if (constant->isInt()) {
|
||||
ss << " .word " << constant->getInt() << "\n";
|
||||
} else {
|
||||
float f = constant->getFloat();
|
||||
uint32_t float_bits = *(uint32_t*)&f;
|
||||
ss << " .word " << float_bits << "\n";
|
||||
if (init_values.getValues().empty()) {
|
||||
is_all_zeros = true;
|
||||
} else {
|
||||
for (auto val : init_values.getValues()) {
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(val)) {
|
||||
if (!const_val->isZero()) {
|
||||
is_all_zeros = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
is_all_zeros = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_all_zeros) {
|
||||
ss << " .zero " << total_size << "\n";
|
||||
} else {
|
||||
// 对于有非零初始值的变量,保持原有的打印逻辑。
|
||||
printInitializer(ss, global->getInitValues());
|
||||
}
|
||||
}
|
||||
|
||||
// b. 处理全局常量 (ConstantVariable)
|
||||
for (const auto& const_ptr : module->getConsts()) {
|
||||
ConstantVariable* cnst = const_ptr.get();
|
||||
Type* allocated_type = cnst->getType()->as<PointerType>()->getBaseType();
|
||||
unsigned total_size = getTypeSizeInBytes(allocated_type);
|
||||
|
||||
ss << " .align 3\n";
|
||||
ss << ".globl " << cnst->getName() << "\n";
|
||||
ss << ".type " << cnst->getName() << ", @object\n";
|
||||
ss << ".size " << cnst->getName() << ", " << total_size << "\n";
|
||||
ss << cnst->getName() << ":\n";
|
||||
printInitializer(ss, cnst->getInitValues());
|
||||
}
|
||||
}
|
||||
|
||||
// --- 处理函数 (.text段) 的逻辑保持不变 ---
|
||||
// --- 步骤4:处理函数 (.text段) 的逻辑 ---
|
||||
if (!module->getFunctions().empty()) {
|
||||
ss << ".text\n";
|
||||
for (const auto& func_pair : module->getFunctions()) {
|
||||
if (func_pair.second.get()) {
|
||||
if (func_pair.second.get() && !func_pair.second->getBasicBlocks().empty()) {
|
||||
ss << function_gen(func_pair.second.get());
|
||||
if (DEBUG) std::cerr << "Function: " << func_pair.first << " generated.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// function_gen 现在是包含具体优化名称的、完整的处理流水线
|
||||
std::string RISCv64CodeGen::function_gen(Function* func) {
|
||||
// === 完整的后端处理流水线 ===
|
||||
|
||||
// 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers)
|
||||
RISCv64ISel isel;
|
||||
std::unique_ptr<MachineFunction> mfunc = isel.runOnFunction(func);
|
||||
|
||||
// 第一次调试打印输出
|
||||
std::stringstream ss1;
|
||||
RISCv64AsmPrinter printer1(mfunc.get());
|
||||
printer1.run(ss1, true);
|
||||
std::stringstream ss_after_isel;
|
||||
RISCv64AsmPrinter printer_isel(mfunc.get());
|
||||
printer_isel.run(ss_after_isel, true);
|
||||
|
||||
// 阶段 2: 指令调度 (Instruction Scheduling)
|
||||
PreRA_Scheduler scheduler;
|
||||
scheduler.runOnMachineFunction(mfunc.get());
|
||||
if (DEBUG) {
|
||||
std::cerr << "====== Intermediate Representation after Instruction Selection ======\n"
|
||||
<< ss_after_isel.str();
|
||||
}
|
||||
|
||||
// 阶段 2: 消除帧索引 (展开伪指令,计算局部变量偏移)
|
||||
// 这个Pass必须在寄存器分配之前运行
|
||||
EliminateFrameIndicesPass efi_pass;
|
||||
efi_pass.runOnMachineFunction(mfunc.get());
|
||||
|
||||
if (DEBUG) {
|
||||
std::cerr << "====== stack info after eliminate frame indices ======\n";
|
||||
mfunc->dumpStackFrameInfo(std::cerr);
|
||||
std::stringstream ss_after_eli;
|
||||
printer_isel.run(ss_after_eli, true);
|
||||
std::cerr << "====== LLIR after eliminate frame indices ======\n"
|
||||
<< ss_after_eli.str();
|
||||
}
|
||||
|
||||
// // 阶段 2: 除法强度削弱优化 (Division Strength Reduction)
|
||||
// DivStrengthReduction div_strength_reduction;
|
||||
// div_strength_reduction.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// // 阶段 2.1: 指令调度 (Instruction Scheduling)
|
||||
// PreRA_Scheduler scheduler;
|
||||
// scheduler.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 3: 物理寄存器分配 (Register Allocation)
|
||||
RISCv64RegAlloc reg_alloc(mfunc.get());
|
||||
reg_alloc.run();
|
||||
|
||||
// 首先尝试图着色分配器
|
||||
if (DEBUG) std::cerr << "Attempting Register Allocation with Graph Coloring...\n";
|
||||
if (!gc_failed) {
|
||||
RISCv64RegAlloc gc_alloc(mfunc.get());
|
||||
|
||||
bool success_gc = gc_alloc.run();
|
||||
|
||||
if (!success_gc) {
|
||||
gc_failed = 1; // 后续不再尝试图着色分配器
|
||||
std::cerr << "Warning: Graph coloring register allocation failed function '"
|
||||
<< func->getName()
|
||||
<< "'. Switching to Linear Scan allocator."
|
||||
<< std::endl;
|
||||
|
||||
RISCv64ISel isel_gc_fallback;
|
||||
mfunc = isel_gc_fallback.runOnFunction(func);
|
||||
EliminateFrameIndicesPass efi_pass_gc_fallback;
|
||||
efi_pass_gc_fallback.runOnMachineFunction(mfunc.get());
|
||||
RISCv64LinearScan ls_alloc(mfunc.get());
|
||||
bool success = ls_alloc.run();
|
||||
if (!success) {
|
||||
// 如果线性扫描最终失败,则调用基本块分配器作为终极后备
|
||||
std::cerr << "Info: Linear Scan failed. Switching to Basic Block Allocator as final fallback.\n";
|
||||
|
||||
// 注意:我们需要在一个“干净”的MachineFunction上运行。
|
||||
// 最安全的方式是重新运行指令选择。
|
||||
RISCv64ISel isel_fallback;
|
||||
mfunc = isel_fallback.runOnFunction(func);
|
||||
EliminateFrameIndicesPass efi_pass_fallback;
|
||||
efi_pass_fallback.runOnMachineFunction(mfunc.get());
|
||||
if (DEBUG) {
|
||||
std::cerr << "====== stack info after reg alloc ======\n";
|
||||
}
|
||||
RISCv64BasicBlockAlloc bb_alloc(mfunc.get());
|
||||
bb_alloc.run();
|
||||
}
|
||||
} else {
|
||||
// 图着色成功完成
|
||||
if (DEBUG) std::cerr << "Graph Coloring allocation completed successfully.\n";
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Info: Graph Coloring allocation failed in last function. Switching to Linear Scan allocator...\n";
|
||||
RISCv64LinearScan ls_alloc(mfunc.get());
|
||||
bool success = ls_alloc.run();
|
||||
if (!success) {
|
||||
// 如果线性扫描最终失败,则调用基本块分配器作为终极后备
|
||||
std::cerr << "Info: Linear Scan failed. Switching to Basic Block Allocator as final fallback.\n";
|
||||
|
||||
// 注意:我们需要在一个“干净”的MachineFunction上运行。
|
||||
// 最安全的方式是重新运行指令选择。
|
||||
RISCv64ISel isel_fallback;
|
||||
mfunc = isel_fallback.runOnFunction(func);
|
||||
EliminateFrameIndicesPass efi_pass_fallback;
|
||||
efi_pass_fallback.runOnMachineFunction(mfunc.get());
|
||||
if (DEBUG) {
|
||||
std::cerr << "====== stack info after reg alloc ======\n";
|
||||
}
|
||||
RISCv64BasicBlockAlloc bb_alloc(mfunc.get());
|
||||
bb_alloc.run();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (DEBUG) {
|
||||
std::cerr << "====== stack info after reg alloc ======\n";
|
||||
mfunc->dumpStackFrameInfo(std::cerr);
|
||||
}
|
||||
|
||||
// 阶段 3.1: 处理被调用者保存寄存器
|
||||
CalleeSavedHandler callee_handler;
|
||||
callee_handler.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 4: 窥孔优化 (Peephole Optimization)
|
||||
PeepholeOptimizer peephole;
|
||||
peephole.runOnMachineFunction(mfunc.get());
|
||||
if (DEBUG) {
|
||||
std::cerr << "====== stack info after callee handler ======\n";
|
||||
mfunc->dumpStackFrameInfo(std::cerr);
|
||||
}
|
||||
|
||||
// // 阶段 4: 窥孔优化 (Peephole Optimization)
|
||||
// PeepholeOptimizer peephole;
|
||||
// peephole.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 5: 局部指令调度 (Local Scheduling)
|
||||
PostRA_Scheduler local_scheduler;
|
||||
@@ -136,7 +325,7 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
||||
PrologueEpilogueInsertionPass pei_pass;
|
||||
pei_pass.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 3.3: 清理产生的大立即数
|
||||
// 阶段 3.3: 大立即数合法化
|
||||
LegalizeImmediatesPass legalizer;
|
||||
legalizer.runOnMachineFunction(mfunc.get());
|
||||
|
||||
@@ -144,7 +333,7 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
||||
std::stringstream ss;
|
||||
RISCv64AsmPrinter printer(mfunc.get());
|
||||
printer.run(ss);
|
||||
if (DEBUG) ss << "\n" << ss1.str(); // 将指令选择阶段的结果也包含在最终输出中
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
267
src/backend/RISCv64/RISCv64BasicBlockAlloc.cpp
Normal file
267
src/backend/RISCv64/RISCv64BasicBlockAlloc.cpp
Normal 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
|
||||
@@ -1,16 +1,33 @@
|
||||
#include "RISCv64ISel.h"
|
||||
#include "IR.h" // For GlobalValue
|
||||
#include <stdexcept>
|
||||
#include <set>
|
||||
#include <functional>
|
||||
#include <cmath> // For std::fabs
|
||||
#include <limits> // For std::numeric_limits
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <iostream>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// DAG节点定义 (内部实现)
|
||||
struct RISCv64ISel::DAGNode {
|
||||
enum NodeKind {ARGUMENT, CONSTANT, LOAD, STORE, BINARY, CALL, RETURN, BRANCH, ALLOCA_ADDR, UNARY, MEMSET, GET_ELEMENT_PTR};
|
||||
enum NodeKind {
|
||||
ARGUMENT,
|
||||
CONSTANT, // 整数或地址常量
|
||||
LOAD,
|
||||
STORE,
|
||||
BINARY, // 整数二元运算
|
||||
CALL,
|
||||
RETURN,
|
||||
BRANCH,
|
||||
ALLOCA_ADDR,
|
||||
UNARY, // 整数一元运算
|
||||
MEMSET,
|
||||
GET_ELEMENT_PTR,
|
||||
FP_CONSTANT, // 浮点常量
|
||||
FBINARY, // 浮点二元运算 (如 FADD, FSUB, FCMP)
|
||||
FUNARY, // 浮点一元运算 (如 FCVT, FNEG)
|
||||
};
|
||||
NodeKind kind;
|
||||
Value* value = nullptr;
|
||||
std::vector<DAGNode*> operands;
|
||||
@@ -29,11 +46,20 @@ unsigned RISCv64ISel::getVReg(Value* val) {
|
||||
if (vreg_counter == 0) {
|
||||
vreg_counter = 1; // vreg 0 保留
|
||||
}
|
||||
vreg_map[val] = vreg_counter++;
|
||||
unsigned new_vreg = vreg_counter++;
|
||||
vreg_map[val] = new_vreg;
|
||||
vreg_to_value_map[new_vreg] = val;
|
||||
vreg_type_map[new_vreg] = val->getType();
|
||||
}
|
||||
return vreg_map.at(val);
|
||||
}
|
||||
|
||||
unsigned RISCv64ISel::getNewVReg(Type* type) {
|
||||
unsigned new_vreg = vreg_counter++;
|
||||
vreg_type_map[new_vreg] = type; // 记录这个新vreg的类型
|
||||
return new_vreg;
|
||||
}
|
||||
|
||||
// 主入口函数
|
||||
std::unique_ptr<MachineFunction> RISCv64ISel::runOnFunction(Function* func) {
|
||||
F = func;
|
||||
@@ -127,17 +153,18 @@ void RISCv64ISel::selectBasicBlock(BasicBlock* bb) {
|
||||
|
||||
for (const auto& inst_ptr : bb->getInstructions()) {
|
||||
DAGNode* node_to_select = nullptr;
|
||||
if (value_to_node.count(inst_ptr.get())) {
|
||||
node_to_select = value_to_node.at(inst_ptr.get());
|
||||
auto it = value_to_node.find(inst_ptr.get());
|
||||
if (it != value_to_node.end()) {
|
||||
node_to_select = it->second;
|
||||
} else {
|
||||
for(const auto& node : dag) {
|
||||
if(node->value == inst_ptr.get()) {
|
||||
node_to_select = node.get();
|
||||
break;
|
||||
}
|
||||
for(const auto& node : dag) {
|
||||
if(node->value == inst_ptr.get()) {
|
||||
node_to_select = node.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(node_to_select) {
|
||||
}
|
||||
if(node_to_select) {
|
||||
select_recursive(node_to_select);
|
||||
}
|
||||
}
|
||||
@@ -154,25 +181,73 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
// 加载其值的责任,被转移给了使用它们的父节点(如STORE, BINARY等)。
|
||||
case DAGNode::ARGUMENT:
|
||||
case DAGNode::CONSTANT:
|
||||
case DAGNode::ALLOCA_ADDR:
|
||||
case DAGNode::ALLOCA_ADDR: {
|
||||
if (node->value) {
|
||||
// 确保它有一个关联的虚拟寄存器即可,不生成代码。
|
||||
getVReg(node->value);
|
||||
// GlobalValue objects (global variables) should not get virtual registers
|
||||
// since they represent memory addresses, not register-allocated values
|
||||
if (dynamic_cast<GlobalValue*>(node->value) == nullptr) {
|
||||
// 确保它有一个关联的虚拟寄存器即可,不生成代码。
|
||||
getVReg(node->value);
|
||||
}
|
||||
}
|
||||
if (auto const_val1 = dynamic_cast<ConstantValue*>(node->value)) {
|
||||
if (const_val1->getInt() == 128875) {
|
||||
foo3 = 1;
|
||||
std::cerr << "Found constant 128875 in selectNode!" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case DAGNode::FP_CONSTANT: {
|
||||
// RISC-V没有直接加载浮点立即数的指令
|
||||
// 标准做法是:1. 将浮点数的32位二进制表示加载到一个整数寄存器
|
||||
// 2. 使用 fmv.w.x 指令将位模式从整数寄存器移动到浮点寄存器
|
||||
auto const_val = dynamic_cast<ConstantValue*>(node->value);
|
||||
auto float_vreg = getVReg(const_val);
|
||||
auto temp_int_vreg = getNewVReg(Type::getIntType()); // 临时整数虚拟寄存器
|
||||
|
||||
float f_val = const_val->getFloat();
|
||||
// 使用 reinterpret_cast 获取浮点数的32位二进制表示
|
||||
uint32_t float_bits = *reinterpret_cast<uint32_t*>(&f_val);
|
||||
|
||||
// 1. li temp_int_vreg, float_bits
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
|
||||
li->addOperand(std::make_unique<ImmOperand>(float_bits));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
|
||||
// 2. fmv.w.x float_vreg, temp_int_vreg
|
||||
auto fmv = std::make_unique<MachineInstr>(RVOpcodes::FMV_W_X);
|
||||
fmv->addOperand(std::make_unique<RegOperand>(float_vreg));
|
||||
fmv->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
|
||||
CurMBB->addInstruction(std::move(fmv));
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::LOAD: {
|
||||
auto dest_vreg = getVReg(node->value);
|
||||
Value* ptr_val = node->operands[0]->value;
|
||||
|
||||
// --- 修改点 ---
|
||||
// 1. 获取加载结果的类型 (即这个LOAD指令自身的类型)
|
||||
Type* loaded_type = node->value->getType();
|
||||
|
||||
// 2. 根据类型选择正确的伪指令或真实指令操作码
|
||||
RVOpcodes frame_opcode = loaded_type->isPointer() ? RVOpcodes::FRAME_LOAD_D : RVOpcodes::FRAME_LOAD_W;
|
||||
RVOpcodes real_opcode = loaded_type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW;
|
||||
|
||||
RVOpcodes frame_opcode;
|
||||
RVOpcodes real_opcode;
|
||||
if (loaded_type->isPointer()) {
|
||||
frame_opcode = RVOpcodes::FRAME_LOAD_D;
|
||||
real_opcode = RVOpcodes::LD;
|
||||
} else if (loaded_type->isFloat()) {
|
||||
frame_opcode = RVOpcodes::FRAME_LOAD_F;
|
||||
real_opcode = RVOpcodes::FLW;
|
||||
} else { // 默认为整数
|
||||
frame_opcode = RVOpcodes::FRAME_LOAD_W;
|
||||
real_opcode = RVOpcodes::LW;
|
||||
}
|
||||
|
||||
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
|
||||
// 3. 创建使用新的、区分宽度的伪指令
|
||||
@@ -183,7 +258,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
|
||||
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_val)) {
|
||||
// 对于全局变量,先用 la 加载其地址
|
||||
auto addr_vreg = getNewVReg();
|
||||
auto addr_vreg = getNewVReg(Type::getPointerType(global->getType()));
|
||||
auto la = std::make_unique<MachineInstr>(RVOpcodes::LA);
|
||||
la->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||
la->addOperand(std::make_unique<LabelOperand>(global->getName()));
|
||||
@@ -220,20 +295,51 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
|
||||
// 如果要存储的值是一个常量,就在这里生成 `li` 指令加载它
|
||||
if (auto val_const = dynamic_cast<ConstantValue*>(val_to_store)) {
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(getVReg(val_const)));
|
||||
li->addOperand(std::make_unique<ImmOperand>(val_const->getInt()));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
// 区分整数常量和浮点常量
|
||||
if (val_const->isInt()) {
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(getVReg(val_const)));
|
||||
li->addOperand(std::make_unique<ImmOperand>(val_const->getInt()));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
} else if (val_const->isFloat()) {
|
||||
// 先将浮点数的位模式加载到整数vreg,再用fmv.w.x移到浮点vreg
|
||||
auto temp_int_vreg = getNewVReg(Type::getIntType());
|
||||
auto float_vreg = getVReg(val_const);
|
||||
|
||||
float f_val = val_const->getFloat();
|
||||
uint32_t float_bits = *reinterpret_cast<uint32_t*>(&f_val);
|
||||
|
||||
// 1. li temp_int_vreg, float_bits
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
|
||||
li->addOperand(std::make_unique<ImmOperand>(float_bits));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
|
||||
// 2. fmv.w.x float_vreg, temp_int_vreg
|
||||
auto fmv = std::make_unique<MachineInstr>(RVOpcodes::FMV_W_X);
|
||||
fmv->addOperand(std::make_unique<RegOperand>(float_vreg));
|
||||
fmv->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
|
||||
CurMBB->addInstruction(std::move(fmv));
|
||||
}
|
||||
}
|
||||
auto val_vreg = getVReg(val_to_store);
|
||||
|
||||
// --- 修改点 ---
|
||||
// 1. 获取被存储的值的类型
|
||||
Type* stored_type = val_to_store->getType();
|
||||
|
||||
// 2. 根据类型选择正确的伪指令或真实指令操作码
|
||||
RVOpcodes frame_opcode = stored_type->isPointer() ? RVOpcodes::FRAME_STORE_D : RVOpcodes::FRAME_STORE_W;
|
||||
RVOpcodes real_opcode = stored_type->isPointer() ? RVOpcodes::SD : RVOpcodes::SW;
|
||||
RVOpcodes frame_opcode;
|
||||
RVOpcodes real_opcode;
|
||||
if (stored_type->isPointer()) {
|
||||
frame_opcode = RVOpcodes::FRAME_STORE_D;
|
||||
real_opcode = RVOpcodes::SD;
|
||||
} else if (stored_type->isFloat()) {
|
||||
frame_opcode = RVOpcodes::FRAME_STORE_F;
|
||||
real_opcode = RVOpcodes::FSW;
|
||||
} else { // 默认为整数
|
||||
frame_opcode = RVOpcodes::FRAME_STORE_W;
|
||||
real_opcode = RVOpcodes::SW;
|
||||
}
|
||||
|
||||
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
|
||||
// 3. 创建使用新的、区分宽度的伪指令
|
||||
@@ -244,7 +350,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
|
||||
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_val)) {
|
||||
// 向全局变量存储
|
||||
auto addr_vreg = getNewVReg();
|
||||
auto addr_vreg = getNewVReg(Type::getIntType());
|
||||
auto la = std::make_unique<MachineInstr>(RVOpcodes::LA);
|
||||
la->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||
la->addOperand(std::make_unique<LabelOperand>(global->getName()));
|
||||
@@ -284,7 +390,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
Value* base = nullptr;
|
||||
Value* offset = nullptr;
|
||||
|
||||
// [修改] 扩展基地址的判断,使其可以识别 AllocaInst 或 GlobalValue
|
||||
// 扩展基地址的判断,使其可以识别 AllocaInst 或 GlobalValue
|
||||
if (dynamic_cast<AllocaInst*>(lhs) || dynamic_cast<GlobalValue*>(lhs)) {
|
||||
base = lhs;
|
||||
offset = rhs;
|
||||
@@ -303,8 +409,8 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
}
|
||||
|
||||
// 2. [修改] 根据基地址的类型,生成不同的指令来获取基地址
|
||||
auto base_addr_vreg = getNewVReg(); // 创建一个新的临时vreg来存放基地址
|
||||
// 2. 根据基地址的类型,生成不同的指令来获取基地址
|
||||
auto base_addr_vreg = getNewVReg(Type::getIntType()); // 创建一个新的临时vreg来存放基地址
|
||||
|
||||
// 情况一:基地址是局部栈变量
|
||||
if (auto alloca_base = dynamic_cast<AllocaInst*>(base)) {
|
||||
@@ -334,7 +440,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
}
|
||||
}
|
||||
|
||||
// [V2优点] 在BINARY节点内部按需加载常量操作数。
|
||||
// 在BINARY节点内部按需加载常量操作数。
|
||||
auto load_val_if_const = [&](Value* val) {
|
||||
if (auto c = dynamic_cast<ConstantValue*>(val)) {
|
||||
if (DEBUG) {
|
||||
@@ -365,7 +471,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
auto dest_vreg = getVReg(bin);
|
||||
auto lhs_vreg = getVReg(lhs);
|
||||
|
||||
// [V2优点] 融合 ADDIW 优化。
|
||||
// 融合 ADDIW 优化。
|
||||
if (rhs_is_imm_opt) {
|
||||
auto rhs_const = dynamic_cast<ConstantValue*>(rhs);
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::ADDIW);
|
||||
@@ -421,6 +527,15 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kSRA: {
|
||||
auto rhs_const = dynamic_cast<ConstantInteger*>(rhs);
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SRAIW);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<ImmOperand>(rhs_const->getInt()));
|
||||
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));
|
||||
@@ -497,6 +612,109 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::FBINARY: {
|
||||
auto bin = dynamic_cast<BinaryInst*>(node->value);
|
||||
auto dest_vreg = getVReg(bin);
|
||||
auto lhs_vreg = getVReg(bin->getLhs());
|
||||
auto rhs_vreg = getVReg(bin->getRhs());
|
||||
|
||||
switch (bin->getKind()) {
|
||||
case Instruction::kFAdd: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FADD_S);
|
||||
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 Instruction::kFSub: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FSUB_S);
|
||||
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 Instruction::kFMul: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FMUL_S);
|
||||
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 Instruction::kFDiv: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FDIV_S);
|
||||
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;
|
||||
}
|
||||
|
||||
// --- 浮点比较指令 ---
|
||||
// 注意:比较结果(0或1)写入的是一个通用整数寄存器(dest_vreg)
|
||||
case Instruction::kFCmpEQ: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FEQ_S);
|
||||
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 Instruction::kFCmpLT: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FLT_S);
|
||||
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 Instruction::kFCmpLE: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FLE_S);
|
||||
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 Instruction::kFCmpGT: { // a > b 等价于 b < a
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FLT_S);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg)); // 操作数交换
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kFCmpGE: { // a >= b 等价于 b <= a
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FLE_S);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg)); // 操作数交换
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kFCmpNE: { // a != b 等价于 !(a == b)
|
||||
// 1. 先用 feq.s 比较,结果存入 dest_vreg
|
||||
auto feq = std::make_unique<MachineInstr>(RVOpcodes::FEQ_S);
|
||||
feq->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
feq->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
feq->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(feq));
|
||||
// 2. 再用 seqz 对结果取反 (如果相等(1),则变0;如果不等(0),则变1)
|
||||
auto seqz = std::make_unique<MachineInstr>(RVOpcodes::SEQZ);
|
||||
seqz->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
seqz->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
CurMBB->addInstruction(std::move(seqz));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("Unsupported float binary instruction in ISel");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::UNARY: {
|
||||
auto unary = dynamic_cast<UnaryInst*>(node->value);
|
||||
auto dest_vreg = getVReg(unary);
|
||||
@@ -524,109 +742,263 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::FUNARY: {
|
||||
auto unary = dynamic_cast<UnaryInst*>(node->value);
|
||||
auto dest_vreg = getVReg(unary);
|
||||
auto src_vreg = getVReg(unary->getOperand());
|
||||
|
||||
switch (unary->getKind()) {
|
||||
case Instruction::kItoF: { // 整数 to 浮点
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FCVT_S_W);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg)); // 目标是浮点vreg
|
||||
instr->addOperand(std::make_unique<RegOperand>(src_vreg)); // 源是整数vreg
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
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. 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.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. 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));
|
||||
|
||||
break;
|
||||
}
|
||||
case Instruction::kFNeg: { // 浮点取负
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FNEG_S);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
// --- 处理位传送指令 ---
|
||||
case Instruction::kBitItoF: { // 整数位模式 -> 浮点寄存器
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FMV_W_X);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg)); // 目标是浮点vreg
|
||||
instr->addOperand(std::make_unique<RegOperand>(src_vreg)); // 源是整数vreg
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kBitFtoI: { // 浮点位模式 -> 整数寄存器
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FMV_X_W);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg)); // 目标是整数vreg
|
||||
instr->addOperand(std::make_unique<RegOperand>(src_vreg)); // 源是浮点vreg
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("Unsupported float unary instruction in ISel");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::CALL: {
|
||||
auto call = dynamic_cast<CallInst*>(node->value);
|
||||
// 处理函数参数,放入a0-a7物理寄存器
|
||||
size_t num_operands = node->operands.size();
|
||||
size_t reg_arg_count = std::min(num_operands, (size_t)8);
|
||||
for (size_t i = 0; i < reg_arg_count; ++i) {
|
||||
DAGNode* arg_node = node->operands[i];
|
||||
auto arg_preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + i);
|
||||
|
||||
if (arg_node->kind == DAGNode::CONSTANT) {
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(arg_node->value)) {
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(arg_preg));
|
||||
li->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
// --- 步骤 1: 分配寄存器参数和栈参数 ---
|
||||
// 根据RISC-V调用约定,前8个整数/指针参数通过a0-a7传递,
|
||||
// 前8个浮点参数通过fa0-fa7传递 (物理寄存器 f10-f17)。其余参数通过栈传递。
|
||||
|
||||
int int_reg_idx = 0; // a0-a7 的索引
|
||||
int fp_reg_idx = 0; // fa0-fa7 的索引
|
||||
|
||||
// 用于存储需要通过栈传递的参数
|
||||
std::vector<DAGNode*> stack_args;
|
||||
|
||||
for (size_t i = 0; i < num_operands; ++i) {
|
||||
DAGNode* arg_node = node->operands[i];
|
||||
Value* arg_val = arg_node->value;
|
||||
Type* arg_type = arg_val->getType();
|
||||
|
||||
// 判断参数是浮点类型还是整型/指针类型
|
||||
if (arg_type->isFloat()) {
|
||||
if (fp_reg_idx < 8) {
|
||||
// --- 处理浮点寄存器参数 (fa0-fa7, 对应物理寄存器 F10-F17) ---
|
||||
auto arg_preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + fp_reg_idx);
|
||||
fp_reg_idx++;
|
||||
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(arg_val)) {
|
||||
// 如果是浮点常量,需要先物化
|
||||
// 1. 获取其32位二进制表示
|
||||
float f_val = const_val->getFloat();
|
||||
uint32_t float_bits = *reinterpret_cast<uint32_t*>(&f_val);
|
||||
// 2. 将位模式加载到一个临时整数寄存器 (使用t0)
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(PhysicalReg::T0));
|
||||
li->addOperand(std::make_unique<ImmOperand>(float_bits));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
// 3. 使用fmv.w.x将位模式从整数寄存器移动到目标浮点参数寄存器
|
||||
auto fmv_wx = std::make_unique<MachineInstr>(RVOpcodes::FMV_W_X);
|
||||
fmv_wx->addOperand(std::make_unique<RegOperand>(arg_preg));
|
||||
fmv_wx->addOperand(std::make_unique<RegOperand>(PhysicalReg::T0));
|
||||
CurMBB->addInstruction(std::move(fmv_wx));
|
||||
} else {
|
||||
// 如果已经是虚拟寄存器,直接用 fmv.s 移动
|
||||
auto src_vreg = getVReg(arg_val);
|
||||
auto fmv_s = std::make_unique<MachineInstr>(RVOpcodes::FMV_S);
|
||||
fmv_s->addOperand(std::make_unique<RegOperand>(arg_preg));
|
||||
fmv_s->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
CurMBB->addInstruction(std::move(fmv_s));
|
||||
}
|
||||
} else {
|
||||
// 浮点寄存器已用完,放到栈上传递
|
||||
stack_args.push_back(arg_node);
|
||||
}
|
||||
} else { // 整数或指针参数
|
||||
if (int_reg_idx < 8) {
|
||||
// --- 处理整数/指针寄存器参数 (a0-a7) ---
|
||||
auto arg_preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_reg_idx);
|
||||
int_reg_idx++;
|
||||
|
||||
if (arg_node->kind == DAGNode::CONSTANT) {
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(arg_val)) {
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(arg_preg));
|
||||
li->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
}
|
||||
} else {
|
||||
auto src_vreg = getVReg(arg_val);
|
||||
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
mv->addOperand(std::make_unique<RegOperand>(arg_preg));
|
||||
mv->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
CurMBB->addInstruction(std::move(mv));
|
||||
}
|
||||
} else {
|
||||
// 整数寄存器已用完,放到栈上传递
|
||||
stack_args.push_back(arg_node);
|
||||
}
|
||||
} else {
|
||||
auto src_vreg = getVReg(arg_node->value);
|
||||
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
mv->addOperand(std::make_unique<RegOperand>(arg_preg));
|
||||
mv->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
CurMBB->addInstruction(std::move(mv));
|
||||
}
|
||||
}
|
||||
if (num_operands > 8) {
|
||||
size_t stack_arg_count = num_operands - 8;
|
||||
int stack_space = stack_arg_count * 8; // RV64中每个参数槽位8字节
|
||||
|
||||
// 2a. 在栈上分配空间
|
||||
auto alloc_instr = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
alloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
alloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
alloc_instr->addOperand(std::make_unique<ImmOperand>(-stack_space));
|
||||
CurMBB->addInstruction(std::move(alloc_instr));
|
||||
// --- 步骤 2: 处理所有栈参数 ---
|
||||
int stack_space = 0;
|
||||
if (!stack_args.empty()) {
|
||||
// 计算栈参数所需的总空间,RV64中每个槽位为8字节
|
||||
stack_space = stack_args.size() * 8;
|
||||
// 根据ABI,为call分配的栈空间需要16字节对齐
|
||||
if (stack_space % 16 != 0) {
|
||||
stack_space += 16 - (stack_space % 16);
|
||||
}
|
||||
|
||||
// 在栈上分配空间
|
||||
if (stack_space > 0) {
|
||||
auto alloc_instr = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
alloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
alloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
alloc_instr->addOperand(std::make_unique<ImmOperand>(-stack_space));
|
||||
CurMBB->addInstruction(std::move(alloc_instr));
|
||||
}
|
||||
|
||||
// 将每个参数存储到栈上对应的位置
|
||||
for (size_t i = 0; i < stack_args.size(); ++i) {
|
||||
DAGNode* arg_node = stack_args[i];
|
||||
Value* arg_val = arg_node->value;
|
||||
Type* arg_type = arg_val->getType();
|
||||
int offset = i * 8;
|
||||
|
||||
// 2b. 存储每个栈参数
|
||||
for (size_t i = 8; i < num_operands; ++i) {
|
||||
DAGNode* arg_node = node->operands[i];
|
||||
unsigned src_vreg;
|
||||
|
||||
// 准备源寄存器
|
||||
if (arg_node->kind == DAGNode::CONSTANT) {
|
||||
// 如果是常量,先加载到临时寄存器
|
||||
src_vreg = getNewVReg();
|
||||
auto const_val = dynamic_cast<ConstantValue*>(arg_node->value);
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
li->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
// 如果是常量,先加载到临时vreg
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(arg_val)) {
|
||||
src_vreg = getNewVReg(arg_type);
|
||||
if(arg_type->isFloat()) {
|
||||
auto temp_int_vreg = getNewVReg(Type::getIntType());
|
||||
float f_val = const_val->getFloat();
|
||||
uint32_t float_bits = *reinterpret_cast<uint32_t*>(&f_val);
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
|
||||
li->addOperand(std::make_unique<ImmOperand>(float_bits));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
auto fmv_wx = std::make_unique<MachineInstr>(RVOpcodes::FMV_W_X);
|
||||
fmv_wx->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
fmv_wx->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
|
||||
CurMBB->addInstruction(std::move(fmv_wx));
|
||||
} else {
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
li->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
}
|
||||
} else {
|
||||
src_vreg = getVReg(arg_node->value);
|
||||
src_vreg = getVReg(arg_val);
|
||||
}
|
||||
|
||||
// 计算在栈上的偏移量
|
||||
int offset = (i - 8) * 8;
|
||||
|
||||
// 生成 sd 指令
|
||||
auto sd_instr = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
||||
sd_instr->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
sd_instr->addOperand(std::make_unique<MemOperand>(
|
||||
// 根据类型选择 fsw (浮点) 或 sd (整型/指针) 存储指令
|
||||
std::unique_ptr<MachineInstr> store_instr;
|
||||
if (arg_type->isFloat()) {
|
||||
store_instr = std::make_unique<MachineInstr>(RVOpcodes::FSW);
|
||||
} else {
|
||||
store_instr = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
||||
}
|
||||
store_instr->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
store_instr->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::SP),
|
||||
std::make_unique<ImmOperand>(offset)
|
||||
));
|
||||
CurMBB->addInstruction(std::move(sd_instr));
|
||||
CurMBB->addInstruction(std::move(store_instr));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- 步骤 3: 生成CALL指令 ---
|
||||
auto call_instr = std::make_unique<MachineInstr>(RVOpcodes::CALL);
|
||||
// [协议] 如果函数有返回值,将它的目标虚拟寄存器作为第一个操作数
|
||||
// 如果函数有返回值,将它的目标虚拟寄存器作为第一个操作数
|
||||
if (!call->getType()->isVoid()) {
|
||||
unsigned dest_vreg = getVReg(call);
|
||||
call_instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
}
|
||||
|
||||
// 将函数名标签作为后续操作数
|
||||
call_instr->addOperand(std::make_unique<LabelOperand>(call->getCallee()->getName()));
|
||||
|
||||
// 将所有参数的虚拟寄存器也作为后续操作数,供getInstrUseDef分析
|
||||
for (size_t i = 0; i < num_operands; ++i) {
|
||||
if (node->operands[i]->kind != DAGNode::CONSTANT) { // 常量参数已直接加载,无需作为use
|
||||
if (node->operands[i]->kind != DAGNode::CONSTANT && node->operands[i]->kind != DAGNode::FP_CONSTANT) {
|
||||
call_instr->addOperand(std::make_unique<RegOperand>(getVReg(node->operands[i]->value)));
|
||||
}
|
||||
}
|
||||
|
||||
CurMBB->addInstruction(std::move(call_instr));
|
||||
|
||||
if (num_operands > 8) {
|
||||
size_t stack_arg_count = num_operands - 8;
|
||||
int stack_space = stack_arg_count * 8;
|
||||
|
||||
// --- 步骤 4: 处理返回值 ---
|
||||
if (!call->getType()->isVoid()) {
|
||||
unsigned dest_vreg = getVReg(call);
|
||||
if (call->getType()->isFloat()) {
|
||||
// 浮点返回值在 fa0 (物理寄存器 F10)
|
||||
auto fmv_s = std::make_unique<MachineInstr>(RVOpcodes::FMV_S);
|
||||
fmv_s->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
fmv_s->addOperand(std::make_unique<RegOperand>(PhysicalReg::F10)); // fa0
|
||||
CurMBB->addInstruction(std::move(fmv_s));
|
||||
} else {
|
||||
// 整数/指针返回值在 a0
|
||||
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
mv->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
mv->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
|
||||
CurMBB->addInstruction(std::move(mv));
|
||||
}
|
||||
}
|
||||
|
||||
// --- 步骤 5: 回收为栈参数分配的空间 ---
|
||||
if (stack_space > 0) {
|
||||
auto dealloc_instr = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
dealloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
dealloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
dealloc_instr->addOperand(std::make_unique<ImmOperand>(stack_space));
|
||||
CurMBB->addInstruction(std::move(dealloc_instr));
|
||||
}
|
||||
// 处理返回值,从a0移动到目标虚拟寄存器
|
||||
// if (!call->getType()->isVoid()) {
|
||||
// auto mv_instr = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
// mv_instr->addOperand(std::make_unique<RegOperand>(getVReg(call)));
|
||||
// mv_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
|
||||
// CurMBB->addInstruction(std::move(mv_instr));
|
||||
// }
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -634,20 +1006,50 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
auto ret_inst_ir = dynamic_cast<ReturnInst*>(node->value);
|
||||
if (ret_inst_ir && ret_inst_ir->hasReturnValue()) {
|
||||
Value* ret_val = ret_inst_ir->getReturnValue();
|
||||
// [V2优点] 在RETURN节点内加载常量返回值
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(ret_val)) {
|
||||
auto li_instr = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
|
||||
li_instr->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
|
||||
CurMBB->addInstruction(std::move(li_instr));
|
||||
Type* ret_type = ret_val->getType();
|
||||
|
||||
if (ret_type->isFloat()) {
|
||||
// --- 处理浮点返回值 ---
|
||||
// 返回值需要被放入 fa0 (物理寄存器 F10)
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(ret_val)) {
|
||||
// 如果是浮点常量,需要先物化到fa0
|
||||
float f_val = const_val->getFloat();
|
||||
uint32_t float_bits = *reinterpret_cast<uint32_t*>(&f_val);
|
||||
// 1. 加载位模式到临时整数寄存器 (t0)
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(PhysicalReg::T0));
|
||||
li->addOperand(std::make_unique<ImmOperand>(float_bits));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
// 2. 将位模式从 t0 移动到 fa0
|
||||
auto fmv_wx = std::make_unique<MachineInstr>(RVOpcodes::FMV_W_X);
|
||||
fmv_wx->addOperand(std::make_unique<RegOperand>(PhysicalReg::F10)); // fa0
|
||||
fmv_wx->addOperand(std::make_unique<RegOperand>(PhysicalReg::T0));
|
||||
CurMBB->addInstruction(std::move(fmv_wx));
|
||||
} else {
|
||||
// 如果是vreg,直接用 fmv.s 移动到 fa0
|
||||
auto fmv_s = std::make_unique<MachineInstr>(RVOpcodes::FMV_S);
|
||||
fmv_s->addOperand(std::make_unique<RegOperand>(PhysicalReg::F10)); // fa0
|
||||
fmv_s->addOperand(std::make_unique<RegOperand>(getVReg(ret_val)));
|
||||
CurMBB->addInstruction(std::move(fmv_s));
|
||||
}
|
||||
} else {
|
||||
auto mv_instr = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
mv_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
|
||||
mv_instr->addOperand(std::make_unique<RegOperand>(getVReg(ret_val)));
|
||||
CurMBB->addInstruction(std::move(mv_instr));
|
||||
// --- 处理整数/指针返回值 ---
|
||||
// 返回值需要被放入 a0
|
||||
// 在RETURN节点内加载常量返回值
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(ret_val)) {
|
||||
auto li_instr = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
|
||||
li_instr->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
|
||||
CurMBB->addInstruction(std::move(li_instr));
|
||||
} else {
|
||||
auto mv_instr = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
mv_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
|
||||
mv_instr->addOperand(std::make_unique<RegOperand>(getVReg(ret_val)));
|
||||
CurMBB->addInstruction(std::move(mv_instr));
|
||||
}
|
||||
}
|
||||
}
|
||||
// [V1设计保留] 函数尾声(epilogue)不由RETURN节点生成,
|
||||
// 函数尾声(epilogue)不由RETURN节点生成,
|
||||
// 而是由后续的AsmPrinter或其它Pass统一处理,这是一种常见且有效的模块化设计。
|
||||
auto ret_mi = std::make_unique<MachineInstr>(RVOpcodes::RET);
|
||||
CurMBB->addInstruction(std::move(ret_mi));
|
||||
@@ -661,7 +1063,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
auto then_bb_name = cond_br->getThenBlock()->getName();
|
||||
auto else_bb_name = cond_br->getElseBlock()->getName();
|
||||
|
||||
// [优化] 检查分支条件是否为编译期常量
|
||||
// 检查分支条件是否为编译期常量
|
||||
if (auto const_cond = dynamic_cast<ConstantValue*>(condition)) {
|
||||
// 如果条件是常量,直接生成一个无条件跳转J,而不是BNE
|
||||
if (const_cond->getInt() != 0) { // 条件为 true
|
||||
@@ -676,7 +1078,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
}
|
||||
// 如果条件不是常量,则执行标准流程
|
||||
else {
|
||||
// [修复] 为条件变量生成加载指令(如果它是常量的话,尽管上面已经处理了)
|
||||
// 为条件变量生成加载指令(如果它是常量的话,尽管上面已经处理了)
|
||||
// 这一步是为了逻辑完整,以防有其他类型的常量没有被捕获
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(condition)) {
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
@@ -710,7 +1112,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
}
|
||||
|
||||
case DAGNode::MEMSET: {
|
||||
// [V1设计保留] Memset的核心展开逻辑在虚拟寄存器层面是正确的,无需修改。
|
||||
// Memset的核心展开逻辑在虚拟寄存器层面是正确的,无需修改。
|
||||
// 之前的bug是由于其输入(地址、值、大小)的虚拟寄存器未被正确初始化。
|
||||
// 在修复了CONSTANT/ALLOCA_ADDR的加载问题后,此处的逻辑现在可以正常工作。
|
||||
|
||||
@@ -756,10 +1158,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) {
|
||||
@@ -850,7 +1253,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);
|
||||
@@ -862,6 +1265,11 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
la_instr->addOperand(std::make_unique<RegOperand>(current_addr_vreg));
|
||||
la_instr->addOperand(std::make_unique<LabelOperand>(global_base->getName()));
|
||||
CurMBB->addInstruction(std::move(la_instr));
|
||||
} else if (auto const_global_base = dynamic_cast<ConstantVariable*>(base_ptr_node->value)) {
|
||||
auto la_instr = std::make_unique<MachineInstr>(RVOpcodes::LA);
|
||||
la_instr->addOperand(std::make_unique<RegOperand>(current_addr_vreg));
|
||||
la_instr->addOperand(std::make_unique<LabelOperand>(const_global_base->getName()));
|
||||
CurMBB->addInstruction(std::move(la_instr));
|
||||
} else {
|
||||
auto base_vreg = getVReg(base_ptr_node->value);
|
||||
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
@@ -870,7 +1278,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
CurMBB->addInstruction(std::move(mv));
|
||||
}
|
||||
|
||||
// --- Step 2: [最终权威版] 遵循LLVM GEP语义迭代计算地址 ---
|
||||
// --- Step 2: 遵循LLVM GEP语义迭代计算地址 ---
|
||||
|
||||
// 初始被索引的类型,是基指针指向的那个类型 (例如, [2 x i32])
|
||||
Type* current_type = gep->getBasePointer()->getType()->as<PointerType>()->getBaseType();
|
||||
@@ -887,15 +1295,20 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
// 如果步长为0(例如对一个void类型或空结构体索引),则不产生任何偏移
|
||||
if (stride != 0) {
|
||||
// --- 为当前索引和步长生成偏移计算指令 ---
|
||||
auto offset_vreg = getNewVReg();
|
||||
auto index_vreg = getVReg(indexValue);
|
||||
|
||||
// 如果索引是常量,先用 LI 指令加载到虚拟寄存器
|
||||
auto offset_vreg = getNewVReg(Type::getIntType());
|
||||
|
||||
// 处理索引 - 区分常量与动态值
|
||||
unsigned index_vreg;
|
||||
if (auto const_index = dynamic_cast<ConstantValue*>(indexValue)) {
|
||||
// 对于常量索引,直接创建新的虚拟寄存器
|
||||
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()));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
} else {
|
||||
// 对于动态索引,使用已存在的虚拟寄存器
|
||||
index_vreg = getVReg(indexValue);
|
||||
}
|
||||
|
||||
// 优化:如果步长是1,可以直接移动(MV)作为偏移量,无需乘法
|
||||
@@ -906,7 +1319,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));
|
||||
@@ -979,15 +1392,17 @@ RISCv64ISel::DAGNode* RISCv64ISel::get_operand_node(
|
||||
|
||||
// 规则1:如果这个Value已经有对应的节点,直接返回
|
||||
if (value_to_node.count(val_ir)) {
|
||||
return value_to_node.at(val_ir);
|
||||
return value_to_node[val_ir];
|
||||
}
|
||||
|
||||
// 规则2:识别各种类型的叶子节点,并创建相应的DAG节点
|
||||
if (dynamic_cast<ConstantValue*>(val_ir)) {
|
||||
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(val_ir)) {
|
||||
if (const_val->isInt()) {
|
||||
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
|
||||
} else {
|
||||
// 为浮点常量创建新的FP_CONSTANT节点
|
||||
return create_node(DAGNode::FP_CONSTANT, val_ir, value_to_node, nodes_storage);
|
||||
}
|
||||
}
|
||||
if (dynamic_cast<GlobalValue*>(val_ir)) {
|
||||
// 全局变量/常量数组被视为一个常量地址
|
||||
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
|
||||
}
|
||||
if (dynamic_cast<AllocaInst*>(val_ir)) {
|
||||
@@ -1051,7 +1466,7 @@ std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicB
|
||||
|
||||
// 依次添加所有索引作为后续的操作数
|
||||
for (auto index : gep->getIndices()) {
|
||||
// [修复] 从 Use 对象中获取真正的 Value*
|
||||
// 从 Use 对象中获取真正的 Value*
|
||||
gep_node->operands.push_back(get_operand_node(index->getValue(), value_to_node, nodes_storage));
|
||||
}
|
||||
} else if (auto load = dynamic_cast<LoadInst*>(inst)) {
|
||||
@@ -1059,6 +1474,17 @@ std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicB
|
||||
load_node->operands.push_back(get_operand_node(load->getPointer(), value_to_node, nodes_storage));
|
||||
} else if (auto bin = dynamic_cast<BinaryInst*>(inst)) {
|
||||
if(value_to_node.count(bin)) continue;
|
||||
if (bin->getKind() == Instruction::kFSub) {
|
||||
if (auto const_lhs = dynamic_cast<ConstantValue*>(bin->getLhs())) {
|
||||
// 使用isZero()来判断浮点数0.0,比直接比较更健壮
|
||||
if (const_lhs->isZero()) {
|
||||
// 这是一个浮点取负操作,创建 FUNARY 节点
|
||||
auto funary_node = create_node(DAGNode::FUNARY, bin, value_to_node, nodes_storage);
|
||||
funary_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
|
||||
continue; // 处理完毕,跳到下一条指令
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bin->getKind() == BinaryInst::kSub) {
|
||||
if (auto const_lhs = dynamic_cast<ConstantValue*>(bin->getLhs())) {
|
||||
if (const_lhs->getInt() == 0) {
|
||||
@@ -1068,13 +1494,24 @@ std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicB
|
||||
}
|
||||
}
|
||||
}
|
||||
auto bin_node = create_node(DAGNode::BINARY, bin, value_to_node, nodes_storage);
|
||||
bin_node->operands.push_back(get_operand_node(bin->getLhs(), value_to_node, nodes_storage));
|
||||
bin_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
|
||||
if (bin->isFPBinary()) { // 假设浮点指令枚举值更大
|
||||
auto fbin_node = create_node(DAGNode::FBINARY, bin, value_to_node, nodes_storage);
|
||||
fbin_node->operands.push_back(get_operand_node(bin->getLhs(), value_to_node, nodes_storage));
|
||||
fbin_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
|
||||
} else {
|
||||
auto bin_node = create_node(DAGNode::BINARY, bin, value_to_node, nodes_storage);
|
||||
bin_node->operands.push_back(get_operand_node(bin->getLhs(), value_to_node, nodes_storage));
|
||||
bin_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
|
||||
}
|
||||
} else if (auto un = dynamic_cast<UnaryInst*>(inst)) {
|
||||
if(value_to_node.count(un)) continue;
|
||||
auto unary_node = create_node(DAGNode::UNARY, un, value_to_node, nodes_storage);
|
||||
unary_node->operands.push_back(get_operand_node(un->getOperand(), value_to_node, nodes_storage));
|
||||
if (un->getKind() >= Instruction::kFNeg) {
|
||||
auto funary_node = create_node(DAGNode::FUNARY, un, value_to_node, nodes_storage);
|
||||
funary_node->operands.push_back(get_operand_node(un->getOperand(), value_to_node, nodes_storage));
|
||||
} else {
|
||||
auto unary_node = create_node(DAGNode::UNARY, un, value_to_node, nodes_storage);
|
||||
unary_node->operands.push_back(get_operand_node(un->getOperand(), value_to_node, nodes_storage));
|
||||
}
|
||||
} else if (auto call = dynamic_cast<CallInst*>(inst)) {
|
||||
if(value_to_node.count(call)) continue;
|
||||
auto call_node = create_node(DAGNode::CALL, call, value_to_node, nodes_storage);
|
||||
@@ -1133,7 +1570,7 @@ unsigned RISCv64ISel::getTypeSizeInBytes(Type* type) {
|
||||
}
|
||||
}
|
||||
|
||||
// [新] 打印DAG图以供调试的辅助函数
|
||||
// 打印DAG图以供调试的辅助函数
|
||||
void RISCv64ISel::print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, const std::string& bb_name) {
|
||||
// 检查是否有DEBUG宏或者全局变量,避免在非调试模式下打印
|
||||
// if (!DEBUG) return;
|
||||
@@ -1229,4 +1666,8 @@ void RISCv64ISel::print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, co
|
||||
std::cerr << "======================================\n\n";
|
||||
}
|
||||
|
||||
unsigned int RISCv64ISel::getVRegCounter() const {
|
||||
return vreg_counter;
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@@ -1,6 +1,195 @@
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "RISCv64Info.h"
|
||||
#include <vector>
|
||||
#include <iostream> // 用于 std::ostream 和 std::cerr
|
||||
#include <string> // 用于 std::string
|
||||
|
||||
namespace sysy {
|
||||
|
||||
}
|
||||
// 辅助函数:将 PhysicalReg 枚举转换为可读的字符串
|
||||
std::string regToString(PhysicalReg reg) {
|
||||
switch (reg) {
|
||||
case PhysicalReg::ZERO: return "x0"; case PhysicalReg::RA: return "ra";
|
||||
case PhysicalReg::SP: return "sp"; case PhysicalReg::GP: return "gp";
|
||||
case PhysicalReg::TP: return "tp"; case PhysicalReg::T0: return "t0";
|
||||
case PhysicalReg::T1: return "t1"; case PhysicalReg::T2: return "t2";
|
||||
case PhysicalReg::S0: return "s0"; case PhysicalReg::S1: return "s1";
|
||||
case PhysicalReg::A0: return "a0"; case PhysicalReg::A1: return "a1";
|
||||
case PhysicalReg::A2: return "a2"; case PhysicalReg::A3: return "a3";
|
||||
case PhysicalReg::A4: return "a4"; case PhysicalReg::A5: return "a5";
|
||||
case PhysicalReg::A6: return "a6"; case PhysicalReg::A7: return "a7";
|
||||
case PhysicalReg::S2: return "s2"; case PhysicalReg::S3: return "s3";
|
||||
case PhysicalReg::S4: return "s4"; case PhysicalReg::S5: return "s5";
|
||||
case PhysicalReg::S6: return "s6"; case PhysicalReg::S7: return "s7";
|
||||
case PhysicalReg::S8: return "s8"; case PhysicalReg::S9: return "s9";
|
||||
case PhysicalReg::S10: return "s10"; case PhysicalReg::S11: return "s11";
|
||||
case PhysicalReg::T3: return "t3"; case PhysicalReg::T4: return "t4";
|
||||
case PhysicalReg::T5: return "t5"; case PhysicalReg::T6: return "t6";
|
||||
case PhysicalReg::F0: return "f0"; case PhysicalReg::F1: return "f1";
|
||||
case PhysicalReg::F2: return "f2"; case PhysicalReg::F3: return "f3";
|
||||
case PhysicalReg::F4: return "f4"; case PhysicalReg::F5: return "f5";
|
||||
case PhysicalReg::F6: return "f6"; case PhysicalReg::F7: return "f7";
|
||||
case PhysicalReg::F8: return "f8"; case PhysicalReg::F9: return "f9";
|
||||
case PhysicalReg::F10: return "f10"; case PhysicalReg::F11: return "f11";
|
||||
case PhysicalReg::F12: return "f12"; case PhysicalReg::F13: return "f13";
|
||||
case PhysicalReg::F14: return "f14"; case PhysicalReg::F15: return "f15";
|
||||
case PhysicalReg::F16: return "f16"; case PhysicalReg::F17: return "f17";
|
||||
case PhysicalReg::F18: return "f18"; case PhysicalReg::F19: return "f19";
|
||||
case PhysicalReg::F20: return "f20"; case PhysicalReg::F21: return "f21";
|
||||
case PhysicalReg::F22: return "f22"; case PhysicalReg::F23: return "f23";
|
||||
case PhysicalReg::F24: return "f24"; case PhysicalReg::F25: return "f25";
|
||||
case PhysicalReg::F26: return "f26"; case PhysicalReg::F27: return "f27";
|
||||
case PhysicalReg::F28: return "f28"; case PhysicalReg::F29: return "f29";
|
||||
case PhysicalReg::F30: return "f30"; case PhysicalReg::F31: return "f31";
|
||||
default: return "UNKNOWN_REG";
|
||||
}
|
||||
}
|
||||
|
||||
// 打印栈帧信息的完整实现
|
||||
void MachineFunction::dumpStackFrameInfo(std::ostream& os) const {
|
||||
const StackFrameInfo& info = frame_info;
|
||||
|
||||
os << "--- Stack Frame Info for function '" << getName() << "' ---\n";
|
||||
|
||||
// 打印尺寸信息
|
||||
os << " Sizes:\n";
|
||||
os << " Total Size: " << info.total_size << " bytes\n";
|
||||
os << " Locals Size: " << info.locals_size << " bytes\n";
|
||||
os << " Spill Size: " << info.spill_size << " bytes\n";
|
||||
os << " Callee-Saved Size: " << info.callee_saved_size << " bytes\n";
|
||||
os << "\n";
|
||||
|
||||
// 打印 Alloca 变量的偏移量
|
||||
os << " Alloca Offsets (vreg -> offset from FP):\n";
|
||||
if (info.alloca_offsets.empty()) {
|
||||
os << " (None)\n";
|
||||
} else {
|
||||
for (const auto& pair : info.alloca_offsets) {
|
||||
os << " %vreg" << pair.first << " -> " << pair.second << "\n";
|
||||
}
|
||||
}
|
||||
os << "\n";
|
||||
|
||||
// 打印溢出变量的偏移量
|
||||
os << " Spill Offsets (vreg -> offset from FP):\n";
|
||||
if (info.spill_offsets.empty()) {
|
||||
os << " (None)\n";
|
||||
} else {
|
||||
for (const auto& pair : info.spill_offsets) {
|
||||
os << " %vreg" << pair.first << " -> " << pair.second << "\n";
|
||||
}
|
||||
}
|
||||
os << "\n";
|
||||
|
||||
// 打印使用的被调用者保存寄存器
|
||||
os << " Used Callee-Saved Registers:\n";
|
||||
if (info.used_callee_saved_regs.empty()) {
|
||||
os << " (None)\n";
|
||||
} else {
|
||||
os << " { ";
|
||||
for (const auto& reg : info.used_callee_saved_regs) {
|
||||
os << regToString(reg) << " ";
|
||||
}
|
||||
os << "}\n";
|
||||
}
|
||||
os << "\n";
|
||||
|
||||
// 打印需要保存/恢复的被调用者保存寄存器 (有序)
|
||||
os << " Callee-Saved Registers to Store/Restore:\n";
|
||||
if (info.callee_saved_regs_to_store.empty()) {
|
||||
os << " (None)\n";
|
||||
} else {
|
||||
os << " [ ";
|
||||
for (const auto& reg : info.callee_saved_regs_to_store) {
|
||||
os << regToString(reg) << " ";
|
||||
}
|
||||
os << "]\n";
|
||||
}
|
||||
os << "\n";
|
||||
|
||||
// 打印最终的寄存器分配结果
|
||||
os << " Final Register Allocation Map (vreg -> preg):\n";
|
||||
if (info.vreg_to_preg_map.empty()) {
|
||||
os << " (None)\n";
|
||||
} else {
|
||||
for (const auto& pair : info.vreg_to_preg_map) {
|
||||
os << " %vreg" << pair.first << " -> " << regToString(pair.second) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
694
src/backend/RISCv64/RISCv64LinearScan.cpp
Normal file
694
src/backend/RISCv64/RISCv64LinearScan.cpp
Normal 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
|
||||
File diff suppressed because it is too large
Load Diff
20
src/include/backend/RISCv64/Handler/EliminateFrameIndices.h
Normal file
20
src/include/backend/RISCv64/Handler/EliminateFrameIndices.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef ELIMINATE_FRAME_INDICES_H
|
||||
#define ELIMINATE_FRAME_INDICES_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class EliminateFrameIndicesPass {
|
||||
public:
|
||||
// Pass 的主入口函数
|
||||
void runOnMachineFunction(MachineFunction* mfunc);
|
||||
|
||||
private:
|
||||
// 帮助计算类型大小的辅助函数,从原RegAlloc中移出
|
||||
unsigned getTypeSizeInBytes(Type* type);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // ELIMINATE_FRAME_INDICES_H
|
||||
30
src/include/backend/RISCv64/Optimize/DivStrengthReduction.h
Normal file
30
src/include/backend/RISCv64/Optimize/DivStrengthReduction.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef RISCV64_DIV_STRENGTH_REDUCTION_H
|
||||
#define RISCV64_DIV_STRENGTH_REDUCTION_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "Pass.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
/**
|
||||
* @class DivStrengthReduction
|
||||
* @brief 除法强度削弱优化器
|
||||
* * 将除法运算转换为乘法运算,使用magic number算法
|
||||
* 适用于除数为常数的情况,可以显著提高性能
|
||||
*/
|
||||
class DivStrengthReduction : public Pass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
DivStrengthReduction() : Pass("div-strength-reduction", Granularity::Function, PassKind::Optimization) {}
|
||||
|
||||
void *getPassID() const override { return &ID; }
|
||||
|
||||
bool runOnFunction(Function *F, AnalysisManager& AM) override;
|
||||
|
||||
void runOnMachineFunction(MachineFunction* mfunc);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // RISCV64_DIV_STRENGTH_REDUCTION_H
|
||||
@@ -12,6 +12,26 @@ namespace sysy {
|
||||
* * 主要目标是优化寄存器分配器插入的spill/fill代码(lw/sw),
|
||||
* 尝试将加载指令提前,以隐藏其访存延迟。
|
||||
*/
|
||||
struct MemoryAccess {
|
||||
PhysicalReg base_reg;
|
||||
int64_t offset;
|
||||
bool valid;
|
||||
|
||||
MemoryAccess() : valid(false) {}
|
||||
MemoryAccess(PhysicalReg base, int64_t off) : base_reg(base), offset(off), valid(true) {}
|
||||
};
|
||||
|
||||
struct InstrRegInfo {
|
||||
std::unordered_set<PhysicalReg> defined_regs;
|
||||
std::unordered_set<PhysicalReg> used_regs;
|
||||
bool is_load;
|
||||
bool is_store;
|
||||
bool is_control_flow;
|
||||
MemoryAccess mem_access;
|
||||
|
||||
InstrRegInfo() : is_load(false), is_store(false), is_control_flow(false) {}
|
||||
};
|
||||
|
||||
class PostRA_Scheduler : public Pass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
@@ -18,12 +18,14 @@ public:
|
||||
void printInstruction(MachineInstr* instr, bool debug = false);
|
||||
// 辅助函数
|
||||
void setStream(std::ostream& os) { OS = &os; }
|
||||
// 辅助函数
|
||||
std::string regToString(PhysicalReg reg);
|
||||
std::string formatInstr(const MachineInstr *instr);
|
||||
|
||||
private:
|
||||
// 打印各个部分
|
||||
void printBasicBlock(MachineBasicBlock* mbb, bool debug = false);
|
||||
|
||||
// 辅助函数
|
||||
std::string regToString(PhysicalReg reg);
|
||||
void printOperand(MachineOperand* op);
|
||||
|
||||
MachineFunction* MFunc;
|
||||
|
||||
@@ -22,7 +22,11 @@ private:
|
||||
// 函数级代码生成 (实现新的流水线)
|
||||
std::string function_gen(Function* func);
|
||||
|
||||
// 私有辅助函数,用于根据类型计算其占用的字节数。
|
||||
unsigned getTypeSizeInBytes(Type* type);
|
||||
|
||||
Module* module;
|
||||
bool gc_failed = false;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
61
src/include/backend/RISCv64/RISCv64BasicBlockAlloc.h
Normal file
61
src/include/backend/RISCv64/RISCv64BasicBlockAlloc.h
Normal 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
|
||||
@@ -3,6 +3,12 @@
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
|
||||
// Forward declarations
|
||||
namespace sysy {
|
||||
class GlobalValue;
|
||||
class Value;
|
||||
}
|
||||
|
||||
extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
|
||||
@@ -16,10 +22,13 @@ public:
|
||||
|
||||
// 公开接口,以便后续模块(如RegAlloc)可以查询或创建vreg
|
||||
unsigned getVReg(Value* val);
|
||||
unsigned getNewVReg() { return vreg_counter++; }
|
||||
unsigned getNewVReg(Type* type);
|
||||
unsigned getVRegCounter() const;
|
||||
// 获取 vreg_map 的公共接口
|
||||
const std::map<Value*, unsigned>& getVRegMap() const { return vreg_map; }
|
||||
|
||||
const std::map<unsigned, Value*>& getVRegValueMap() const { return vreg_to_value_map; }
|
||||
const std::map<unsigned, Type*>& getVRegTypeMap() const { return vreg_type_map; }
|
||||
int foo3 = 0;
|
||||
private:
|
||||
// DAG节点定义,作为ISel的内部实现细节
|
||||
struct DAGNode;
|
||||
@@ -38,6 +47,7 @@ private:
|
||||
// 用于计算类型大小的辅助函数
|
||||
unsigned getTypeSizeInBytes(Type* type);
|
||||
|
||||
// 打印DAG图以供调试
|
||||
void print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, const std::string& bb_name);
|
||||
|
||||
// 状态
|
||||
@@ -47,6 +57,8 @@ private:
|
||||
|
||||
// 映射关系
|
||||
std::map<Value*, unsigned> vreg_map;
|
||||
std::map<unsigned, Value*> vreg_to_value_map;
|
||||
std::map<unsigned, Type*> vreg_type_map;
|
||||
std::map<const BasicBlock*, MachineBasicBlock*> bb_map;
|
||||
|
||||
unsigned vreg_counter;
|
||||
|
||||
97
src/include/backend/RISCv64/RISCv64Info.h
Normal file
97
src/include/backend/RISCv64/RISCv64Info.h
Normal file
@@ -0,0 +1,97 @@
|
||||
#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::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
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "IR.h" // 确保包含了您自己的IR头文件
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
@@ -32,21 +33,22 @@ enum class PhysicalReg {
|
||||
A0, A1, A2, A3, A4, A5, A6, A7,
|
||||
|
||||
// --- 浮点寄存器 ---
|
||||
// (保持您原有的 F0-F31 命名)
|
||||
F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11,
|
||||
F12, F13, F14, F15, F16, F17, F18, F19, F20, F21,
|
||||
F22, F23, F24, F25, F26, F27, F28, F29, F30, F31,
|
||||
|
||||
// 用于内部表示物理寄存器在干扰图中的节点ID(一个简单的特殊ID,确保不与vreg_counter冲突)
|
||||
// 假设 vreg_counter 不会达到这么大的值
|
||||
PHYS_REG_START_ID = 100000,
|
||||
PHYS_REG_START_ID = 1000000,
|
||||
PHYS_REG_END_ID = PHYS_REG_START_ID + 320, // 预留足够的空间
|
||||
|
||||
INVALID, ///< 无效寄存器标记
|
||||
};
|
||||
|
||||
// RISC-V 指令操作码枚举
|
||||
enum class RVOpcodes {
|
||||
// 算术指令
|
||||
ADD, ADDI, ADDW, ADDIW, SUB, SUBW, MUL, MULW, DIV, DIVW, REM, REMW,
|
||||
ADD, ADDI, ADDW, ADDIW, SUB, SUBW, MUL, MULW, MULH, DIV, DIVW, REM, REMW,
|
||||
// 逻辑指令
|
||||
XOR, XORI, OR, ORI, AND, ANDI,
|
||||
// 移位指令
|
||||
@@ -64,16 +66,102 @@ enum class RVOpcodes {
|
||||
CALL,
|
||||
// 特殊标记,非指令
|
||||
LABEL,
|
||||
// 新增伪指令,用于解耦栈帧处理
|
||||
|
||||
// 浮点指令 (RISC-V 'F' 扩展)
|
||||
// 浮点加载与存储
|
||||
FLW, // flw rd, offset(rs1)
|
||||
FSW, // fsw rs2, offset(rs1)
|
||||
FLD, // fld rd, offset(rs1)
|
||||
FSD, // fsd rs2, offset(rs1)
|
||||
|
||||
// 浮点算术运算 (单精度)
|
||||
FADD_S, // fadd.s rd, rs1, rs2
|
||||
FSUB_S, // fsub.s rd, rs1, rs2
|
||||
FMUL_S, // fmul.s rd, rs1, rs2
|
||||
FDIV_S, // fdiv.s rd, rs1, rs2
|
||||
|
||||
// 浮点比较 (单精度)
|
||||
FEQ_S, // feq.s rd, rs1, rs2 (结果写入整数寄存器rd)
|
||||
FLT_S, // flt.s rd, rs1, rs2 (less than)
|
||||
FLE_S, // fle.s rd, rs1, rs2 (less than or equal)
|
||||
|
||||
// 浮点转换
|
||||
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 (浮点寄存器之间)
|
||||
FMV_W_X, // fmv.w.x rd, rs1 (整数寄存器位模式 -> 浮点寄存器)
|
||||
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)
|
||||
FRAME_STORE_W, // 保存 32位 Word 到栈帧 (对应 sw)
|
||||
FRAME_STORE_D, // 保存 64位 Doubleword 到栈帧 (对应 sd)
|
||||
FRAME_LOAD_F, // 从栈帧加载单精度浮点数
|
||||
FRAME_STORE_F, // 将单精度浮点数存入栈帧
|
||||
FRAME_ADDR, // 获取栈帧变量的地址
|
||||
PSEUDO_KEEPALIVE, // 保持寄存器活跃,防止优化器删除
|
||||
};
|
||||
|
||||
// 定义一个全局辅助函数或常量,提供调用者保存寄存器列表
|
||||
const std::vector<PhysicalReg>& getCallerSavedIntRegs();
|
||||
inline bool isGPR(PhysicalReg reg) {
|
||||
return reg >= PhysicalReg::ZERO && reg <= PhysicalReg::T6;
|
||||
}
|
||||
|
||||
// 判断一个物理寄存器是否是浮点寄存器 (FPR)
|
||||
inline bool isFPR(PhysicalReg reg) {
|
||||
return reg >= PhysicalReg::F0 && reg <= PhysicalReg::F31;
|
||||
}
|
||||
|
||||
// 获取所有调用者保存的整数寄存器 (t0-t6, a0-a7)
|
||||
inline const std::vector<PhysicalReg>& getCallerSavedIntRegs() {
|
||||
static const std::vector<PhysicalReg> regs = {
|
||||
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3,
|
||||
PhysicalReg::T4, PhysicalReg::T5, PhysicalReg::T6,
|
||||
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3,
|
||||
PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7
|
||||
};
|
||||
return regs;
|
||||
}
|
||||
|
||||
// 获取所有被调用者保存的整数寄存器 (s0-s11)
|
||||
inline const std::vector<PhysicalReg>& getCalleeSavedIntRegs() {
|
||||
static const std::vector<PhysicalReg> regs = {
|
||||
PhysicalReg::S0, PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3,
|
||||
PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
|
||||
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11
|
||||
};
|
||||
return regs;
|
||||
}
|
||||
|
||||
// 获取所有调用者保存的浮点寄存器 (ft0-ft11, fa0-fa7)
|
||||
inline const std::vector<PhysicalReg>& getCallerSavedFpRegs() {
|
||||
static const std::vector<PhysicalReg> regs = {
|
||||
PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3,
|
||||
PhysicalReg::F4, PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7,
|
||||
PhysicalReg::F8, PhysicalReg::F9, PhysicalReg::F10, PhysicalReg::F11, // ft0-ft11 和 fa0-fa7 在标准ABI中重叠
|
||||
PhysicalReg::F12, PhysicalReg::F13, PhysicalReg::F14, PhysicalReg::F15,
|
||||
PhysicalReg::F16, PhysicalReg::F17
|
||||
};
|
||||
return regs;
|
||||
}
|
||||
|
||||
// 获取所有被调用者保存的浮点寄存器 (fs0-fs11)
|
||||
inline const std::vector<PhysicalReg>& getCalleeSavedFpRegs() {
|
||||
static const std::vector<PhysicalReg> regs = {
|
||||
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
|
||||
};
|
||||
return regs;
|
||||
}
|
||||
|
||||
class MachineOperand;
|
||||
class RegOperand;
|
||||
@@ -114,6 +202,11 @@ public:
|
||||
preg = new_preg;
|
||||
is_virtual = false;
|
||||
}
|
||||
|
||||
void setVRegNum(unsigned new_vreg_num) {
|
||||
vreg_num = new_vreg_num;
|
||||
is_virtual = true; // 确保设置vreg时,操作数状态正确
|
||||
}
|
||||
private:
|
||||
unsigned vreg_num = 0;
|
||||
PhysicalReg preg = PhysicalReg::ZERO;
|
||||
@@ -162,6 +255,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;
|
||||
@@ -193,12 +299,15 @@ private:
|
||||
// 栈帧信息
|
||||
struct StackFrameInfo {
|
||||
int locals_size = 0; // 仅为AllocaInst分配的大小
|
||||
int locals_end_offset = 0; // 记录局部变量分配结束后的偏移量(相对于s0,为负)
|
||||
int spill_size = 0; // 仅为溢出分配的大小
|
||||
int total_size = 0; // 总大小
|
||||
int callee_saved_size = 0; // 保存寄存器的大小
|
||||
std::map<unsigned, int> alloca_offsets; // <AllocaInst的vreg, 栈偏移>
|
||||
std::map<unsigned, int> spill_offsets; // <溢出vreg, 栈偏移>
|
||||
std::set<PhysicalReg> used_callee_saved_regs; // 使用的保存寄存器
|
||||
std::map<unsigned, PhysicalReg> vreg_to_preg_map; // RegAlloc最终的分配结果
|
||||
std::vector<PhysicalReg> callee_saved_regs_to_store; // 已排序的、需要存取的被调用者保存寄存器
|
||||
};
|
||||
|
||||
// 机器函数
|
||||
@@ -212,7 +321,7 @@ public:
|
||||
StackFrameInfo& getFrameInfo() { return frame_info; }
|
||||
const std::vector<std::unique_ptr<MachineBasicBlock>>& getBlocks() const { return blocks; }
|
||||
std::vector<std::unique_ptr<MachineBasicBlock>>& getBlocks() { return blocks; }
|
||||
|
||||
void dumpStackFrameInfo(std::ostream& os = std::cerr) const;
|
||||
void addBlock(std::unique_ptr<MachineBasicBlock> block) {
|
||||
blocks.push_back(std::move(block));
|
||||
}
|
||||
@@ -223,16 +332,23 @@ private:
|
||||
std::vector<std::unique_ptr<MachineBasicBlock>> blocks;
|
||||
StackFrameInfo frame_info;
|
||||
};
|
||||
|
||||
inline const std::vector<PhysicalReg>& getCallerSavedIntRegs() {
|
||||
static const std::vector<PhysicalReg> regs = {
|
||||
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3,
|
||||
PhysicalReg::T4, PhysicalReg::T5, PhysicalReg::T6,
|
||||
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3,
|
||||
PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7
|
||||
};
|
||||
return regs;
|
||||
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
|
||||
|
||||
#endif // RISCV64_LLIR_H
|
||||
81
src/include/backend/RISCv64/RISCv64LinearScan.h
Normal file
81
src/include/backend/RISCv64/RISCv64LinearScan.h
Normal 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
|
||||
@@ -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"
|
||||
@@ -8,7 +9,8 @@
|
||||
#include "CalleeSavedHandler.h"
|
||||
#include "LegalizeImmediates.h"
|
||||
#include "PrologueEpilogueInsertion.h"
|
||||
#include "Pass.h"
|
||||
#include "EliminateFrameIndices.h"
|
||||
#include "DivStrengthReduction.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
|
||||
@@ -3,9 +3,15 @@
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "RISCv64ISel.h" // 包含 RISCv64ISel.h 以访问 ISel 和 Value 类型
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <stack>
|
||||
|
||||
extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
extern int DEBUGLENGTH; // 用于限制调试输出的长度
|
||||
extern int DEEPERDEBUG; // 用于更深层次的调试输出
|
||||
|
||||
namespace sysy {
|
||||
|
||||
@@ -14,60 +20,101 @@ public:
|
||||
RISCv64RegAlloc(MachineFunction* mfunc);
|
||||
|
||||
// 模块主入口
|
||||
void run();
|
||||
bool run();
|
||||
|
||||
private:
|
||||
using LiveSet = std::set<unsigned>; // 活跃虚拟寄存器集合
|
||||
using InterferenceGraph = std::map<unsigned, std::set<unsigned>>;
|
||||
// 类型定义,与Python版本对应
|
||||
using VRegSet = std::set<unsigned>;
|
||||
using InterferenceGraph = std::map<unsigned, VRegSet>;
|
||||
using VRegStack = std::vector<unsigned>; // 使用vector模拟栈,方便遍历
|
||||
using MoveList = std::map<unsigned, std::set<const MachineInstr*>>;
|
||||
using AliasMap = std::map<unsigned, unsigned>;
|
||||
using ColorMap = std::map<unsigned, PhysicalReg>;
|
||||
using VRegMoveSet = std::set<const MachineInstr*>;
|
||||
|
||||
// 栈帧管理
|
||||
void eliminateFrameIndices();
|
||||
|
||||
// 活跃性分析
|
||||
// --- 核心算法流程 ---
|
||||
void initialize();
|
||||
void build();
|
||||
void makeWorklist();
|
||||
void simplify();
|
||||
void coalesce();
|
||||
void freeze();
|
||||
void selectSpill();
|
||||
void assignColors();
|
||||
void rewriteProgram();
|
||||
bool doAllocation();
|
||||
void applyColoring();
|
||||
|
||||
void dumpState(const std::string &stage);
|
||||
|
||||
void precolorByCallingConvention();
|
||||
|
||||
// --- 辅助函数 ---
|
||||
void getInstrUseDef(const MachineInstr* instr, VRegSet& use, VRegSet& def);
|
||||
void getInstrUseDef_Liveness(const MachineInstr *instr, VRegSet &use, VRegSet &def);
|
||||
void addEdge(unsigned u, unsigned v);
|
||||
VRegSet adjacent(unsigned n);
|
||||
VRegMoveSet nodeMoves(unsigned n);
|
||||
bool moveRelated(unsigned n);
|
||||
void decrementDegree(unsigned m);
|
||||
void enableMoves(const VRegSet& nodes);
|
||||
unsigned getAlias(unsigned n);
|
||||
void addWorklist(unsigned u);
|
||||
bool briggsHeuristic(unsigned u, unsigned v);
|
||||
bool georgeHeuristic(unsigned u, unsigned v);
|
||||
void combine(unsigned u, unsigned v);
|
||||
void freezeMoves(unsigned u);
|
||||
void collectUsedCalleeSavedRegs();
|
||||
bool isFPVReg(unsigned vreg) const;
|
||||
std::string regToString(PhysicalReg reg);
|
||||
std::string regIdToString(unsigned id);
|
||||
|
||||
// --- 活跃性分析 ---
|
||||
void analyzeLiveness();
|
||||
|
||||
// 构建干扰图
|
||||
void buildInterferenceGraph();
|
||||
|
||||
// 图着色分配寄存器
|
||||
void colorGraph();
|
||||
|
||||
// 重写函数,替换vreg并插入溢出代码
|
||||
void rewriteFunction();
|
||||
|
||||
// 辅助函数,获取指令的Use/Def集合
|
||||
void getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def);
|
||||
|
||||
// 辅助函数,处理调用约定
|
||||
void handleCallingConvention();
|
||||
|
||||
MachineFunction* MFunc;
|
||||
|
||||
// 活跃性分析结果
|
||||
std::map<const MachineInstr*, LiveSet> live_in_map;
|
||||
std::map<const MachineInstr*, LiveSet> live_out_map;
|
||||
RISCv64ISel* ISel;
|
||||
|
||||
// 干扰图
|
||||
InterferenceGraph interference_graph;
|
||||
|
||||
// 图着色结果
|
||||
std::map<unsigned, PhysicalReg> color_map; // vreg -> preg
|
||||
std::set<unsigned> spilled_vregs; // 被溢出的vreg集合
|
||||
|
||||
// 可用的物理寄存器池
|
||||
// --- 算法数据结构 ---
|
||||
// 寄存器池
|
||||
std::vector<PhysicalReg> allocable_int_regs;
|
||||
std::vector<PhysicalReg> allocable_fp_regs;
|
||||
int K_int; // 整数寄存器数量
|
||||
int K_fp; // 浮点寄存器数量
|
||||
|
||||
// 存储vreg到IR Value*的反向映射
|
||||
// 这个map将在run()函数开始时被填充,并在rewriteFunction()中使用。
|
||||
std::map<unsigned, Value*> vreg_to_value_map;
|
||||
std::map<PhysicalReg, unsigned> preg_to_vreg_id_map; // 物理寄存器到特殊vreg ID的映射
|
||||
|
||||
// 用于计算类型大小的辅助函数
|
||||
unsigned getTypeSizeInBytes(Type* type);
|
||||
// 节点集合
|
||||
VRegSet precolored; // 预着色的节点 (物理寄存器)
|
||||
VRegSet initial; // 初始的、所有待处理的虚拟寄存器节点
|
||||
VRegSet simplifyWorklist;
|
||||
VRegSet freezeWorklist;
|
||||
VRegSet spillWorklist;
|
||||
VRegSet spilledNodes;
|
||||
VRegSet coalescedNodes;
|
||||
VRegSet coloredNodes;
|
||||
VRegStack selectStack;
|
||||
|
||||
// 辅助函数,用于打印集合
|
||||
static void printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os);
|
||||
// Move指令相关
|
||||
std::set<const MachineInstr*> coalescedMoves;
|
||||
std::set<const MachineInstr*> constrainedMoves;
|
||||
std::set<const MachineInstr*> frozenMoves;
|
||||
std::set<const MachineInstr*> worklistMoves;
|
||||
std::set<const MachineInstr*> activeMoves;
|
||||
|
||||
// 数据结构
|
||||
InterferenceGraph adjSet;
|
||||
std::map<unsigned, VRegSet> adjList; // 邻接表
|
||||
std::map<unsigned, int> degree;
|
||||
MoveList moveList;
|
||||
AliasMap alias;
|
||||
ColorMap color_map;
|
||||
|
||||
// 活跃性分析结果
|
||||
std::map<const MachineInstr*, VRegSet> live_in_map;
|
||||
std::map<const MachineInstr*, VRegSet> live_out_map;
|
||||
|
||||
// VReg -> Value* 和 VReg -> Type* 的映射
|
||||
const std::map<unsigned, Value*>& vreg_to_value_map;
|
||||
const std::map<unsigned, Type*>& vreg_type_map;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
@@ -202,6 +202,7 @@ class Use {
|
||||
|
||||
public:
|
||||
unsigned getIndex() const { return index; } ///< 返回value在User操作数中的位置
|
||||
void setIndex(int newIndex) { index = newIndex; } ///< 设置value在User操作数中的位置
|
||||
User* getUser() const { return user; } ///< 返回使用者
|
||||
Value* getValue() const { return value; } ///< 返回被使用的值
|
||||
void setValue(Value *newValue) { value = newValue; } ///< 将被使用的值设置为newValue
|
||||
@@ -229,7 +230,14 @@ class Value {
|
||||
std::list<std::shared_ptr<Use>>& getUses() { return uses; } ///< 获取使用关系列表
|
||||
void addUse(const std::shared_ptr<Use> &use) { uses.push_back(use); } ///< 添加使用关系
|
||||
void replaceAllUsesWith(Value *value); ///< 将原来使用该value的使用者全变为使用给定参数value并修改相应use关系
|
||||
void removeUse(const std::shared_ptr<Use> &use) { uses.remove(use); } ///< 删除使用关系use
|
||||
void removeUse(const std::shared_ptr<Use> &use) {
|
||||
assert(use != nullptr && "Use cannot be null");
|
||||
assert(use->getValue() == this && "Use being removed does NOT point to this Value!");
|
||||
auto it = std::find(uses.begin(), uses.end(), use);
|
||||
assert(it != uses.end() && "Use not found in Value's uses");
|
||||
uses.remove(use);
|
||||
} ///< 删除使用关系use
|
||||
void removeAllUses();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -576,7 +584,9 @@ public:
|
||||
if (iter != predecessors.end()) {
|
||||
predecessors.erase(iter);
|
||||
} else {
|
||||
assert(false);
|
||||
// 如果没有找到前驱块,可能是因为它已经被移除或不存在
|
||||
// 这可能是一个错误情况,或者是因为在CFG优化过程中已经处理
|
||||
// assert(false && "Predecessor block not found in BasicBlock");
|
||||
}
|
||||
}
|
||||
void removeSuccessor(BasicBlock *block) {
|
||||
@@ -584,7 +594,9 @@ public:
|
||||
if (iter != successors.end()) {
|
||||
successors.erase(iter);
|
||||
} else {
|
||||
assert(false);
|
||||
// 如果没有找到后继块,可能是因为它已经被移除或不存在
|
||||
// 这可能是一个错误情况,或者是因为在CFG优化过程中已经处理
|
||||
// assert(false && "Successor block not found in BasicBlock");
|
||||
}
|
||||
}
|
||||
void replacePredecessor(BasicBlock *oldBlock, BasicBlock *newBlock) {
|
||||
@@ -629,21 +641,6 @@ class User : public Value {
|
||||
explicit User(Type *type, const std::string &name = "") : Value(type, name) {}
|
||||
|
||||
public:
|
||||
// ~User() override {
|
||||
// // 当 User 对象被销毁时(例如,LoadInst 或 StoreInst 被删除时),
|
||||
// // 它必须通知它所使用的所有 Value,将对应的 Use 关系从它们的 uses 列表中移除。
|
||||
// // 这样可以防止 Value 的 uses 列表中出现悬空的 Use 对象。
|
||||
// for (const auto &use_ptr : operands) {
|
||||
// // 确保 use_ptr 非空,并且其内部指向的 Value* 也非空
|
||||
// // (虽然通常情况下不会为空,但为了健壮性考虑)
|
||||
// if (use_ptr && use_ptr->getValue()) {
|
||||
// use_ptr->getValue()->removeUse(use_ptr);
|
||||
// }
|
||||
// }
|
||||
// // operands 向量本身是 std::vector<std::shared_ptr<Use>>,
|
||||
// // 在此析构函数结束后,operands 向量会被销毁,其内部的 shared_ptr 也会被释放,
|
||||
// // 如果 shared_ptr 引用计数降为0,Use 对象本身也会被销毁。
|
||||
// }
|
||||
unsigned getNumOperands() const { return operands.size(); } ///< 获取操作数数量
|
||||
auto operand_begin() const { return operands.begin(); } ///< 返回操作数列表的开头迭代器
|
||||
auto operand_end() const { return operands.end(); } ///< 返回操作数列表的结尾迭代器
|
||||
@@ -653,11 +650,7 @@ class User : public Value {
|
||||
operands.emplace_back(std::make_shared<Use>(operands.size(), this, value));
|
||||
value->addUse(operands.back());
|
||||
} ///< 增加操作数
|
||||
void removeOperand(unsigned index) {
|
||||
auto value = getOperand(index);
|
||||
value->removeUse(operands[index]);
|
||||
operands.erase(operands.begin() + index);
|
||||
} ///< 移除操作数
|
||||
void removeOperand(unsigned index);
|
||||
template <typename ContainerT>
|
||||
void addOperands(const ContainerT &newoperands) {
|
||||
for (auto value : newoperands) {
|
||||
@@ -724,6 +717,8 @@ class Instruction : public User {
|
||||
kPhi = 0x1UL << 39,
|
||||
kBitItoF = 0x1UL << 40,
|
||||
kBitFtoI = 0x1UL << 41,
|
||||
kSRA = 0x1UL << 42,
|
||||
kMulh = 0x1UL << 43
|
||||
};
|
||||
|
||||
protected:
|
||||
@@ -820,6 +815,12 @@ public:
|
||||
return "Memset";
|
||||
case kPhi:
|
||||
return "Phi";
|
||||
case kBitItoF:
|
||||
return "BitItoF";
|
||||
case kBitFtoI:
|
||||
return "BitFtoI";
|
||||
case kSRA:
|
||||
return "SRA";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
@@ -831,11 +832,15 @@ public:
|
||||
|
||||
bool isBinary() const {
|
||||
static constexpr uint64_t BinaryOpMask =
|
||||
(kAdd | kSub | kMul | kDiv | kRem | kAnd | kOr) |
|
||||
(kICmpEQ | kICmpNE | kICmpLT | kICmpGT | kICmpLE | kICmpGE) |
|
||||
(kAdd | kSub | kMul | kDiv | kRem | kAnd | kOr | kSRA | kMulh) |
|
||||
(kICmpEQ | kICmpNE | kICmpLT | kICmpGT | kICmpLE | kICmpGE);
|
||||
return kind & BinaryOpMask;
|
||||
}
|
||||
bool isFPBinary() const {
|
||||
static constexpr uint64_t FPBinaryOpMask =
|
||||
(kFAdd | kFSub | kFMul | kFDiv) |
|
||||
(kFCmpEQ | kFCmpNE | kFCmpLT | kFCmpGT | kFCmpLE | kFCmpGE);
|
||||
return kind & BinaryOpMask;
|
||||
return kind & FPBinaryOpMask;
|
||||
}
|
||||
bool isUnary() const {
|
||||
static constexpr uint64_t UnaryOpMask =
|
||||
@@ -903,40 +908,54 @@ class PhiInst : public Instruction {
|
||||
const std::string &name = "")
|
||||
: Instruction(Kind::kPhi, type, parent, name), vsize(rhs.size()) {
|
||||
assert(rhs.size() == Blocks.size() && "PhiInst: rhs and Blocks must have the same size");
|
||||
for(size_t i = 0; i < rhs.size(); ++i) {
|
||||
for(size_t i = 0; i < vsize; ++i) {
|
||||
addOperand(rhs[i]);
|
||||
addOperand(Blocks[i]);
|
||||
blk2val[Blocks[i]] = rhs[i];
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
Value* getValue(unsigned k) const {return getOperand(2 * k);} ///< 获取位置为k的值
|
||||
BasicBlock* getBlock(unsigned k) const {return dynamic_cast<BasicBlock*>(getOperand(2 * k + 1));}
|
||||
//增加llvm同名方法实现获取value和block
|
||||
Value* getIncomingValue(unsigned k) const {return getOperand(2 * k);} ///< 获取位置为k的值
|
||||
BasicBlock* getIncomingBlock(unsigned k) const {return dynamic_cast<BasicBlock*>(getOperand(2 * k + 1));}
|
||||
|
||||
auto& getincomings() const {return blk2val;} ///< 获取所有的基本块和对应的值
|
||||
|
||||
Value* getvalfromBlk(BasicBlock* blk);
|
||||
BasicBlock* getBlkfromVal(Value* val);
|
||||
|
||||
unsigned getNumIncomingValues() const { return vsize; } ///< 获取传入值的数量
|
||||
Value *getIncomingValue(unsigned Idx) const { return getOperand(Idx * 2); } ///< 获取指定位置的传入值
|
||||
BasicBlock *getIncomingBlock(unsigned Idx) const {return dynamic_cast<BasicBlock *>(getOperand(Idx * 2 + 1)); } ///< 获取指定位置的传入基本块
|
||||
|
||||
Value* getValfromBlk(BasicBlock* block);
|
||||
BasicBlock* getBlkfromVal(Value* value);
|
||||
|
||||
void addIncoming(Value *value, BasicBlock *block) {
|
||||
assert(value && block && "PhiInst: value and block must not be null");
|
||||
assert(value && block && "PhiInst: value and block cannot be null");
|
||||
addOperand(value);
|
||||
addOperand(block);
|
||||
blk2val[block] = value;
|
||||
vsize++;
|
||||
} ///< 添加传入值和对应的基本块
|
||||
|
||||
void delValue(Value* val);
|
||||
void delBlk(BasicBlock* blk);
|
||||
|
||||
void replaceBlk(BasicBlock* newBlk, unsigned k);
|
||||
void replaceold2new(BasicBlock* oldBlk, BasicBlock* newBlk);
|
||||
void refreshB2VMap();
|
||||
|
||||
void removeIncoming(unsigned Idx) {
|
||||
assert(Idx < vsize && "PhiInst: Index out of bounds");
|
||||
auto blk = getIncomingBlock(Idx);
|
||||
removeOperand(Idx * 2 + 1); // Remove block
|
||||
removeOperand(Idx * 2); // Remove value
|
||||
blk2val.erase(blk);
|
||||
vsize--;
|
||||
} ///< 移除指定位置的传入值和对应的基本块
|
||||
// 移除指定的传入值或基本块
|
||||
void removeIncomingValue(Value *value);
|
||||
void removeIncomingBlock(BasicBlock *block);
|
||||
// 设置指定位置的传入值或基本块
|
||||
void setIncomingValue(unsigned Idx, Value *value);
|
||||
void setIncomingBlock(unsigned Idx, BasicBlock *block);
|
||||
// 替换指定位置的传入值或基本块(原理是删除再添加)保留旧块或者旧值
|
||||
void replaceIncomingValue(Value *oldValue, Value *newValue);
|
||||
void replaceIncomingBlock(BasicBlock *oldBlock, BasicBlock *newBlock);
|
||||
// 替换指定位置的传入值或基本块(原理是删除再添加)
|
||||
void replaceIncomingValue(Value *oldValue, Value *newValue, BasicBlock *newBlock);
|
||||
void replaceIncomingBlock(BasicBlock *oldBlock, BasicBlock *newBlock, Value *newValue);
|
||||
void refreshMap() {
|
||||
blk2val.clear();
|
||||
for (unsigned i = 0; i < vsize; ++i) {
|
||||
blk2val[getIncomingBlock(i)] = getIncomingValue(i);
|
||||
}
|
||||
} ///< 刷新块到值的映射关系
|
||||
auto getValues() { return make_range(std::next(operand_begin()), operand_end()); }
|
||||
};
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ class IRBuilder {
|
||||
UnaryInst * createFNotInst(Value *operand, const std::string &name = "") {
|
||||
return createUnaryInst(Instruction::kFNot, Type::getIntType(), operand, name);
|
||||
} ///< 创建浮点取非指令
|
||||
UnaryInst * createIToFInst(Value *operand, const std::string &name = "") {
|
||||
UnaryInst * createItoFInst(Value *operand, const std::string &name = "") {
|
||||
return createUnaryInst(Instruction::kItoF, Type::getFloatType(), operand, name);
|
||||
} ///< 创建整型转浮点指令
|
||||
UnaryInst * createBitItoFInst(Value *operand, const std::string &name = "") {
|
||||
@@ -217,6 +217,12 @@ class IRBuilder {
|
||||
BinaryInst * createOrInst(Value *lhs, Value *rhs, const std::string &name = "") {
|
||||
return createBinaryInst(Instruction::kOr, Type::getIntType(), lhs, rhs, name);
|
||||
} ///< 创建按位或指令
|
||||
BinaryInst * createSRAInst(Value *lhs, Value *rhs, const std::string &name = "") {
|
||||
return createBinaryInst(Instruction::kSRA, Type::getIntType(), lhs, rhs, name);
|
||||
} ///< 创建算术右移指令
|
||||
BinaryInst * createMulhInst(Value *lhs, Value *rhs, const std::string &name = "") {
|
||||
return createBinaryInst(Instruction::kMulh, Type::getIntType(), lhs, rhs, name);
|
||||
} ///< 创建高位乘法指令
|
||||
CallInst * createCallInst(Function *callee, const std::vector<Value *> &args, const std::string &name = "") {
|
||||
std::string newName;
|
||||
if (name.empty() && callee->getReturnType() != Type::getVoidType()) {
|
||||
|
||||
@@ -6,30 +6,82 @@
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 支配树分析结果类 (保持不变)
|
||||
// 支配树分析结果类
|
||||
class DominatorTree : public AnalysisResultBase {
|
||||
public:
|
||||
DominatorTree(Function* F);
|
||||
// 获取指定基本块的所有支配者
|
||||
const std::set<BasicBlock*>* getDominators(BasicBlock* BB) const;
|
||||
BasicBlock* getImmediateDominator(BasicBlock* BB) const;
|
||||
const std::set<BasicBlock*>* getDominanceFrontier(BasicBlock* BB) const;
|
||||
// 获取指定基本块的即时支配者 (Immediate Dominator)
|
||||
BasicBlock* getImmediateDominator(BasicBlock* BB) const;
|
||||
// 获取指定基本块的支配边界 (Dominance Frontier)
|
||||
const std::set<BasicBlock*>* getDominanceFrontier(BasicBlock* BB) const;
|
||||
// 获取指定基本块在支配树中的子节点
|
||||
const std::set<BasicBlock*>* getDominatorTreeChildren(BasicBlock* BB) const;
|
||||
// 额外的 Getter:获取所有支配者、即时支配者和支配边界的完整映射(可选,主要用于调试或特定场景)
|
||||
const std::map<BasicBlock*, std::set<BasicBlock*>>& getDominatorsMap() const { return Dominators; }
|
||||
const std::map<BasicBlock*, BasicBlock*>& getIDomsMap() const { return IDoms; }
|
||||
const std::map<BasicBlock*, std::set<BasicBlock*>>& getDominanceFrontiersMap() const { return DominanceFrontiers; }
|
||||
|
||||
// 计算所有基本块的支配者集合
|
||||
void computeDominators(Function* F);
|
||||
void computeIDoms(Function* F);
|
||||
// 计算所有基本块的即时支配者(内部使用 Lengauer-Tarjan 算法)
|
||||
void computeIDoms(Function* F);
|
||||
// 计算所有基本块的支配边界
|
||||
void computeDominanceFrontiers(Function* F);
|
||||
// 计算支配树的结构(即每个节点的直接子节点)
|
||||
void computeDominatorTreeChildren(Function* F);
|
||||
private:
|
||||
// 与该支配树关联的函数
|
||||
Function* AssociatedFunction;
|
||||
std::map<BasicBlock*, std::set<BasicBlock*>> Dominators;
|
||||
std::map<BasicBlock*, BasicBlock*> IDoms;
|
||||
std::map<BasicBlock*, std::set<BasicBlock*>> DominanceFrontiers;
|
||||
std::map<BasicBlock*, std::set<BasicBlock*>> DominatorTreeChildren;
|
||||
std::map<BasicBlock*, std::set<BasicBlock*>> Dominators; // 每个基本块的支配者集合
|
||||
std::map<BasicBlock*, BasicBlock*> IDoms; // 每个基本块的即时支配者
|
||||
std::map<BasicBlock*, std::set<BasicBlock*>> DominanceFrontiers; // 每个基本块的支配边界
|
||||
std::map<BasicBlock*, std::set<BasicBlock*>> DominatorTreeChildren; // 支配树中每个基本块的子节点
|
||||
|
||||
// ==========================================================
|
||||
// Lengauer-Tarjan 算法内部所需的数据结构和辅助函数
|
||||
// 这些成员是私有的,以封装 LT 算法的复杂性并避免命名空间污染
|
||||
// ==========================================================
|
||||
|
||||
// DFS 遍历相关:
|
||||
std::map<BasicBlock*, int> dfnum_map; // 存储每个基本块的 DFS 编号
|
||||
std::vector<BasicBlock*> vertex_vec; // 通过 DFS 编号反向查找对应的基本块指针
|
||||
std::map<BasicBlock*, BasicBlock*> parent_map; // 存储 DFS 树中每个基本块的父节点
|
||||
int df_counter; // DFS 计数器,也代表 DFS 遍历的总节点数 (N)
|
||||
|
||||
// 半支配者 (Semi-dominator) 相关:
|
||||
std::map<BasicBlock*, BasicBlock*> sdom_map; // 存储每个基本块的半支配者
|
||||
std::map<BasicBlock*, BasicBlock*> idom_map; // 存储每个基本块的即时支配者 (IDom)
|
||||
std::map<BasicBlock*, std::vector<BasicBlock*>> bucket_map; // 桶结构,用于存储具有相同半支配者的节点,以延迟 IDom 计算
|
||||
|
||||
// 并查集 (Union-Find) 相关(用于 evalAndCompress 函数):
|
||||
std::map<BasicBlock*, BasicBlock*> ancestor_map; // 并查集中的父节点(用于路径压缩)
|
||||
std::map<BasicBlock*, BasicBlock*> label_map; // 并查集中,每个集合的代表节点(或其路径上 sdom 最小的节点)
|
||||
|
||||
// ==========================================================
|
||||
// 辅助计算函数 (私有)
|
||||
// ==========================================================
|
||||
|
||||
// 计算基本块的逆后序遍历 (Reverse Post Order, RPO) 顺序
|
||||
// RPO 用于优化支配者计算和 LT 算法的效率
|
||||
std::vector<BasicBlock*> computeReversePostOrder(Function* F);
|
||||
|
||||
// Lengauer-Tarjan 算法特定的辅助 DFS 函数
|
||||
// 用于初始化 dfnum_map, vertex_vec, parent_map
|
||||
void dfs_lt_helper(BasicBlock* u);
|
||||
|
||||
// 结合了并查集的 Find 操作和 LT 算法的 Eval 操作
|
||||
// 用于在路径压缩时更新 label,找到路径上 sdom 最小的节点
|
||||
BasicBlock* evalAndCompress_lt_helper(BasicBlock* i);
|
||||
|
||||
// 并查集的 Link 操作
|
||||
// 将 v_child 挂载到 u_parent 的并查集树下
|
||||
void link_lt_helper(BasicBlock* u_parent, BasicBlock* v_child);
|
||||
};
|
||||
|
||||
|
||||
|
||||
20
src/include/midend/Pass/Optimize/BuildCFG.h
Normal file
20
src/include/midend/Pass/Optimize/BuildCFG.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "IR.h"
|
||||
#include "Pass.h"
|
||||
#include <queue>
|
||||
#include <set>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class BuildCFG : public OptimizationPass {
|
||||
public:
|
||||
static void *ID;
|
||||
BuildCFG() : OptimizationPass("BuildCFG", Granularity::Function) {}
|
||||
bool runOnFunction(Function *F, AnalysisManager &AM) override;
|
||||
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override;
|
||||
void *getPassID() const override { return &ID; }
|
||||
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
24
src/include/midend/Pass/Optimize/LargeArrayToGlobal.h
Normal file
24
src/include/midend/Pass/Optimize/LargeArrayToGlobal.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#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
|
||||
@@ -75,11 +75,7 @@ private:
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// 对支配树进行深度优先遍历,重命名变量并替换 load/store 指令
|
||||
// alloca: 当前正在处理的 AllocaInst
|
||||
// currentBB: 当前正在遍历的基本块
|
||||
// dt: 支配树分析结果
|
||||
// valueStack: 存储当前 AllocaInst 在当前路径上可见的 SSA 值栈
|
||||
void renameVariables(AllocaInst* alloca, BasicBlock* currentBB);
|
||||
void renameVariables(BasicBlock* currentBB);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 阶段4: 清理
|
||||
|
||||
@@ -48,13 +48,6 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
// 清空 User 的 operands 向量。这会递减 User 持有的 shared_ptr<Use> 的引用计数。
|
||||
// 当引用计数降为 0 时,Use 对象本身将被销毁。
|
||||
// User::operands.clear(); // 这个步骤会在 Instruction 的析构函数中自动完成,因为它是 vector 成员
|
||||
// 或者我们可以在 User::removeOperand 方法中确保 Use 对象从 operands 中移除。
|
||||
// 实际上,只要 Value::removeUse(use_ptr) 被调用了,
|
||||
// 当 Instruction 所在的 unique_ptr 销毁时,它的 operands vector 也会被销毁。
|
||||
// 所以这里不需要显式 clear()
|
||||
}
|
||||
static void usedelete(Instruction *inst) {
|
||||
assert(inst && "Instruction to delete cannot be null.");
|
||||
@@ -75,7 +68,7 @@ public:
|
||||
// 步骤3: 物理删除指令
|
||||
// 这会导致 Instruction 对象的 unique_ptr 销毁,从而调用其析构函数链。
|
||||
parentBlock->removeInst(inst);
|
||||
}
|
||||
}
|
||||
|
||||
static BasicBlock::iterator usedelete(BasicBlock::iterator inst_it) {
|
||||
Instruction *inst_to_delete = inst_it->get();
|
||||
@@ -92,7 +85,7 @@ public:
|
||||
|
||||
// 步骤3: 物理删除指令并返回下一个迭代器
|
||||
return parentBlock->removeInst(inst_it);
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否是全局变量
|
||||
static bool isGlobal(Value *val) {
|
||||
|
||||
@@ -279,7 +279,7 @@ private:
|
||||
IRBuilder *pBuilder;
|
||||
|
||||
public:
|
||||
PassManager() = default;
|
||||
PassManager() = delete;
|
||||
~PassManager() = default;
|
||||
|
||||
PassManager(Module *module, IRBuilder *builder) : pmodule(module) ,pBuilder(builder), analysisManager(module) {}
|
||||
|
||||
@@ -59,6 +59,88 @@ private:
|
||||
std::unique_ptr<Module> module;
|
||||
IRBuilder builder;
|
||||
|
||||
using ValueOrOperator = std::variant<Value*, int>;
|
||||
std::vector<ValueOrOperator> BinaryExpStack; ///< 用于存储二元表达式的中缀表达式
|
||||
std::vector<int> BinaryExpLenStack; ///< 用于存储该层次的二元表达式的长度
|
||||
// 下面是用于后缀表达式的计算的数据结构
|
||||
std::vector<ValueOrOperator> BinaryRPNStack; ///< 用于存储二元表达式的后缀表达式
|
||||
std::vector<int> BinaryOpStack; ///< 用于存储二元表达式中缀表达式转换到后缀表达式的操作符栈
|
||||
std::vector<Value *> BinaryValueStack; ///< 用于存储后缀表达式计算的操作数栈
|
||||
|
||||
// 约定操作符:
|
||||
// 1: 'ADD', 2: 'SUB', 3: 'MUL', 4: 'DIV', 5: '%', 6: 'PLUS', 7: 'NEG', 8: 'NOT', 9: 'LPAREN', 10: 'RPAREN'
|
||||
// 这里的操作符是为了方便后缀表达式的计算而设计
|
||||
// 其中,'ADD', 'SUB', 'MUL', 'DIV', '%'
|
||||
// 分别对应加法、减法、乘法、除法和取模
|
||||
// 'PLUS' 和 'NEG' 分别对应一元加法和一元减法
|
||||
// 'NOT' 对应逻辑非
|
||||
// 'LPAREN' 和 'RPAREN' 分别对应左括号和右括号
|
||||
enum BinaryOp {
|
||||
ADD = 1, SUB = 2, MUL = 3, DIV = 4, MOD = 5, PLUS = 6, NEG = 7, NOT = 8, LPAREN = 9, RPAREN = 10,
|
||||
};
|
||||
int getOperatorPrecedence(int op) {
|
||||
switch (op) {
|
||||
case MUL: case DIV: case MOD: return 2;
|
||||
case ADD: case SUB: return 1;
|
||||
case PLUS: case NEG: case NOT: return 3;
|
||||
case LPAREN: case RPAREN: return 0; // Parentheses have lowest precedence for stack logic
|
||||
default: return -1; // Unknown operator
|
||||
}
|
||||
};
|
||||
|
||||
struct ExpKey {
|
||||
BinaryOp op; ///< 操作符
|
||||
Value *left; ///< 左操作数
|
||||
Value *right; ///< 右操作数
|
||||
ExpKey(BinaryOp op, Value *left, Value *right) : op(op), left(left), right(right) {}
|
||||
|
||||
bool operator<(const ExpKey &other) const {
|
||||
if (op != other.op)
|
||||
return op < other.op; ///< 比较操作符
|
||||
if (left != other.left)
|
||||
return left < other.left; ///< 比较左操作
|
||||
return right < other.right; ///< 比较右操作数
|
||||
} ///< 重载小于运算符用于比较ExpKey
|
||||
};
|
||||
|
||||
struct UnExpKey {
|
||||
BinaryOp op; ///< 一元操作符
|
||||
Value *operand; ///< 操作数
|
||||
UnExpKey(BinaryOp op, Value *operand) : op(op), operand(operand) {}
|
||||
|
||||
bool operator<(const UnExpKey &other) const {
|
||||
if (op != other.op)
|
||||
return op < other.op; ///< 比较操作符
|
||||
return operand < other.operand; ///< 比较操作数
|
||||
} ///< 重载小于运算符用于比较UnExpKey
|
||||
};
|
||||
|
||||
struct GEPKey {
|
||||
Value *basePointer;
|
||||
std::vector<Value *> indices;
|
||||
|
||||
// 为 std::map 定义比较运算符,使得 GEPKey 可以作为键
|
||||
bool operator<(const GEPKey &other) const {
|
||||
if (basePointer != other.basePointer) {
|
||||
return basePointer < other.basePointer;
|
||||
}
|
||||
// 逐个比较索引,确保顺序一致
|
||||
if (indices.size() != other.indices.size()) {
|
||||
return indices.size() < other.indices.size();
|
||||
}
|
||||
for (size_t i = 0; i < indices.size(); ++i) {
|
||||
if (indices[i] != other.indices[i]) {
|
||||
return indices[i] < other.indices[i];
|
||||
}
|
||||
}
|
||||
return false; // 如果 basePointer 和所有索引都相同,则认为相等
|
||||
}
|
||||
};
|
||||
std::map<GEPKey, Value*> availableGEPs; ///< 用于存储 GEP 的缓存
|
||||
std::map<ExpKey, Value*> availableBinaryExpressions;
|
||||
std::map<UnExpKey, Value*> availableUnaryExpressions;
|
||||
std::map<Value*, Value*> availableLoads;
|
||||
|
||||
public:
|
||||
SysYIRGenerator() = default;
|
||||
|
||||
@@ -97,7 +179,7 @@ public:
|
||||
std::any visitBlockStmt(SysYParser::BlockStmtContext* ctx) override;
|
||||
// std::any visitStmt(SysYParser::StmtContext *ctx) override;
|
||||
std::any visitAssignStmt(SysYParser::AssignStmtContext *ctx) override;
|
||||
// std::any visitExpStmt(SysYParser::ExpStmtContext *ctx) override;
|
||||
std::any visitExpStmt(SysYParser::ExpStmtContext *ctx) override;
|
||||
// std::any visitBlkStmt(SysYParser::BlkStmtContext *ctx) override;
|
||||
std::any visitIfStmt(SysYParser::IfStmtContext *ctx) override;
|
||||
std::any visitWhileStmt(SysYParser::WhileStmtContext *ctx) override;
|
||||
@@ -131,8 +213,22 @@ public:
|
||||
std::any visitLAndExp(SysYParser::LAndExpContext *ctx) override;
|
||||
std::any visitLOrExp(SysYParser::LOrExpContext *ctx) override;
|
||||
|
||||
// std::any visitConstExp(SysYParser::ConstExpContext *ctx) override;
|
||||
std::any visitConstExp(SysYParser::ConstExpContext *ctx) override;
|
||||
|
||||
bool isRightAssociative(int op);
|
||||
Value* promoteType(Value* value, Type* targetType);
|
||||
Value* computeExp(SysYParser::ExpContext *ctx, Type* targetType = nullptr);
|
||||
Value* computeAddExp(SysYParser::AddExpContext *ctx, Type* targetType = nullptr);
|
||||
void compute();
|
||||
|
||||
// 参数是发生 store 操作的目标地址/变量的 Value*
|
||||
void invalidateExpressionsOnStore(Value* storedAddress);
|
||||
|
||||
// 清除因函数调用而失效的表达式缓存(保守策略)
|
||||
void invalidateExpressionsOnCall();
|
||||
|
||||
// 在进入新的基本块时清空所有表达式缓存
|
||||
void enterNewBasicBlock();
|
||||
public:
|
||||
// 获取GEP指令的地址
|
||||
Value* getGEPAddressInst(Value* basePointer, const std::vector<Value*>& indices);
|
||||
@@ -141,6 +237,7 @@ public:
|
||||
|
||||
unsigned countArrayDimensions(Type* type);
|
||||
|
||||
|
||||
}; // class SysYIRGenerator
|
||||
|
||||
} // namespace sysy
|
||||
@@ -11,6 +11,8 @@ add_library(midend_lib STATIC
|
||||
Pass/Optimize/Reg2Mem.cpp
|
||||
Pass/Optimize/SysYIRCFGOpt.cpp
|
||||
Pass/Optimize/SCCP.cpp
|
||||
Pass/Optimize/BuildCFG.cpp
|
||||
Pass/Optimize/LargeArrayToGlobal.cpp
|
||||
)
|
||||
|
||||
# 包含中端模块所需的头文件路径
|
||||
|
||||
@@ -118,13 +118,45 @@ ArrayType *ArrayType::get(Type *elementType, unsigned numElements) {
|
||||
return result.first->get();
|
||||
}
|
||||
|
||||
// void Value::replaceAllUsesWith(Value *value) {
|
||||
// for (auto &use : uses) {
|
||||
// auto user = use->getUser();
|
||||
// assert(user && "Use's user cannot be null");
|
||||
// user->setOperand(use->getIndex(), value);
|
||||
// }
|
||||
// uses.clear();
|
||||
// }
|
||||
void Value::replaceAllUsesWith(Value *value) {
|
||||
for (auto &use : uses) {
|
||||
use->getUser()->setOperand(use->getIndex(), value);
|
||||
}
|
||||
uses.clear();
|
||||
}
|
||||
// 1. 创建 uses 列表的副本进行迭代。
|
||||
// 这样做是为了避免在迭代过程中,由于 setOperand 间接调用 removeUse 或 addUse
|
||||
// 导致原列表被修改,从而引发迭代器失效问题。
|
||||
std::list<std::shared_ptr<Use>> uses_copy = uses;
|
||||
|
||||
for (auto &use_ptr : uses_copy) { // 遍历副本
|
||||
// 2. 检查 shared_ptr<Use> 本身是否为空。这是最常见的崩溃原因之一。
|
||||
if (use_ptr == nullptr) {
|
||||
std::cerr << "Warning: Encountered a null std::shared_ptr<Use> in Value::uses list. Skipping this entry." << std::endl;
|
||||
// 在一个健康的 IR 中,这种情况不应该发生。如果经常出现,说明你的 Use 创建或管理有问题。
|
||||
continue; // 跳过空的智能指针
|
||||
}
|
||||
|
||||
// 3. 检查 Use 对象内部的 User* 是否为空。
|
||||
User* user_val = use_ptr->getUser();
|
||||
if (user_val == nullptr) {
|
||||
std::cerr << "Warning: Use object (" << use_ptr.get() << ") has a null User* in replaceAllUsesWith. Skipping this entry. This indicates IR corruption." << std::endl;
|
||||
// 同样,在一个健康的 IR 中,Use 对象的 User* 不应该为空。
|
||||
continue; // 跳过用户指针为空的 Use 对象
|
||||
}
|
||||
|
||||
// 如果走到这里,use_ptr 和 user_val 都是有效的,可以安全调用 setOperand
|
||||
user_val->setOperand(use_ptr->getIndex(), value);
|
||||
}
|
||||
|
||||
// 4. 处理完所有 use 之后,清空原始的 uses 列表。
|
||||
// replaceAllUsesWith 的目的就是将所有使用关系从当前 Value 转移走,
|
||||
// 所以最后清空列表是正确的。
|
||||
uses.clear();
|
||||
}
|
||||
|
||||
// Implementations for static members
|
||||
|
||||
@@ -182,377 +214,45 @@ auto Function::getCalleesWithNoExternalAndSelf() -> std::set<Function *> {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
// 函数克隆,后续函数级优化(内联等)需要用到
|
||||
Function * Function::clone(const std::string &suffix) const {
|
||||
std::stringstream ss;
|
||||
std::map<BasicBlock *, BasicBlock *> oldNewBlockMap;
|
||||
IRBuilder builder;
|
||||
auto newFunction = new Function(parent, type, name);
|
||||
newFunction->getEntryBlock()->setName(blocks.front()->getName());
|
||||
oldNewBlockMap.emplace(blocks.front().get(), newFunction->getEntryBlock());
|
||||
auto oldBlockListIter = std::next(blocks.begin());
|
||||
while (oldBlockListIter != blocks.end()) {
|
||||
auto newBlock = newFunction->addBasicBlock(oldBlockListIter->get()->getName());
|
||||
oldNewBlockMap.emplace(oldBlockListIter->get(), newBlock);
|
||||
oldBlockListIter++;
|
||||
}
|
||||
|
||||
for (const auto &oldNewBlockItem : oldNewBlockMap) {
|
||||
auto oldBlock = oldNewBlockItem.first;
|
||||
auto newBlock = oldNewBlockItem.second;
|
||||
for (const auto &oldPred : oldBlock->getPredecessors()) {
|
||||
newBlock->addPredecessor(oldNewBlockMap.at(oldPred));
|
||||
}
|
||||
for (const auto &oldSucc : oldBlock->getSuccessors()) {
|
||||
newBlock->addSuccessor(oldNewBlockMap.at(oldSucc));
|
||||
void Value::removeAllUses() {
|
||||
while (!uses.empty()) {
|
||||
auto use = uses.back();
|
||||
uses.pop_back();
|
||||
if (use && use->getUser()) {
|
||||
auto user = use->getUser();
|
||||
int index = use->getIndex();
|
||||
user->removeOperand(index); ///< 从User中移除该操作数
|
||||
} else {
|
||||
// 如果use或user为null,输出警告信息
|
||||
assert(use != nullptr && "Use cannot be null");
|
||||
assert(use->getUser() != nullptr && "Use's user cannot be null");
|
||||
}
|
||||
}
|
||||
|
||||
std::map<Value *, Value *> oldNewValueMap;
|
||||
std::map<Value *, bool> isAddedToCreate;
|
||||
std::map<Value *, bool> isCreated;
|
||||
std::queue<Value *> toCreate;
|
||||
|
||||
for (const auto &oldBlock : blocks) {
|
||||
for (const auto &inst : oldBlock->getInstructions()) {
|
||||
isAddedToCreate.emplace(inst.get(), false);
|
||||
isCreated.emplace(inst.get(), false);
|
||||
}
|
||||
}
|
||||
for (const auto &oldBlock : blocks) {
|
||||
for (const auto &inst : oldBlock->getInstructions()) {
|
||||
for (const auto &valueUse : inst->getOperands()) {
|
||||
auto value = valueUse->getValue();
|
||||
if (oldNewValueMap.find(value) == oldNewValueMap.end()) {
|
||||
auto oldAllocInst = dynamic_cast<AllocaInst *>(value);
|
||||
if (oldAllocInst != nullptr) {
|
||||
std::vector<Value *> dims;
|
||||
// TODO: 这里的dims用type推断
|
||||
// for (const auto &dim : oldAllocInst->getDims()) {
|
||||
// dims.emplace_back(dim->getValue());
|
||||
// }
|
||||
ss << oldAllocInst->getName() << suffix;
|
||||
auto newAllocInst =
|
||||
new AllocaInst(oldAllocInst->getType(), oldNewBlockMap.at(oldAllocInst->getParent()), ss.str());
|
||||
ss.str("");
|
||||
oldNewValueMap.emplace(oldAllocInst, newAllocInst);
|
||||
if (isAddedToCreate.find(oldAllocInst) == isAddedToCreate.end()) {
|
||||
isAddedToCreate.emplace(oldAllocInst, true);
|
||||
} else {
|
||||
isAddedToCreate.at(oldAllocInst) = true;
|
||||
}
|
||||
if (isCreated.find(oldAllocInst) == isCreated.end()) {
|
||||
isCreated.emplace(oldAllocInst, true);
|
||||
} else {
|
||||
isCreated.at(oldAllocInst) = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (inst->getKind() == Instruction::kAlloca) {
|
||||
if (oldNewValueMap.find(inst.get()) == oldNewValueMap.end()) {
|
||||
auto oldAllocInst = dynamic_cast<AllocaInst *>(inst.get());
|
||||
std::vector<Value *> dims;
|
||||
// TODO: 这里的dims用type推断
|
||||
// for (const auto &dim : oldAllocInst->getDims()) {
|
||||
// dims.emplace_back(dim->getValue());
|
||||
// }
|
||||
ss << oldAllocInst->getName() << suffix;
|
||||
auto newAllocInst =
|
||||
new AllocaInst(oldAllocInst->getType(), oldNewBlockMap.at(oldAllocInst->getParent()), ss.str());
|
||||
ss.str("");
|
||||
oldNewValueMap.emplace(oldAllocInst, newAllocInst);
|
||||
if (isAddedToCreate.find(oldAllocInst) == isAddedToCreate.end()) {
|
||||
isAddedToCreate.emplace(oldAllocInst, true);
|
||||
} else {
|
||||
isAddedToCreate.at(oldAllocInst) = true;
|
||||
}
|
||||
if (isCreated.find(oldAllocInst) == isCreated.end()) {
|
||||
isCreated.emplace(oldAllocInst, true);
|
||||
} else {
|
||||
isCreated.at(oldAllocInst) = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto &oldBlock : blocks) {
|
||||
for (const auto &inst : oldBlock->getInstructions()) {
|
||||
for (const auto &valueUse : inst->getOperands()) {
|
||||
auto value = valueUse->getValue();
|
||||
if (oldNewValueMap.find(value) == oldNewValueMap.end()) {
|
||||
auto globalValue = dynamic_cast<GlobalValue *>(value);
|
||||
auto constVariable = dynamic_cast<ConstantVariable *>(value);
|
||||
auto constantValue = dynamic_cast<ConstantValue *>(value);
|
||||
auto functionValue = dynamic_cast<Function *>(value);
|
||||
if (globalValue != nullptr || constantValue != nullptr || constVariable != nullptr ||
|
||||
functionValue != nullptr) {
|
||||
if (functionValue == this) {
|
||||
oldNewValueMap.emplace(value, newFunction);
|
||||
} else {
|
||||
oldNewValueMap.emplace(value, value);
|
||||
}
|
||||
isCreated.emplace(value, true);
|
||||
isAddedToCreate.emplace(value, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto &oldBlock : blocks) {
|
||||
for (const auto &inst : oldBlock->getInstructions()) {
|
||||
if (inst->getKind() != Instruction::kAlloca) {
|
||||
bool isReady = true;
|
||||
for (const auto &use : inst->getOperands()) {
|
||||
auto value = use->getValue();
|
||||
if (dynamic_cast<BasicBlock *>(value) == nullptr && !isCreated.at(value)) {
|
||||
isReady = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isReady) {
|
||||
toCreate.push(inst.get());
|
||||
isAddedToCreate.at(inst.get()) = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (!toCreate.empty()) {
|
||||
auto inst = dynamic_cast<Instruction *>(toCreate.front());
|
||||
toCreate.pop();
|
||||
|
||||
bool isReady = true;
|
||||
for (const auto &valueUse : inst->getOperands()) {
|
||||
auto value = dynamic_cast<Instruction *>(valueUse->getValue());
|
||||
if (value != nullptr && !isCreated.at(value)) {
|
||||
isReady = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isReady) {
|
||||
toCreate.push(inst);
|
||||
continue;
|
||||
}
|
||||
isCreated.at(inst) = true;
|
||||
switch (inst->getKind()) {
|
||||
case Instruction::kAdd:
|
||||
case Instruction::kSub:
|
||||
case Instruction::kMul:
|
||||
case Instruction::kDiv:
|
||||
case Instruction::kRem:
|
||||
case Instruction::kICmpEQ:
|
||||
case Instruction::kICmpNE:
|
||||
case Instruction::kICmpLT:
|
||||
case Instruction::kICmpGT:
|
||||
case Instruction::kICmpLE:
|
||||
case Instruction::kICmpGE:
|
||||
case Instruction::kAnd:
|
||||
case Instruction::kOr:
|
||||
case Instruction::kFAdd:
|
||||
case Instruction::kFSub:
|
||||
case Instruction::kFMul:
|
||||
case Instruction::kFDiv:
|
||||
case Instruction::kFCmpEQ:
|
||||
case Instruction::kFCmpNE:
|
||||
case Instruction::kFCmpLT:
|
||||
case Instruction::kFCmpGT:
|
||||
case Instruction::kFCmpLE:
|
||||
case Instruction::kFCmpGE: {
|
||||
auto oldBinaryInst = dynamic_cast<BinaryInst *>(inst);
|
||||
auto lhs = oldBinaryInst->getLhs();
|
||||
auto rhs = oldBinaryInst->getRhs();
|
||||
Value *newLhs;
|
||||
Value *newRhs;
|
||||
newLhs = oldNewValueMap[lhs];
|
||||
newRhs = oldNewValueMap[rhs];
|
||||
ss << oldBinaryInst->getName() << suffix;
|
||||
auto newBinaryInst = new BinaryInst(oldBinaryInst->getKind(), oldBinaryInst->getType(), newLhs, newRhs,
|
||||
oldNewBlockMap.at(oldBinaryInst->getParent()), ss.str());
|
||||
ss.str("");
|
||||
oldNewValueMap.emplace(oldBinaryInst, newBinaryInst);
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::kNeg:
|
||||
case Instruction::kNot:
|
||||
case Instruction::kFNeg:
|
||||
case Instruction::kFNot:
|
||||
case Instruction::kItoF:
|
||||
case Instruction::kFtoI: {
|
||||
auto oldUnaryInst = dynamic_cast<UnaryInst *>(inst);
|
||||
auto hs = oldUnaryInst->getOperand();
|
||||
Value *newHs;
|
||||
newHs = oldNewValueMap.at(hs);
|
||||
ss << oldUnaryInst->getName() << suffix;
|
||||
auto newUnaryInst = new UnaryInst(oldUnaryInst->getKind(), oldUnaryInst->getType(), newHs,
|
||||
oldNewBlockMap.at(oldUnaryInst->getParent()), ss.str());
|
||||
ss.str("");
|
||||
oldNewValueMap.emplace(oldUnaryInst, newUnaryInst);
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::kCall: {
|
||||
auto oldCallInst = dynamic_cast<CallInst *>(inst);
|
||||
std::vector<Value *> newArgumnts;
|
||||
for (const auto &arg : oldCallInst->getArguments()) {
|
||||
newArgumnts.emplace_back(oldNewValueMap.at(arg->getValue()));
|
||||
}
|
||||
|
||||
ss << oldCallInst->getName() << suffix;
|
||||
CallInst *newCallInst;
|
||||
newCallInst =
|
||||
new CallInst(oldCallInst->getCallee(), newArgumnts, oldNewBlockMap.at(oldCallInst->getParent()), ss.str());
|
||||
ss.str("");
|
||||
// if (oldCallInst->getCallee() != this) {
|
||||
// newCallInst = new CallInst(oldCallInst->getCallee(), newArgumnts,
|
||||
// oldNewBlockMap.at(oldCallInst->getParent()),
|
||||
// oldCallInst->getName());
|
||||
// } else {
|
||||
// newCallInst = new CallInst(newFunction, newArgumnts, oldNewBlockMap.at(oldCallInst->getParent()),
|
||||
// oldCallInst->getName());
|
||||
// }
|
||||
|
||||
oldNewValueMap.emplace(oldCallInst, newCallInst);
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::kCondBr: {
|
||||
auto oldCondBrInst = dynamic_cast<CondBrInst *>(inst);
|
||||
auto oldCond = oldCondBrInst->getCondition();
|
||||
Value *newCond;
|
||||
newCond = oldNewValueMap.at(oldCond);
|
||||
auto newCondBrInst = new CondBrInst(newCond, oldNewBlockMap.at(oldCondBrInst->getThenBlock()),
|
||||
oldNewBlockMap.at(oldCondBrInst->getElseBlock()),
|
||||
oldNewBlockMap.at(oldCondBrInst->getParent()));
|
||||
oldNewValueMap.emplace(oldCondBrInst, newCondBrInst);
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::kBr: {
|
||||
auto oldBrInst = dynamic_cast<UncondBrInst *>(inst);
|
||||
auto newBrInst =
|
||||
new UncondBrInst(oldNewBlockMap.at(oldBrInst->getBlock()), oldNewBlockMap.at(oldBrInst->getParent()));
|
||||
oldNewValueMap.emplace(oldBrInst, newBrInst);
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::kReturn: {
|
||||
auto oldReturnInst = dynamic_cast<ReturnInst *>(inst);
|
||||
auto oldRval = oldReturnInst->getReturnValue();
|
||||
Value *newRval = nullptr;
|
||||
if (oldRval != nullptr) {
|
||||
newRval = oldNewValueMap.at(oldRval);
|
||||
}
|
||||
auto newReturnInst =
|
||||
new ReturnInst(newRval, oldNewBlockMap.at(oldReturnInst->getParent()), oldReturnInst->getName());
|
||||
oldNewValueMap.emplace(oldReturnInst, newReturnInst);
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::kAlloca: {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
case Instruction::kLoad: {
|
||||
auto oldLoadInst = dynamic_cast<LoadInst *>(inst);
|
||||
auto oldPointer = oldLoadInst->getPointer();
|
||||
Value *newPointer;
|
||||
newPointer = oldNewValueMap.at(oldPointer);
|
||||
|
||||
std::vector<Value *> newIndices;
|
||||
// for (const auto &index : oldLoadInst->getIndices()) {
|
||||
// newIndices.emplace_back(oldNewValueMap.at(index->getValue()));
|
||||
// }
|
||||
ss << oldLoadInst->getName() << suffix;
|
||||
// TODO : 这里的newLoadInst的类型需要根据oldLoadInst的类型来推断
|
||||
auto newLoadInst = new LoadInst(newPointer, oldNewBlockMap.at(oldLoadInst->getParent()), ss.str());
|
||||
ss.str("");
|
||||
oldNewValueMap.emplace(oldLoadInst, newLoadInst);
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::kStore: {
|
||||
auto oldStoreInst = dynamic_cast<StoreInst *>(inst);
|
||||
auto oldPointer = oldStoreInst->getPointer();
|
||||
auto oldValue = oldStoreInst->getValue();
|
||||
Value *newPointer;
|
||||
Value *newValue;
|
||||
std::vector<Value *> newIndices;
|
||||
newPointer = oldNewValueMap.at(oldPointer);
|
||||
newValue = oldNewValueMap.at(oldValue);
|
||||
// TODO: 这里的newIndices需要根据oldStoreInst的类型来推断
|
||||
// for (const auto &index : oldStoreInst->getIndices()) {
|
||||
// newIndices.emplace_back(oldNewValueMap.at(index->getValue()));
|
||||
// }
|
||||
auto newStoreInst = new StoreInst(newValue, newPointer,
|
||||
oldNewBlockMap.at(oldStoreInst->getParent()), oldStoreInst->getName());
|
||||
oldNewValueMap.emplace(oldStoreInst, newStoreInst);
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO:复制GEP指令
|
||||
|
||||
case Instruction::kMemset: {
|
||||
auto oldMemsetInst = dynamic_cast<MemsetInst *>(inst);
|
||||
auto oldPointer = oldMemsetInst->getPointer();
|
||||
auto oldValue = oldMemsetInst->getValue();
|
||||
Value *newPointer;
|
||||
Value *newValue;
|
||||
newPointer = oldNewValueMap.at(oldPointer);
|
||||
newValue = oldNewValueMap.at(oldValue);
|
||||
|
||||
auto newMemsetInst = new MemsetInst(newPointer, oldMemsetInst->getBegin(), oldMemsetInst->getSize(), newValue,
|
||||
oldNewBlockMap.at(oldMemsetInst->getParent()), oldMemsetInst->getName());
|
||||
oldNewValueMap.emplace(oldMemsetInst, newMemsetInst);
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::kInvalid:
|
||||
case Instruction::kPhi: {
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
for (const auto &userUse : inst->getUses()) {
|
||||
auto user = userUse->getUser();
|
||||
if (!isAddedToCreate.at(user)) {
|
||||
toCreate.push(user);
|
||||
isAddedToCreate.at(user) = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &oldBlock : blocks) {
|
||||
auto newBlock = oldNewBlockMap.at(oldBlock.get());
|
||||
builder.setPosition(newBlock, newBlock->end());
|
||||
for (const auto &inst : oldBlock->getInstructions()) {
|
||||
builder.insertInst(dynamic_cast<Instruction *>(oldNewValueMap.at(inst.get())));
|
||||
}
|
||||
}
|
||||
|
||||
// for (const auto ¶m : blocks.front()->getArguments()) {
|
||||
// newFunction->getEntryBlock()->insertArgument(dynamic_cast<AllocaInst *>(oldNewValueMap.at(param)));
|
||||
// }
|
||||
for (const auto &arg : arguments) {
|
||||
auto newArg = dynamic_cast<Argument *>(oldNewValueMap.at(arg));
|
||||
if (newArg != nullptr) {
|
||||
newFunction->insertArgument(newArg);
|
||||
}
|
||||
}
|
||||
|
||||
return newFunction;
|
||||
uses.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置操作数
|
||||
*/
|
||||
void User::setOperand(unsigned index, Value *value) {
|
||||
assert(index < getNumOperands());
|
||||
operands[index]->setValue(value);
|
||||
value->addUse(operands[index]);
|
||||
void User::setOperand(unsigned index, Value *newvalue) {
|
||||
if (index >= operands.size()) {
|
||||
std::cerr << "index=" << index << ", but mOperands max size=" << operands.size() << std::endl;
|
||||
assert(index < operands.size());
|
||||
}
|
||||
std::shared_ptr<Use> olduse = operands[index];
|
||||
Value *oldValue = olduse->getValue();
|
||||
if (oldValue != newvalue) {
|
||||
// 如果新值和旧值不同,先移除旧值的使用关系
|
||||
oldValue->removeUse(olduse);
|
||||
// 设置新的操作数
|
||||
operands[index] = std::make_shared<Use>(index, this, newvalue);
|
||||
newvalue->addUse(operands[index]);
|
||||
}
|
||||
else {
|
||||
// 如果新值和旧值相同,直接更新use的索引
|
||||
operands[index]->setValue(newvalue);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 替换操作数
|
||||
@@ -565,83 +265,128 @@ void User::replaceOperand(unsigned index, Value *value) {
|
||||
value->addUse(use);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除操作数
|
||||
*/
|
||||
void User::removeOperand(unsigned index) {
|
||||
assert(index < getNumOperands() && "Index out of range in removeOperand");
|
||||
std::shared_ptr<Use> useToRemove = operands.at(index);
|
||||
Value *valueToRemove = useToRemove->getValue();
|
||||
if(valueToRemove) {
|
||||
if(valueToRemove == this) {
|
||||
std::cerr << "Cannot remove operand that is the same as the User itself." << std::endl;
|
||||
}
|
||||
valueToRemove->removeUse(useToRemove);
|
||||
}
|
||||
operands.erase(operands.begin() + index);
|
||||
unsigned newIndex = 0;
|
||||
for(auto it = operands.begin(); it != operands.end(); ++it, ++newIndex) {
|
||||
(*it)->setIndex(newIndex); // 更新剩余操作数的索引
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* phi相关函数
|
||||
*/
|
||||
|
||||
Value* PhiInst::getvalfromBlk(BasicBlock* blk){
|
||||
refreshB2VMap();
|
||||
Value* PhiInst::getValfromBlk(BasicBlock* blk) {
|
||||
refreshMap();
|
||||
if( blk2val.find(blk) != blk2val.end()) {
|
||||
return blk2val.at(blk);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BasicBlock* PhiInst::getBlkfromVal(Value* val){
|
||||
BasicBlock* PhiInst::getBlkfromVal(Value* val) {
|
||||
// 返回第一个值对应的基本块
|
||||
for(unsigned i = 0; i < vsize; i++) {
|
||||
if(getValue(i) == val) {
|
||||
return getBlock(i);
|
||||
if(getIncomingValue(i) == val) {
|
||||
return getIncomingBlock(i);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void PhiInst::delValue(Value* val){
|
||||
void PhiInst::removeIncomingValue(Value* val){
|
||||
//根据value删除对应的基本块和值
|
||||
unsigned i = 0;
|
||||
BasicBlock* blk = getBlkfromVal(val);
|
||||
if(blk == nullptr) {
|
||||
return; // 如果val没有对应的基本块,直接返回
|
||||
}
|
||||
for(i = 0; i < vsize; i++) {
|
||||
if(getValue(i) == val) {
|
||||
if(getIncomingValue(i) == val) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
removeOperand(2 * i + 1); // 删除blk
|
||||
removeOperand(2 * i); // 删除val
|
||||
vsize--;
|
||||
blk2val.erase(blk); // 删除blk2val映射
|
||||
removeIncoming(i);
|
||||
}
|
||||
|
||||
void PhiInst::delBlk(BasicBlock* blk){
|
||||
void PhiInst::removeIncomingBlock(BasicBlock* blk){
|
||||
//根据Blk删除对应的基本块和值
|
||||
unsigned i = 0;
|
||||
Value* val = getvalfromBlk(blk);
|
||||
Value* val = getValfromBlk(blk);
|
||||
if(val == nullptr) {
|
||||
return; // 如果blk没有对应的值,直接返回
|
||||
}
|
||||
for(i = 0; i < vsize; i++) {
|
||||
if(getBlock(i) == blk) {
|
||||
if(getIncomingBlock(i) == blk) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
removeOperand(2 * i + 1); // 删除blk
|
||||
removeOperand(2 * i); // 删除val
|
||||
vsize--;
|
||||
blk2val.erase(blk); // 删除blk2val映射
|
||||
removeIncoming(i);
|
||||
}
|
||||
|
||||
void PhiInst::replaceBlk(BasicBlock* newBlk, unsigned k){
|
||||
refreshB2VMap();
|
||||
BasicBlock* oldBlk = getBlock(k);
|
||||
Value* val = blk2val.at(oldBlk);
|
||||
// Value* val = blk2val.at(getBlock(k));
|
||||
// 替换基本块
|
||||
setOperand(2 * k + 1, newBlk);
|
||||
// 替换blk2val映射
|
||||
blk2val.erase(oldBlk);
|
||||
blk2val.emplace(newBlk, val);
|
||||
void PhiInst::setIncomingValue(unsigned k, Value* val) {
|
||||
assert(k < vsize && "PhiInst: index out of range");
|
||||
assert(val != nullptr && "PhiInst: value cannot be null");
|
||||
refreshMap();
|
||||
blk2val.erase(getIncomingBlock(k));
|
||||
setOperand(2 * k, val);
|
||||
blk2val[getIncomingBlock(k)] = val;
|
||||
}
|
||||
|
||||
void PhiInst::replaceold2new(BasicBlock* oldBlk, BasicBlock* newBlk){
|
||||
refreshB2VMap();
|
||||
Value* val = blk2val.at(oldBlk);
|
||||
// 替换基本块
|
||||
delBlk(oldBlk);
|
||||
void PhiInst::setIncomingBlock(unsigned k, BasicBlock* blk) {
|
||||
assert(k < vsize && "PhiInst: index out of range");
|
||||
assert(blk != nullptr && "PhiInst: block cannot be null");
|
||||
refreshMap();
|
||||
auto oldVal = getIncomingValue(k);
|
||||
blk2val.erase(getIncomingBlock(k));
|
||||
setOperand(2 * k + 1, blk);
|
||||
blk2val[blk] = oldVal;
|
||||
}
|
||||
|
||||
void PhiInst::replaceIncomingValue(Value* newVal, Value* oldVal) {
|
||||
refreshMap();
|
||||
assert(blk2val.find(getBlkfromVal(oldVal)) != blk2val.end() && "PhiInst: oldVal not found in blk2val");
|
||||
auto blk = getBlkfromVal(oldVal);
|
||||
removeIncomingValue(oldVal);
|
||||
addIncoming(newVal, blk);
|
||||
}
|
||||
|
||||
void PhiInst::replaceIncomingBlock(BasicBlock* newBlk, BasicBlock* oldBlk) {
|
||||
refreshMap();
|
||||
assert(blk2val.find(oldBlk) != blk2val.end() && "PhiInst: oldBlk not found in blk2val");
|
||||
auto val = blk2val[oldBlk];
|
||||
removeIncomingBlock(oldBlk);
|
||||
addIncoming(val, newBlk);
|
||||
}
|
||||
|
||||
void PhiInst::refreshB2VMap(){
|
||||
blk2val.clear();
|
||||
for(unsigned i = 0; i < vsize; i++) {
|
||||
blk2val.emplace(getBlock(i), getValue(i));
|
||||
}
|
||||
void PhiInst::replaceIncomingValue(Value *oldValue, Value *newValue, BasicBlock *newBlock) {
|
||||
refreshMap();
|
||||
assert(blk2val.find(getBlkfromVal(oldValue)) != blk2val.end() && "PhiInst: oldValue not found in blk2val");
|
||||
auto oldBlock = getBlkfromVal(oldValue);
|
||||
removeIncomingValue(oldValue);
|
||||
addIncoming(newValue, newBlock);
|
||||
}
|
||||
|
||||
void PhiInst::replaceIncomingBlock(BasicBlock *oldBlock, BasicBlock *newBlock, Value *newValue) {
|
||||
refreshMap();
|
||||
assert(blk2val.find(oldBlock) != blk2val.end() && "PhiInst: oldBlock not found in blk2val");
|
||||
auto oldValue = blk2val[oldBlock];
|
||||
removeIncomingBlock(oldBlock);
|
||||
addIncoming(newValue, newBlock);
|
||||
}
|
||||
|
||||
CallInst::CallInst(Function *callee, const std::vector<Value *> &args, BasicBlock *parent, const std::string &name)
|
||||
|
||||
@@ -1,19 +1,30 @@
|
||||
#include "Dom.h"
|
||||
#include <limits> // for std::numeric_limits
|
||||
#include <algorithm> // for std::set_intersection, std::reverse
|
||||
#include <iostream> // for debug output
|
||||
#include <limits> // for std::numeric_limits
|
||||
#include <queue>
|
||||
#include <functional> // for std::function
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 初始化 支配树静态 ID
|
||||
// ==============================================================
|
||||
// DominatorTreeAnalysisPass 的静态ID
|
||||
// ==============================================================
|
||||
void *DominatorTreeAnalysisPass::ID = (void *)&DominatorTreeAnalysisPass::ID;
|
||||
|
||||
// ==============================================================
|
||||
// DominatorTree 结果类的实现
|
||||
// ==============================================================
|
||||
|
||||
// 构造函数:初始化关联函数,但不进行计算
|
||||
DominatorTree::DominatorTree(Function *F) : AssociatedFunction(F) {
|
||||
// 构造时可以不计算,在分析遍运行里计算并填充
|
||||
// 构造时不需要计算,在分析遍运行里计算并填充
|
||||
}
|
||||
|
||||
// Getter 方法 (保持不变)
|
||||
const std::set<BasicBlock *> *DominatorTree::getDominators(BasicBlock *BB) const {
|
||||
auto it = Dominators.find(BB);
|
||||
if (it != Dominators.end()) {
|
||||
@@ -38,164 +49,437 @@ const std::set<BasicBlock *> *DominatorTree::getDominanceFrontier(BasicBlock *BB
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::set<BasicBlock*>* DominatorTree::getDominatorTreeChildren(BasicBlock* BB) const {
|
||||
auto it = DominatorTreeChildren.find(BB);
|
||||
if (it != DominatorTreeChildren.end()) {
|
||||
return &(it->second);
|
||||
}
|
||||
return nullptr;
|
||||
const std::set<BasicBlock *> *DominatorTree::getDominatorTreeChildren(BasicBlock *BB) const {
|
||||
auto it = DominatorTreeChildren.find(BB);
|
||||
if (it != DominatorTreeChildren.end()) {
|
||||
return &(it->second);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DominatorTree::computeDominators(Function *F) {
|
||||
// 经典的迭代算法计算支配者集合
|
||||
// TODO: 可以替换为更高效的算法,如 Lengauer-Tarjan 算法
|
||||
BasicBlock *entryBlock = F->getEntryBlock();
|
||||
// 辅助函数:打印 BasicBlock 集合 (保持不变)
|
||||
void printBBSet(const std::string &prefix, const std::set<BasicBlock *> &s) {
|
||||
if (!DEBUG)
|
||||
return;
|
||||
std::cout << prefix << "{";
|
||||
bool first = true;
|
||||
for (const auto &bb : s) {
|
||||
if (!first)
|
||||
std::cout << ", ";
|
||||
std::cout << bb->getName();
|
||||
first = false;
|
||||
}
|
||||
std::cout << "}" << std::endl;
|
||||
}
|
||||
|
||||
for (const auto &bb_ptr : F->getBasicBlocks()) {
|
||||
BasicBlock *bb = bb_ptr.get();
|
||||
// 辅助函数:计算逆后序遍历 (RPO) - 保持不变
|
||||
std::vector<BasicBlock*> DominatorTree::computeReversePostOrder(Function* F) {
|
||||
std::vector<BasicBlock*> postOrder;
|
||||
std::set<BasicBlock*> visited;
|
||||
|
||||
std::function<void(BasicBlock*)> dfs_rpo =
|
||||
[&](BasicBlock* bb) {
|
||||
visited.insert(bb);
|
||||
for (BasicBlock* succ : bb->getSuccessors()) {
|
||||
if (visited.find(succ) == visited.end()) {
|
||||
dfs_rpo(succ);
|
||||
}
|
||||
}
|
||||
postOrder.push_back(bb);
|
||||
};
|
||||
|
||||
dfs_rpo(F->getEntryBlock());
|
||||
std::reverse(postOrder.begin(), postOrder.end());
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "--- Computed RPO: ";
|
||||
for (BasicBlock* bb : postOrder) {
|
||||
std::cout << bb->getName() << " ";
|
||||
}
|
||||
std::cout << "---" << std::endl;
|
||||
}
|
||||
return postOrder;
|
||||
}
|
||||
|
||||
// computeDominators 方法 (保持不变,因为它它是独立于IDom算法的)
|
||||
void DominatorTree::computeDominators(Function *F) {
|
||||
if (DEBUG)
|
||||
std::cout << "--- Computing Dominators ---" << std::endl;
|
||||
|
||||
BasicBlock *entryBlock = F->getEntryBlock();
|
||||
std::vector<BasicBlock*> bbs_rpo = computeReversePostOrder(F);
|
||||
|
||||
for (BasicBlock *bb : bbs_rpo) {
|
||||
if (bb == entryBlock) {
|
||||
Dominators[bb].clear();
|
||||
Dominators[bb].insert(bb);
|
||||
if (DEBUG) std::cout << "Init Dominators[" << bb->getName() << "]: {" << bb->getName() << "}" << std::endl;
|
||||
} else {
|
||||
for (const auto &all_bb_ptr : F->getBasicBlocks()) {
|
||||
Dominators[bb].insert(all_bb_ptr.get());
|
||||
Dominators[bb].clear();
|
||||
for (BasicBlock *all_bb : bbs_rpo) {
|
||||
Dominators[bb].insert(all_bb);
|
||||
}
|
||||
if (DEBUG) {
|
||||
std::cout << "Init Dominators[" << bb->getName() << "]: ";
|
||||
printBBSet("", Dominators[bb]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool changed = true;
|
||||
int iteration = 0;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
for (const auto &bb_ptr : F->getBasicBlocks()) {
|
||||
BasicBlock *bb = bb_ptr.get();
|
||||
if (bb == entryBlock)
|
||||
continue;
|
||||
iteration++;
|
||||
if (DEBUG) std::cout << "Iteration " << iteration << std::endl;
|
||||
|
||||
for (BasicBlock *bb : bbs_rpo) {
|
||||
if (bb == entryBlock) continue;
|
||||
|
||||
std::set<BasicBlock *> newDom;
|
||||
bool firstPred = true;
|
||||
bool firstPredProcessed = false;
|
||||
|
||||
for (BasicBlock *pred : bb->getPredecessors()) {
|
||||
if (Dominators.count(pred)) {
|
||||
if (firstPred) {
|
||||
newDom = Dominators[pred];
|
||||
firstPred = false;
|
||||
} else {
|
||||
std::set<BasicBlock *> intersection;
|
||||
std::set_intersection(newDom.begin(), newDom.end(), Dominators[pred].begin(), Dominators[pred].end(),
|
||||
std::inserter(intersection, intersection.begin()));
|
||||
newDom = intersection;
|
||||
}
|
||||
if(DEBUG){
|
||||
std::cout << " Processing predecessor: " << pred->getName() << std::endl;
|
||||
}
|
||||
if (!firstPredProcessed) {
|
||||
newDom = Dominators[pred];
|
||||
firstPredProcessed = true;
|
||||
} else {
|
||||
std::set<BasicBlock *> intersection;
|
||||
std::set_intersection(newDom.begin(), newDom.end(), Dominators[pred].begin(), Dominators[pred].end(),
|
||||
std::inserter(intersection, intersection.begin()));
|
||||
newDom = intersection;
|
||||
}
|
||||
}
|
||||
newDom.insert(bb);
|
||||
|
||||
if (newDom != Dominators[bb]) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Dominators[" << bb->getName() << "] changed from ";
|
||||
printBBSet("", Dominators[bb]);
|
||||
std::cout << " to ";
|
||||
printBBSet("", newDom);
|
||||
}
|
||||
Dominators[bb] = newDom;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DEBUG)
|
||||
std::cout << "--- Dominators Computation Finished ---" << std::endl;
|
||||
}
|
||||
|
||||
void DominatorTree::computeIDoms(Function *F) {
|
||||
// 采用与之前类似的简化实现。TODO:Lengauer-Tarjan等算法。
|
||||
BasicBlock *entryBlock = F->getEntryBlock();
|
||||
IDoms[entryBlock] = nullptr;
|
||||
// ==============================================================
|
||||
// Lengauer-Tarjan 算法辅助数据结构和函数 (私有成员)
|
||||
// ==============================================================
|
||||
|
||||
for (const auto &bb_ptr : F->getBasicBlocks()) {
|
||||
BasicBlock *bb = bb_ptr.get();
|
||||
if (bb == entryBlock)
|
||||
continue;
|
||||
|
||||
BasicBlock *currentIDom = nullptr;
|
||||
const std::set<BasicBlock *> *domsOfBB = getDominators(bb);
|
||||
if (!domsOfBB)
|
||||
continue;
|
||||
|
||||
for (BasicBlock *D : *domsOfBB) {
|
||||
if (D == bb)
|
||||
continue;
|
||||
|
||||
bool isCandidateIDom = true;
|
||||
for (BasicBlock *candidate : *domsOfBB) {
|
||||
if (candidate == bb || candidate == D)
|
||||
continue;
|
||||
const std::set<BasicBlock *> *domsOfCandidate = getDominators(candidate);
|
||||
if (domsOfCandidate && domsOfCandidate->count(D) == 0 && domsOfBB->count(candidate)) {
|
||||
isCandidateIDom = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isCandidateIDom) {
|
||||
currentIDom = D;
|
||||
break;
|
||||
}
|
||||
// DFS 遍历,填充 dfnum_map, vertex_vec, parent_map
|
||||
// 对应用户代码的 dfs 函数
|
||||
void DominatorTree::dfs_lt_helper(BasicBlock* u) {
|
||||
dfnum_map[u] = df_counter;
|
||||
if (df_counter >= vertex_vec.size()) { // 动态调整大小
|
||||
vertex_vec.resize(df_counter + 1);
|
||||
}
|
||||
vertex_vec[df_counter] = u;
|
||||
if (DEBUG) std::cout << " DFS: Visiting " << u->getName() << ", dfnum = " << df_counter << std::endl;
|
||||
df_counter++;
|
||||
|
||||
for (BasicBlock* v : u->getSuccessors()) {
|
||||
if (dfnum_map.find(v) == dfnum_map.end()) { // 如果 v 未访问过
|
||||
parent_map[v] = u;
|
||||
if (DEBUG) std::cout << " DFS: Setting parent[" << v->getName() << "] = " << u->getName() << std::endl;
|
||||
dfs_lt_helper(v);
|
||||
}
|
||||
}
|
||||
IDoms[bb] = currentIDom;
|
||||
}
|
||||
}
|
||||
|
||||
// 并查集:找到集合的代表,并进行路径压缩
|
||||
// 同时更新 label,确保 label[i] 总是指向其祖先链中 sdom_map 最小的节点
|
||||
// 对应用户代码的 find 函数,也包含了 eval 的逻辑
|
||||
BasicBlock* DominatorTree::evalAndCompress_lt_helper(BasicBlock* i) {
|
||||
if (DEBUG) std::cout << " Eval: Processing " << i->getName() << std::endl;
|
||||
// 如果 i 是根 (ancestor_map[i] == nullptr)
|
||||
if (ancestor_map.find(i) == ancestor_map.end() || ancestor_map[i] == nullptr) {
|
||||
if (DEBUG) std::cout << " Eval: " << i->getName() << " is root, returning itself." << std::endl;
|
||||
return i; // 根节点自身就是路径上sdom最小的,因为它没有祖先
|
||||
}
|
||||
|
||||
// 如果 i 的祖先不是根,则递归查找并进行路径压缩
|
||||
BasicBlock* root_ancestor = evalAndCompress_lt_helper(ancestor_map[i]);
|
||||
|
||||
// 路径压缩时,根据 sdom_map 比较并更新 label_map
|
||||
// 确保 label_map[i] 存储的是 i 到 root_ancestor 路径上 sdom_map 最小的节点
|
||||
// 注意:这里的 ancestor_map[i] 已经被递归调用压缩过一次了,所以是root_ancestor的旧路径
|
||||
// 应该比较的是 label_map[ancestor_map[i]] 和 label_map[i]
|
||||
if (sdom_map.count(label_map[ancestor_map[i]]) && // 确保 label_map[ancestor_map[i]] 存在 sdom
|
||||
sdom_map.count(label_map[i]) && // 确保 label_map[i] 存在 sdom
|
||||
dfnum_map[sdom_map[label_map[ancestor_map[i]]]] < dfnum_map[sdom_map[label_map[i]]]) {
|
||||
if (DEBUG) std::cout << " Eval: Updating label for " << i->getName() << " from "
|
||||
<< label_map[i]->getName() << " to " << label_map[ancestor_map[i]]->getName() << std::endl;
|
||||
label_map[i] = label_map[ancestor_map[i]];
|
||||
}
|
||||
|
||||
ancestor_map[i] = root_ancestor; // 执行路径压缩:将 i 直接指向其所属集合的根
|
||||
if (DEBUG) std::cout << " Eval: Path compression for " << i->getName() << ", new ancestor = "
|
||||
<< (root_ancestor ? root_ancestor->getName() : "nullptr") << std::endl;
|
||||
|
||||
return label_map[i]; // <-- **将这里改为返回 label_map[i]**
|
||||
}
|
||||
|
||||
// Link 函数:将 v 加入 u 的 DFS 树子树中 (实际上是并查集操作)
|
||||
// 对应用户代码的 fa[u] = fth[u];
|
||||
void DominatorTree::link_lt_helper(BasicBlock* u_parent, BasicBlock* v_child) {
|
||||
ancestor_map[v_child] = u_parent; // 设置并查集父节点
|
||||
label_map[v_child] = v_child; // 初始化 label 为自身
|
||||
if (DEBUG) std::cout << " Link: " << v_child->getName() << " linked to " << u_parent->getName() << std::endl;
|
||||
}
|
||||
|
||||
// ==============================================================
|
||||
// Lengauer-Tarjan 算法实现 computeIDoms
|
||||
// ==============================================================
|
||||
void DominatorTree::computeIDoms(Function *F) {
|
||||
if (DEBUG) std::cout << "--- Computing Immediate Dominators (IDoms) using Lengauer-Tarjan ---" << std::endl;
|
||||
|
||||
BasicBlock *entryBlock = F->getEntryBlock();
|
||||
|
||||
// 1. 初始化所有 LT 相关的数据结构
|
||||
dfnum_map.clear();
|
||||
vertex_vec.clear();
|
||||
parent_map.clear();
|
||||
sdom_map.clear();
|
||||
idom_map.clear();
|
||||
bucket_map.clear();
|
||||
ancestor_map.clear();
|
||||
label_map.clear();
|
||||
df_counter = 0; // DFS 计数器从 0 开始
|
||||
|
||||
// 预分配 vertex_vec 的大小,避免频繁resize
|
||||
vertex_vec.resize(F->getBasicBlocks().size() + 1);
|
||||
// 在 DFS 遍历之前,先为所有基本块初始化 sdom 和 label
|
||||
// 这是 Lengauer-Tarjan 算法的要求,确保所有节点在 Phase 2 开始前都在 map 中
|
||||
for (auto &bb_ptr : F->getBasicBlocks()) {
|
||||
BasicBlock* bb = bb_ptr.get();
|
||||
sdom_map[bb] = bb; // sdom(bb) 初始化为 bb 自身
|
||||
label_map[bb] = bb; // label(bb) 初始化为 bb 自身 (用于 Union-Find 的路径压缩)
|
||||
}
|
||||
// 确保入口块也被正确初始化(如果它不在 F->getBasicBlocks() 的正常迭代中)
|
||||
sdom_map[entryBlock] = entryBlock;
|
||||
label_map[entryBlock] = entryBlock;
|
||||
// Phase 1: DFS 遍历并预处理
|
||||
// 对应用户代码的 dfs(st)
|
||||
dfs_lt_helper(entryBlock);
|
||||
idom_map[entryBlock] = nullptr; // 入口块没有即时支配者
|
||||
if (DEBUG) std::cout << " IDom[" << entryBlock->getName() << "] = nullptr" << std::endl;
|
||||
|
||||
if (DEBUG) std::cout << " Sdom[" << entryBlock->getName() << "] = " << entryBlock->getName() << std::endl;
|
||||
|
||||
// 初始化并查集的祖先和 label
|
||||
for (auto const& [bb_key, dfn_val] : dfnum_map) {
|
||||
ancestor_map[bb_key] = nullptr; // 初始为独立集合的根
|
||||
label_map[bb_key] = bb_key; // 初始 label 为自身
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " --- DFS Phase Complete ---" << std::endl;
|
||||
std::cout << " dfnum_map:" << std::endl;
|
||||
for (auto const& [bb, dfn] : dfnum_map) {
|
||||
std::cout << " " << bb->getName() << " -> " << dfn << std::endl;
|
||||
}
|
||||
std::cout << " vertex_vec (by dfnum):" << std::endl;
|
||||
for (size_t k = 0; k < df_counter; ++k) {
|
||||
if (vertex_vec[k]) std::cout << " [" << k << "] -> " << vertex_vec[k]->getName() << std::endl;
|
||||
}
|
||||
std::cout << " parent_map:" << std::endl;
|
||||
for (auto const& [child, parent] : parent_map) {
|
||||
std::cout << " " << child->getName() << " -> " << (parent ? parent->getName() : "nullptr") << std::endl;
|
||||
}
|
||||
std::cout << " ------------------------" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
// Phase 2: 计算半支配者 (sdom)
|
||||
// 对应用户代码的 for (int i = dfc; i >= 2; --i) 循环的上半部分
|
||||
// 按照 DFS 编号递减的顺序遍历所有节点 (除了 entryBlock,它的 DFS 编号是 0)
|
||||
if (DEBUG) std::cout << "--- Phase 2: Computing Semi-Dominators (sdom) ---" << std::endl;
|
||||
for (int i = df_counter - 1; i >= 1; --i) { // 从 DFS 编号最大的节点开始,到 1
|
||||
BasicBlock* w = vertex_vec[i]; // 当前处理的节点
|
||||
if (DEBUG) std::cout << " Processing node w: " << w->getName() << " (dfnum=" << i << ")" << std::endl;
|
||||
|
||||
|
||||
// 对于 w 的每个前驱 v
|
||||
for (BasicBlock* v : w->getPredecessors()) {
|
||||
if (DEBUG) std::cout << " Considering predecessor v: " << v->getName() << std::endl;
|
||||
// 如果前驱 v 未被 DFS 访问过 (即不在 dfnum_map 中),则跳过
|
||||
if (dfnum_map.find(v) == dfnum_map.end()) {
|
||||
if (DEBUG) std::cout << " Predecessor " << v->getName() << " not in DFS tree, skipping." << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 调用 evalAndCompress 来找到 v 在其 DFS 树祖先链上具有最小 sdom 的节点
|
||||
BasicBlock* u_with_min_sdom_on_path = evalAndCompress_lt_helper(v);
|
||||
if (DEBUG) std::cout << " Eval(" << v->getName() << ") returned "
|
||||
<< u_with_min_sdom_on_path->getName() << std::endl;
|
||||
if (DEBUG && sdom_map.count(u_with_min_sdom_on_path) && sdom_map.count(w)) {
|
||||
std::cout << " Comparing sdom: dfnum[" << sdom_map[u_with_min_sdom_on_path]->getName() << "] (" << dfnum_map[sdom_map[u_with_min_sdom_on_path]]
|
||||
<< ") vs dfnum[" << sdom_map[w]->getName() << "] (" << dfnum_map[sdom_map[w]] << ")" << std::endl;
|
||||
}
|
||||
// 比较 sdom(u) 和 sdom(w)
|
||||
if (sdom_map.count(u_with_min_sdom_on_path) && sdom_map.count(w) &&
|
||||
dfnum_map[sdom_map[u_with_min_sdom_on_path]] < dfnum_map[sdom_map[w]]) {
|
||||
if (DEBUG) std::cout << " Updating sdom[" << w->getName() << "] from "
|
||||
<< sdom_map[w]->getName() << " to "
|
||||
<< sdom_map[u_with_min_sdom_on_path]->getName() << std::endl;
|
||||
sdom_map[w] = sdom_map[u_with_min_sdom_on_path]; // 更新 sdom(w)
|
||||
if (DEBUG) std::cout << " Sdom update applied. New sdom[" << w->getName() << "] = " << sdom_map[w]->getName() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 将 w 加入 sdom(w) 对应的桶中
|
||||
bucket_map[sdom_map[w]].push_back(w);
|
||||
if (DEBUG) std::cout << " Adding " << w->getName() << " to bucket of sdom(" << w->getName() << "): "
|
||||
<< sdom_map[w]->getName() << std::endl;
|
||||
|
||||
// 将 w 的父节点加入并查集 (link 操作)
|
||||
if (parent_map.count(w) && parent_map[w] != nullptr) {
|
||||
link_lt_helper(parent_map[w], w);
|
||||
}
|
||||
|
||||
// Phase 3-part 1: 处理 parent[w] 的桶中所有节点,确定部分 idom
|
||||
if (parent_map.count(w) && parent_map[w] != nullptr) {
|
||||
BasicBlock* p = parent_map[w]; // p 是 w 的父节点
|
||||
if (DEBUG) std::cout << " Processing bucket for parent " << p->getName() << std::endl;
|
||||
|
||||
// 注意:这里需要复制桶的内容,因为原始桶在循环中会被clear
|
||||
std::vector<BasicBlock*> nodes_in_p_bucket_copy = bucket_map[p];
|
||||
for (BasicBlock* y : nodes_in_p_bucket_copy) {
|
||||
if (DEBUG) std::cout << " Processing node y from bucket: " << y->getName() << std::endl;
|
||||
// 找到 y 在其 DFS 树祖先链上具有最小 sdom 的节点
|
||||
BasicBlock* u = evalAndCompress_lt_helper(y);
|
||||
if (DEBUG) std::cout << " Eval(" << y->getName() << ") returned " << u->getName() << std::endl;
|
||||
|
||||
// 确定 idom(y)
|
||||
// if sdom(eval(y)) == sdom(parent(w)), then idom(y) = parent(w)
|
||||
// else idom(y) = eval(y)
|
||||
if (sdom_map.count(u) && sdom_map.count(p) &&
|
||||
dfnum_map[sdom_map[u]] < dfnum_map[sdom_map[p]]) {
|
||||
idom_map[y] = u; // 确定的 idom
|
||||
if (DEBUG) std::cout << " IDom[" << y->getName() << "] set to " << u->getName() << std::endl;
|
||||
} else {
|
||||
idom_map[y] = p; // p 是 y 的 idom
|
||||
if (DEBUG) std::cout << " IDom[" << y->getName() << "] set to " << p->getName() << std::endl;
|
||||
}
|
||||
}
|
||||
bucket_map[p].clear(); // 清空桶,防止重复处理
|
||||
if (DEBUG) std::cout << " Cleared bucket for parent " << p->getName() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 3-part 2: 最终确定 idom (处理那些 idom != sdom 的节点)
|
||||
if (DEBUG) std::cout << "--- Phase 3: Finalizing Immediate Dominators (idom) ---" << std::endl;
|
||||
for (int i = 1; i < df_counter; ++i) { // 从 DFS 编号最小的节点 (除了 entryBlock) 开始
|
||||
BasicBlock* w = vertex_vec[i];
|
||||
if (DEBUG) std::cout << " Finalizing node w: " << w->getName() << std::endl;
|
||||
if (idom_map.count(w) && sdom_map.count(w) && idom_map[w] != sdom_map[w]) {
|
||||
// idom[w] 的 idom 是其真正的 idom
|
||||
if (DEBUG) std::cout << " idom[" << w->getName() << "] (" << idom_map[w]->getName()
|
||||
<< ") != sdom[" << w->getName() << "] (" << sdom_map[w]->getName() << ")" << std::endl;
|
||||
if (idom_map.count(idom_map[w])) {
|
||||
idom_map[w] = idom_map[idom_map[w]];
|
||||
if (DEBUG) std::cout << " Updating idom[" << w->getName() << "] to idom(idom(w)): "
|
||||
<< idom_map[w]->getName() << std::endl;
|
||||
} else {
|
||||
if (DEBUG) std::cout << " Warning: idom(idom(" << w->getName() << ")) not found, leaving idom[" << w->getName() << "] as is." << std::endl;
|
||||
}
|
||||
}
|
||||
if (DEBUG) {
|
||||
std::cout << " Final IDom[" << w->getName() << "] = " << (idom_map[w] ? idom_map[w]->getName() : "nullptr") << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 将计算结果从 idom_map 存储到 DominatorTree 的成员变量 IDoms 中
|
||||
IDoms = idom_map;
|
||||
|
||||
if (DEBUG) std::cout << "--- Immediate Dominators Computation Finished ---" << std::endl;
|
||||
}
|
||||
|
||||
// ==============================================================
|
||||
// computeDominanceFrontiers 和 computeDominatorTreeChildren (保持不变)
|
||||
// ==============================================================
|
||||
|
||||
void DominatorTree::computeDominanceFrontiers(Function *F) {
|
||||
// 经典的支配边界计算算法
|
||||
if (DEBUG)
|
||||
std::cout << "--- Computing Dominance Frontiers ---" << std::endl;
|
||||
|
||||
for (const auto &bb_ptr_X : F->getBasicBlocks()) {
|
||||
BasicBlock *X = bb_ptr_X.get();
|
||||
DominanceFrontiers[X].clear();
|
||||
|
||||
for (BasicBlock *Y : X->getSuccessors()) {
|
||||
const std::set<BasicBlock *> *domsOfY = getDominators(Y);
|
||||
if (domsOfY && domsOfY->find(X) == domsOfY->end()) {
|
||||
DominanceFrontiers[X].insert(Y);
|
||||
}
|
||||
}
|
||||
|
||||
const std::set<BasicBlock *> *domsOfX = getDominators(X);
|
||||
if (!domsOfX)
|
||||
continue;
|
||||
for (const auto &bb_ptr_Z : F->getBasicBlocks()) {
|
||||
BasicBlock *Z = bb_ptr_Z.get();
|
||||
if (Z == X)
|
||||
continue;
|
||||
const std::set<BasicBlock *> *domsOfZ = getDominators(Z);
|
||||
if (domsOfZ && domsOfZ->count(X) && Z != X) {
|
||||
|
||||
for (BasicBlock *Y : Z->getSuccessors()) {
|
||||
const std::set<BasicBlock *> *domsOfY = getDominators(Y);
|
||||
if (domsOfY && domsOfY->find(X) == domsOfY->end()) {
|
||||
DominanceFrontiers[X].insert(Y);
|
||||
}
|
||||
if (!domsOfZ || domsOfZ->find(X) == domsOfZ->end()) { // Z 不被 X 支配
|
||||
continue;
|
||||
}
|
||||
|
||||
for (BasicBlock *Y : Z->getSuccessors()) {
|
||||
const std::set<BasicBlock *> *domsOfY = getDominators(Y);
|
||||
// 如果 Y == X,或者 Y 不被 X 严格支配 (即 Y 不被 X 支配)
|
||||
if (Y == X || (domsOfY && domsOfY->find(X) == domsOfY->end())) {
|
||||
DominanceFrontiers[X].insert(Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DEBUG) {
|
||||
std::cout << " DF(" << X->getName() << "): ";
|
||||
printBBSet("", DominanceFrontiers[X]);
|
||||
}
|
||||
}
|
||||
if (DEBUG)
|
||||
std::cout << "--- Dominance Frontiers Computation Finished ---" << std::endl;
|
||||
}
|
||||
|
||||
void DominatorTree::computeDominatorTreeChildren(Function *F) {
|
||||
if (DEBUG)
|
||||
std::cout << "--- Computing Dominator Tree Children ---" << std::endl;
|
||||
// 首先清空,确保重新计算时是空的
|
||||
for (auto &bb_ptr : F->getBasicBlocks()) {
|
||||
DominatorTreeChildren[bb_ptr.get()].clear();
|
||||
}
|
||||
|
||||
for (auto &bb_ptr : F->getBasicBlocks()) {
|
||||
BasicBlock *B = bb_ptr.get();
|
||||
auto it = getImmediateDominator(B);
|
||||
if (it != nullptr) {
|
||||
BasicBlock *A = it;
|
||||
if (A) {
|
||||
DominatorTreeChildren[A].insert(B);
|
||||
BasicBlock *A = getImmediateDominator(B); // A 是 B 的即时支配者
|
||||
|
||||
if (A) { // 如果 B 有即时支配者 A (即 B 不是入口块)
|
||||
DominatorTreeChildren[A].insert(B);
|
||||
if (DEBUG) {
|
||||
std::cout << " " << B->getName() << " is child of " << A->getName() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DEBUG)
|
||||
std::cout << "--- Dominator Tree Children Computation Finished ---" << std::endl;
|
||||
}
|
||||
|
||||
// ==============================================================
|
||||
// DominatorTreeAnalysisPass 的实现
|
||||
// DominatorTreeAnalysisPass 的实现 (保持不变)
|
||||
// ==============================================================
|
||||
|
||||
|
||||
bool DominatorTreeAnalysisPass::runOnFunction(Function* F, AnalysisManager &AM) {
|
||||
bool DominatorTreeAnalysisPass::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
// 每次运行时清空旧数据,确保重新计算
|
||||
CurrentDominatorTree = std::make_unique<DominatorTree>(F);
|
||||
|
||||
CurrentDominatorTree->computeDominators(F);
|
||||
CurrentDominatorTree->computeIDoms(F);
|
||||
CurrentDominatorTree->computeIDoms(F); // 修正后的LT算法
|
||||
CurrentDominatorTree->computeDominanceFrontiers(F);
|
||||
CurrentDominatorTree->computeDominatorTreeChildren(F);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<AnalysisResultBase> DominatorTreeAnalysisPass::getResult() {
|
||||
// 返回计算好的 DominatorTree 实例,所有权转移给 AnalysisManager
|
||||
return std::move(CurrentDominatorTree);
|
||||
}
|
||||
|
||||
|
||||
79
src/midend/Pass/Optimize/BuildCFG.cpp
Normal file
79
src/midend/Pass/Optimize/BuildCFG.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#include "BuildCFG.h"
|
||||
#include "Dom.h"
|
||||
#include "Liveness.h"
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
void *BuildCFG::ID = (void *)&BuildCFG::ID; // 定义唯一的 Pass ID
|
||||
|
||||
// 声明Pass的分析使用
|
||||
void BuildCFG::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
|
||||
// BuildCFG不依赖其他分析
|
||||
// analysisDependencies.insert(&DominatorTreeAnalysisPass::ID); // 错误的例子
|
||||
|
||||
// BuildCFG会使所有依赖于CFG的分析结果失效,所以它必须声明这些失效
|
||||
analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID);
|
||||
analysisInvalidations.insert(&LivenessAnalysisPass::ID);
|
||||
}
|
||||
|
||||
bool BuildCFG::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
if (DEBUG) {
|
||||
std::cout << "Running BuildCFG pass on function: " << F->getName() << std::endl;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
|
||||
// 1. 清空所有基本块的前驱和后继列表
|
||||
for (auto &bb : F->getBasicBlocks()) {
|
||||
bb->clearPredecessors();
|
||||
bb->clearSuccessors();
|
||||
}
|
||||
|
||||
// 2. 遍历每个基本块,重建CFG
|
||||
for (auto &bb : F->getBasicBlocks()) {
|
||||
// 获取基本块的最后一条指令
|
||||
auto &inst = *bb->terminator();
|
||||
Instruction *termInst = inst.get();
|
||||
// 确保基本块有终结指令
|
||||
if (!termInst) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 根据终结指令类型,建立前驱后继关系
|
||||
if (termInst->isBranch()) {
|
||||
// 无条件跳转
|
||||
if (termInst->isUnconditional()) {
|
||||
auto brInst = dynamic_cast<UncondBrInst *>(termInst);
|
||||
BasicBlock *succ = dynamic_cast<BasicBlock *>(brInst->getBlock());
|
||||
assert(succ && "Branch instruction's target must be a BasicBlock");
|
||||
bb->addSuccessor(succ);
|
||||
succ->addPredecessor(bb.get());
|
||||
changed = true;
|
||||
|
||||
// 条件跳转
|
||||
} else if (termInst->isConditional()) {
|
||||
auto brInst = dynamic_cast<CondBrInst *>(termInst);
|
||||
BasicBlock *trueSucc = dynamic_cast<BasicBlock *>(brInst->getThenBlock());
|
||||
BasicBlock *falseSucc = dynamic_cast<BasicBlock *>(brInst->getElseBlock());
|
||||
|
||||
assert(trueSucc && falseSucc && "Branch instruction's targets must be BasicBlocks");
|
||||
|
||||
bb->addSuccessor(trueSucc);
|
||||
trueSucc->addPredecessor(bb.get());
|
||||
bb->addSuccessor(falseSucc);
|
||||
falseSucc->addPredecessor(bb.get());
|
||||
changed = true;
|
||||
}
|
||||
} else if (auto retInst = dynamic_cast<ReturnInst *>(termInst)) {
|
||||
// RetInst没有后继,无需处理
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
143
src/midend/Pass/Optimize/LargeArrayToGlobal.cpp
Normal file
143
src/midend/Pass/Optimize/LargeArrayToGlobal.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
#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);
|
||||
|
||||
// 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) {
|
||||
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
|
||||
@@ -60,7 +60,7 @@ void Mem2RegContext::run(Function *func, AnalysisManager *AM) {
|
||||
}
|
||||
|
||||
// 从入口基本块开始,对支配树进行 DFS 遍历,进行变量重命名
|
||||
renameVariables(nullptr, func->getEntryBlock()); // 第一个参数 alloca 在这里不使用,因为是递归入口点
|
||||
renameVariables(func->getEntryBlock()); // 第一个参数 alloca 在这里不使用,因为是递归入口点
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 阶段4: 清理
|
||||
@@ -209,16 +209,21 @@ void Mem2RegContext::insertPhis(AllocaInst *alloca, const std::unordered_set<Bas
|
||||
}
|
||||
|
||||
// 对支配树进行深度优先遍历,重命名变量并替换 load/store 指令
|
||||
void Mem2RegContext::renameVariables(AllocaInst *currentAlloca, BasicBlock *currentBB) {
|
||||
// 维护一个局部栈,用于存储当前基本块中为 Phi 和 Store 创建的 SSA 值,以便在退出时弹出
|
||||
std::stack<Value *> localStackPushed;
|
||||
// 移除了 AllocaInst *currentAlloca 参数,因为这个函数是为整个基本块处理所有可提升的 Alloca
|
||||
void Mem2RegContext::renameVariables(BasicBlock *currentBB) {
|
||||
// 1. 在函数开始时,记录每个 promotableAlloca 的当前栈深度。
|
||||
// 这将用于在函数返回时精确地回溯栈状态。
|
||||
std::map<AllocaInst *, size_t> originalStackSizes;
|
||||
for (auto alloca : promotableAllocas) {
|
||||
originalStackSizes[alloca] = allocaToValueStackMap[alloca].size();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 处理当前基本块的指令
|
||||
// --------------------------------------------------------------------
|
||||
for (auto instIter = currentBB->getInstructions().begin(); instIter != currentBB->getInstructions().end();) {
|
||||
Instruction *inst = instIter->get();
|
||||
bool instDeleted = false;
|
||||
bool instDeleted = false;
|
||||
|
||||
// 处理 Phi 指令 (如果是当前 alloca 的 Phi)
|
||||
if (auto phiInst = dynamic_cast<PhiInst *>(inst)) {
|
||||
@@ -227,55 +232,69 @@ void Mem2RegContext::renameVariables(AllocaInst *currentAlloca, BasicBlock *curr
|
||||
if (allocaToPhiMap[alloca].count(currentBB) && allocaToPhiMap[alloca][currentBB] == phiInst) {
|
||||
// 为 Phi 指令的输出创建一个新的 SSA 值,并压入值栈
|
||||
allocaToValueStackMap[alloca].push(phiInst);
|
||||
localStackPushed.push(phiInst); // 记录以便弹出
|
||||
break; // 找到对应的 alloca,处理下一个指令
|
||||
if (DEBUG) {
|
||||
std::cout << "Mem2Reg: Pushed Phi " << (phiInst->getName().empty() ? "anonymous" : phiInst->getName()) << " for alloca " << alloca->getName()
|
||||
<< ". Stack size: " << allocaToValueStackMap[alloca].size() << std::endl;
|
||||
}
|
||||
break; // 找到对应的 alloca,处理下一个指令
|
||||
}
|
||||
}
|
||||
}
|
||||
// 处理 LoadInst
|
||||
else if (auto loadInst = dynamic_cast<LoadInst *>(inst)) {
|
||||
// 检查这个 LoadInst 是否是为某个可提升的 alloca
|
||||
for (auto alloca : promotableAllocas) {
|
||||
if (loadInst->getPointer() == alloca) {
|
||||
// loadInst->getPointer() 返回 AllocaInst*
|
||||
// 将 LoadInst 的所有用途替换为当前 alloca 值栈顶部的 SSA 值
|
||||
// 检查 LoadInst 的指针是否直接是 alloca,或者是指向 alloca 的 GEP
|
||||
Value *ptrOperand = loadInst->getPointer();
|
||||
if (ptrOperand == alloca || (dynamic_cast<GetElementPtrInst *>(ptrOperand) &&
|
||||
dynamic_cast<GetElementPtrInst *>(ptrOperand)->getBasePointer() == alloca)) {
|
||||
assert(!allocaToValueStackMap[alloca].empty() && "Value stack empty for alloca during load replacement!");
|
||||
if(DEBUG){
|
||||
std::cout << "Mem2Reg: Replacing load " << loadInst->getPointer()->getName() << " with SSA value." << std::endl;
|
||||
if (DEBUG) {
|
||||
std::cout << "Mem2Reg: Replacing load "
|
||||
<< (ptrOperand->getName().empty() ? "anonymous" : ptrOperand->getName()) << " with SSA value "
|
||||
<< (allocaToValueStackMap[alloca].top()->getName().empty()
|
||||
? "anonymous"
|
||||
: allocaToValueStackMap[alloca].top()->getName())
|
||||
<< " for alloca " << alloca->getName() << std::endl;
|
||||
std::cout << "Mem2Reg: allocaToValueStackMap[" << alloca->getName()
|
||||
<< "] size: " << allocaToValueStackMap[alloca].size() << std::endl;
|
||||
}
|
||||
loadInst->replaceAllUsesWith(allocaToValueStackMap[alloca].top());
|
||||
instIter = SysYIROptUtils::usedelete(instIter);
|
||||
instDeleted = true;
|
||||
// std::cerr << "Mem2Reg: Replaced load " << loadInst->name() << " with SSA value." << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 处理 StoreInst
|
||||
else if (auto storeInst = dynamic_cast<StoreInst *>(inst)) {
|
||||
// 检查这个 StoreInst 是否是为某个可提升的 alloca
|
||||
for (auto alloca : promotableAllocas) {
|
||||
if (storeInst->getPointer() == alloca) {
|
||||
// 假设 storeInst->getPointer() 返回 AllocaInst*
|
||||
// 将 StoreInst 存储的值作为新的 SSA 值,压入值栈
|
||||
if(DEBUG){
|
||||
std::cout << "Mem2Reg: Replacing store to " << storeInst->getPointer()->getName() << " with SSA value." << std::endl;
|
||||
// 检查 StoreInst 的指针是否直接是 alloca,或者是指向 alloca 的 GEP
|
||||
Value *ptrOperand = storeInst->getPointer();
|
||||
if (ptrOperand == alloca || (dynamic_cast<GetElementPtrInst *>(ptrOperand) &&
|
||||
dynamic_cast<GetElementPtrInst *>(ptrOperand)->getBasePointer() == alloca)) {
|
||||
if (DEBUG) {
|
||||
std::cout << "Mem2Reg: Replacing store to "
|
||||
<< (ptrOperand->getName().empty() ? "anonymous" : ptrOperand->getName()) << " with SSA value "
|
||||
<< (storeInst->getValue()->getName().empty() ? "anonymous" : storeInst->getValue()->getName())
|
||||
<< " for alloca " << alloca->getName() << std::endl;
|
||||
std::cout << "Mem2Reg: allocaToValueStackMap[" << alloca->getName()
|
||||
<< "] size before push: " << allocaToValueStackMap[alloca].size() << std::endl;
|
||||
}
|
||||
allocaToValueStackMap[alloca].push(storeInst->getValue());
|
||||
localStackPushed.push(storeInst->getValue()); // 记录以便弹出
|
||||
instIter = SysYIROptUtils::usedelete(instIter);
|
||||
instDeleted = true;
|
||||
// std::cerr << "Mem2Reg: Replaced store to " << storeInst->ptr()->name() << " with SSA value." << std::endl;
|
||||
if (DEBUG) {
|
||||
std::cout << "Mem2Reg: allocaToValueStackMap[" << alloca->getName()
|
||||
<< "] size after push: " << allocaToValueStackMap[alloca].size() << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!instDeleted) {
|
||||
++instIter; // 如果指令没有被删除,移动到下一个
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 处理后继基本块的 Phi 指令参数
|
||||
// --------------------------------------------------------------------
|
||||
@@ -290,40 +309,57 @@ void Mem2RegContext::renameVariables(AllocaInst *currentAlloca, BasicBlock *curr
|
||||
// 参数值是当前 alloca 值栈顶部的 SSA 值
|
||||
assert(!allocaToValueStackMap[alloca].empty() && "Value stack empty for alloca when setting phi operand!");
|
||||
phiInst->addIncoming(allocaToValueStackMap[alloca].top(), currentBB);
|
||||
if (DEBUG) {
|
||||
std::cout << "Mem2Reg: Added incoming arg to Phi "
|
||||
<< (phiInst->getName().empty() ? "anonymous" : phiInst->getName()) << " from "
|
||||
<< currentBB->getName() << " with value "
|
||||
<< (allocaToValueStackMap[alloca].top()->getName().empty()
|
||||
? "anonymous"
|
||||
: allocaToValueStackMap[alloca].top()->getName())
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 递归访问支配树的子节点
|
||||
// --------------------------------------------------------------------
|
||||
const std::set<BasicBlock *> *dominatedBlocks = dt->getDominatorTreeChildren(currentBB);
|
||||
if(dominatedBlocks){
|
||||
if (dominatedBlocks) { // 检查是否存在子节点
|
||||
if(DEBUG){
|
||||
std::cout << "Mem2Reg: Processing dominated blocks for " << currentBB->getName() << std::endl;
|
||||
for (auto dominatedBB : *dominatedBlocks) {
|
||||
std::cout << "Mem2Reg: Dominated block: " << (dominatedBB ? dominatedBB->getName() : "null") << std::endl;
|
||||
}
|
||||
}
|
||||
for (auto dominatedBB : *dominatedBlocks) {
|
||||
if (dominatedBB) {
|
||||
if(DEBUG){
|
||||
std::cout << "Mem2Reg: Recursively renaming variables in dominated block: " << dominatedBB->getName() << std::endl;
|
||||
if (dominatedBB) { // 确保子块有效
|
||||
if (DEBUG) {
|
||||
std::cout << "Mem2Reg: Recursively renaming variables in dominated block: " << dominatedBB->getName()
|
||||
<< std::endl;
|
||||
}
|
||||
renameVariables(currentAlloca, dominatedBB);
|
||||
renameVariables(dominatedBB); // 递归调用,不再传递 currentAlloca
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 退出基本块时,弹出在此块中压入值栈的 SSA 值
|
||||
// 退出基本块时,弹出在此块中压入值栈的 SSA 值,恢复栈到进入该块时的状态
|
||||
// --------------------------------------------------------------------
|
||||
while (!localStackPushed.empty()) {
|
||||
Value *val = localStackPushed.top();
|
||||
localStackPushed.pop();
|
||||
// 找到是哪个 alloca 对应的栈
|
||||
for (auto alloca : promotableAllocas) {
|
||||
if (!allocaToValueStackMap[alloca].empty() && allocaToValueStackMap[alloca].top() == val) {
|
||||
allocaToValueStackMap[alloca].pop();
|
||||
break;
|
||||
for (auto alloca : promotableAllocas) {
|
||||
while (allocaToValueStackMap[alloca].size() > originalStackSizes[alloca]) {
|
||||
if (DEBUG) {
|
||||
std::cout << "Mem2Reg: Popping value "
|
||||
<< (allocaToValueStackMap[alloca].top()->getName().empty()
|
||||
? "anonymous"
|
||||
: allocaToValueStackMap[alloca].top()->getName())
|
||||
<< " for alloca " << alloca->getName() << ". Stack size: " << allocaToValueStackMap[alloca].size()
|
||||
<< " -> " << (allocaToValueStackMap[alloca].size() - 1) << std::endl;
|
||||
}
|
||||
allocaToValueStackMap[alloca].pop();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 删除所有原始的 AllocaInst、LoadInst 和 StoreInst
|
||||
|
||||
@@ -148,8 +148,8 @@ void Reg2MemContext::rewritePhis(Function *func) {
|
||||
// 1. 为 Phi 指令的每个入边,在前驱块的末尾插入 Store 指令
|
||||
// PhiInst 假设有 getIncomingValues() 和 getIncomingBlocks()
|
||||
for (unsigned i = 0; i < phiInst->getNumIncomingValues(); ++i) { // 假设 PhiInst 是通过操作数来管理入边的
|
||||
Value *incomingValue = phiInst->getValue(i); // 获取入值
|
||||
BasicBlock *incomingBlock = phiInst->getBlock(i); // 获取对应的入块
|
||||
Value *incomingValue = phiInst->getIncomingValue(i); // 获取入值
|
||||
BasicBlock *incomingBlock = phiInst->getIncomingBlock(i); // 获取对应的入块
|
||||
|
||||
// 在入块的跳转指令之前插入 StoreInst
|
||||
// 需要找到 incomingBlock 的终结指令 (Terminator Instruction)
|
||||
|
||||
@@ -845,7 +845,7 @@ void SCCPContext::RemovePhiIncoming(BasicBlock *phiParentBB, BasicBlock *removed
|
||||
|
||||
for (Instruction *inst : insts_to_check) {
|
||||
if (auto phi = dynamic_cast<PhiInst *>(inst)) {
|
||||
phi->delBlk(removedPred);
|
||||
phi->removeIncomingBlock(removedPred);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#include "SysYIRCFGOpt.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <queue> // 引入队列,SysYDelNoPreBLock需要
|
||||
#include <string>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
@@ -18,7 +18,6 @@ void *SysYBlockMergePass::ID = (void *)&SysYBlockMergePass::ID;
|
||||
void *SysYAddReturnPass::ID = (void *)&SysYAddReturnPass::ID;
|
||||
void *SysYCondBr2BrPass::ID = (void *)&SysYCondBr2BrPass::ID;
|
||||
|
||||
|
||||
// ======================================================================
|
||||
// SysYCFGOptUtils: 辅助工具类,包含实际的CFG优化逻辑
|
||||
// ======================================================================
|
||||
@@ -26,40 +25,42 @@ void *SysYCondBr2BrPass::ID = (void *)&SysYCondBr2BrPass::ID;
|
||||
// 删除br后的无用指令
|
||||
bool SysYCFGOptUtils::SysYDelInstAfterBr(Function *func) {
|
||||
bool changed = false;
|
||||
|
||||
|
||||
auto basicBlocks = func->getBasicBlocks();
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
bool Branch = false;
|
||||
auto &instructions = basicBlock->getInstructions();
|
||||
auto Branchiter = instructions.end();
|
||||
for (auto iter = instructions.begin(); iter != instructions.end(); ++iter) {
|
||||
if ((*iter)->isTerminator()){
|
||||
if ((*iter)->isTerminator()) {
|
||||
Branch = true;
|
||||
Branchiter = iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Branchiter != instructions.end()) ++Branchiter;
|
||||
if (Branchiter != instructions.end())
|
||||
++Branchiter;
|
||||
while (Branchiter != instructions.end()) {
|
||||
changed = true;
|
||||
Branchiter = instructions.erase(Branchiter);
|
||||
}
|
||||
|
||||
if (Branch) { // 更新前驱后继关系
|
||||
auto thelastinstinst = basicBlock->getInstructions().end();
|
||||
--thelastinstinst;
|
||||
|
||||
if (Branch) { // 更新前驱后继关系
|
||||
auto thelastinstinst = basicBlock->terminator();
|
||||
auto &Successors = basicBlock->getSuccessors();
|
||||
for (auto iterSucc = Successors.begin(); iterSucc != Successors.end();) {
|
||||
(*iterSucc)->removePredecessor(basicBlock.get());
|
||||
basicBlock->removeSuccessor(*iterSucc);
|
||||
}
|
||||
if (thelastinstinst->get()->isUnconditional()) {
|
||||
BasicBlock* branchBlock = dynamic_cast<BasicBlock *>(thelastinstinst->get()->getOperand(0));
|
||||
auto brinst = dynamic_cast<UncondBrInst *>(thelastinstinst->get());
|
||||
BasicBlock *branchBlock = dynamic_cast<BasicBlock *>(brinst->getBlock());
|
||||
basicBlock->addSuccessor(branchBlock);
|
||||
branchBlock->addPredecessor(basicBlock.get());
|
||||
} else if (thelastinstinst->get()->isConditional()) {
|
||||
BasicBlock* thenBlock = dynamic_cast<BasicBlock *>(thelastinstinst->get()->getOperand(1));
|
||||
BasicBlock* elseBlock = dynamic_cast<BasicBlock *>(thelastinstinst->get()->getOperand(2));
|
||||
auto brinst = dynamic_cast<CondBrInst *>(thelastinstinst->get());
|
||||
BasicBlock *thenBlock = dynamic_cast<BasicBlock *>(brinst->getThenBlock());
|
||||
BasicBlock *elseBlock = dynamic_cast<BasicBlock *>(brinst->getElseBlock());
|
||||
basicBlock->addSuccessor(thenBlock);
|
||||
basicBlock->addSuccessor(elseBlock);
|
||||
thenBlock->addPredecessor(basicBlock.get());
|
||||
@@ -75,26 +76,26 @@ bool SysYCFGOptUtils::SysYDelInstAfterBr(Function *func) {
|
||||
bool SysYCFGOptUtils::SysYBlockMerge(Function *func) {
|
||||
bool changed = false;
|
||||
|
||||
for (auto blockiter = func->getBasicBlocks().begin();
|
||||
blockiter != func->getBasicBlocks().end();) {
|
||||
for (auto blockiter = func->getBasicBlocks().begin(); blockiter != func->getBasicBlocks().end();) {
|
||||
if (blockiter->get()->getNumSuccessors() == 1) {
|
||||
// 如果当前块只有一个后继块
|
||||
// 且后继块只有一个前驱块
|
||||
// 则将当前块和后继块合并
|
||||
if (((blockiter->get())->getSuccessors()[0])->getNumPredecessors() == 1) {
|
||||
// std::cout << "merge block: " << blockiter->get()->getName() << std::endl;
|
||||
BasicBlock* block = blockiter->get();
|
||||
BasicBlock* nextBlock = blockiter->get()->getSuccessors()[0];
|
||||
BasicBlock *block = blockiter->get();
|
||||
BasicBlock *nextBlock = blockiter->get()->getSuccessors()[0];
|
||||
// auto nextarguments = nextBlock->getArguments();
|
||||
// 删除br指令
|
||||
if (block->getNumInstructions() != 0) {
|
||||
auto thelastinstinst = block->end();
|
||||
(--thelastinstinst);
|
||||
auto thelastinstinst = block->terminator();
|
||||
if (thelastinstinst->get()->isUnconditional()) {
|
||||
thelastinstinst = SysYIROptUtils::usedelete(thelastinstinst);
|
||||
} else if (thelastinstinst->get()->isConditional()) {
|
||||
// 如果是条件分支,判断条件是否相同,主要优化相同布尔表达式
|
||||
if (thelastinstinst->get()->getOperand(1)->getName() == thelastinstinst->get()->getOperand(1)->getName()) {
|
||||
// 按道理不会走到这个分支
|
||||
// 如果是条件分支,查看then else是否相同
|
||||
auto brinst = dynamic_cast<CondBrInst *>(thelastinstinst->get());
|
||||
if (brinst->getThenBlock() == brinst->getElseBlock()) {
|
||||
thelastinstinst = SysYIROptUtils::usedelete(thelastinstinst);
|
||||
}
|
||||
}
|
||||
@@ -104,7 +105,7 @@ bool SysYCFGOptUtils::SysYBlockMerge(Function *func) {
|
||||
for (auto institer = nextBlock->begin(); institer != nextBlock->end();) {
|
||||
institer->get()->setParent(block);
|
||||
block->getInstructions().emplace_back(institer->release());
|
||||
institer = nextBlock->getInstructions().erase(institer);
|
||||
institer = nextBlock->getInstructions().erase(institer);
|
||||
}
|
||||
// 更新前驱后继关系,类似树节点操作
|
||||
block->removeSuccessor(nextBlock);
|
||||
@@ -135,318 +136,434 @@ bool SysYCFGOptUtils::SysYBlockMerge(Function *func) {
|
||||
|
||||
// 删除无前驱块,兼容SSA后的处理
|
||||
bool SysYCFGOptUtils::SysYDelNoPreBLock(Function *func) {
|
||||
|
||||
bool changed = false;
|
||||
bool changed = false; // 标记是否有基本块被删除
|
||||
std::set<BasicBlock *> reachableBlocks; // 用于存储所有可达的基本块
|
||||
std::queue<BasicBlock *> blockQueue; // BFS 遍历队列
|
||||
|
||||
for (auto &block : func->getBasicBlocks()) {
|
||||
block->setreachableFalse();
|
||||
BasicBlock *entryBlock = func->getEntryBlock();
|
||||
if (entryBlock) { // 确保函数有入口块
|
||||
reachableBlocks.insert(entryBlock); // 将入口块标记为可达
|
||||
blockQueue.push(entryBlock); // 入口块入队
|
||||
}
|
||||
// 对函数基本块做一个拓扑排序,排查不可达基本块
|
||||
auto entryBlock = func->getEntryBlock();
|
||||
entryBlock->setreachableTrue();
|
||||
std::queue<BasicBlock *> blockqueue;
|
||||
blockqueue.push(entryBlock);
|
||||
while (!blockqueue.empty()) {
|
||||
auto block = blockqueue.front();
|
||||
blockqueue.pop();
|
||||
for (auto &succ : block->getSuccessors()) {
|
||||
if (!succ->getreachable()) {
|
||||
succ->setreachableTrue();
|
||||
blockqueue.push(succ);
|
||||
// 如果没有入口块(比如一个空函数),则没有块是可达的,所有块都将被删除。
|
||||
|
||||
while (!blockQueue.empty()) { // BFS 遍历:只要队列不空
|
||||
BasicBlock *currentBlock = blockQueue.front();
|
||||
blockQueue.pop(); // 取出当前块
|
||||
|
||||
for (auto &succ : currentBlock->getSuccessors()) { // 遍历当前块的所有后继
|
||||
// 如果后继块不在 reachableBlocks 中(即尚未被访问过)
|
||||
if (reachableBlocks.find(succ) == reachableBlocks.end()) {
|
||||
reachableBlocks.insert(succ); // 标记为可达
|
||||
blockQueue.push(succ); // 入队,以便继续遍历
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除不可达基本块指令
|
||||
for (auto blockIter = func->getBasicBlocks().begin(); blockIter != func->getBasicBlocks().end(); blockIter++) {
|
||||
if (!blockIter->get()->getreachable()) {
|
||||
for (auto instIter = blockIter->get()->getInstructions().begin();
|
||||
instIter != blockIter->get()->getInstructions().end();) {
|
||||
instIter = SysYIROptUtils::usedelete(instIter);
|
||||
std::vector<BasicBlock *> blocksToDelete; // 用于存储所有不可达的基本块
|
||||
|
||||
for (auto &blockPtr : func->getBasicBlocks()) {
|
||||
BasicBlock *block = blockPtr.get();
|
||||
// 如果当前块不在 reachableBlocks 集合中,说明它是不可达的
|
||||
if (reachableBlocks.find(block) == reachableBlocks.end()) {
|
||||
blocksToDelete.push_back(block); // 将其加入待删除列表
|
||||
changed = true; // 只要找到一个不可达块,就说明函数发生了改变
|
||||
}
|
||||
}
|
||||
|
||||
for (BasicBlock *unreachableBlock : blocksToDelete) {
|
||||
// 遍历不可达块中的所有指令,并删除它们
|
||||
for (auto instIter = unreachableBlock->getInstructions().begin();
|
||||
instIter != unreachableBlock->getInstructions().end();) {
|
||||
instIter = SysYIROptUtils::usedelete(instIter);
|
||||
}
|
||||
}
|
||||
|
||||
for (BasicBlock *unreachableBlock : blocksToDelete) {
|
||||
for (BasicBlock *succBlock : unreachableBlock->getSuccessors()) {
|
||||
// 只有当后继块自身是可达的(没有被删除)时才需要处理
|
||||
if (reachableBlocks.count(succBlock)) {
|
||||
for (auto &phiInstPtr : succBlock->getInstructions()) {
|
||||
// Phi 指令总是在基本块的开头。一旦遇到非 Phi 指令即可停止。
|
||||
if (phiInstPtr->getKind() != Instruction::kPhi) {
|
||||
break;
|
||||
}
|
||||
// 将这个 Phi 节点中来自不可达前驱(unreachableBlock)的输入参数删除
|
||||
dynamic_cast<PhiInst *>(phiInstPtr.get())->removeIncomingBlock(unreachableBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (auto blockIter = func->getBasicBlocks().begin(); blockIter != func->getBasicBlocks().end();) {
|
||||
if (!blockIter->get()->getreachable()) {
|
||||
for (auto succblock : blockIter->get()->getSuccessors()) {
|
||||
for (auto &phiinst : succblock->getInstructions()) {
|
||||
if (phiinst->getKind() != Instruction::kPhi) {
|
||||
break;
|
||||
}
|
||||
// 使用 delBlk 方法正确地删除对应于被删除基本块的传入值
|
||||
dynamic_cast<PhiInst *>(phiinst.get())->delBlk(blockIter->get());
|
||||
}
|
||||
}
|
||||
// 删除不可达基本块,注意迭代器不可达问题
|
||||
BasicBlock *currentBlock = blockIter->get();
|
||||
// 如果当前块不在可达块集合中,则将其从函数中移除
|
||||
if (reachableBlocks.find(currentBlock) == reachableBlocks.end()) {
|
||||
// func->removeBasicBlock 应该返回下一个有效的迭代器
|
||||
func->removeBasicBlock((blockIter++)->get());
|
||||
changed = true;
|
||||
} else {
|
||||
blockIter++;
|
||||
blockIter++; // 如果可达,则移动到下一个块
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
// 删除空块
|
||||
bool SysYCFGOptUtils::SysYDelEmptyBlock(Function *func, IRBuilder* pBuilder) {
|
||||
bool SysYCFGOptUtils::SysYDelEmptyBlock(Function *func, IRBuilder *pBuilder) {
|
||||
bool changed = false;
|
||||
|
||||
// 收集不可达基本块
|
||||
// 这里的不可达基本块是指没有实际指令的基本块
|
||||
// 当一个基本块没有实际指令例如只有phi指令和一个uncondbr指令时,也会被视作不可达
|
||||
auto basicBlocks = func->getBasicBlocks();
|
||||
std::map<sysy::BasicBlock *, BasicBlock *> EmptyBlocks;
|
||||
// 空块儿和后继的基本块的映射
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
if (basicBlock->getNumInstructions() == 0) {
|
||||
if (basicBlock->getNumSuccessors() == 1) {
|
||||
EmptyBlocks[basicBlock.get()] = basicBlock->getSuccessors().front();
|
||||
}
|
||||
}
|
||||
else{
|
||||
// 如果只有phi指令和一个uncondbr。(phi)*(uncondbr)?
|
||||
// 判断除了最后一个指令之外是不是只有phi指令
|
||||
bool onlyPhi = true;
|
||||
for (auto &inst : basicBlock->getInstructions()) {
|
||||
if (!inst->isPhi() && !inst->isUnconditional()) {
|
||||
onlyPhi = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(onlyPhi && basicBlock->getNumSuccessors() == 1) // 确保有后继且只有一个
|
||||
EmptyBlocks[basicBlock.get()] = basicBlock->getSuccessors().front();
|
||||
}
|
||||
// 步骤 1: 识别并映射所有符合“空块”定义的基本块及其目标后继
|
||||
// 使用 std::map 来存储 <空块, 空块跳转目标>
|
||||
// 这样可以处理空块链:A -> B -> C,如果 B 是空块,A 应该跳到 C
|
||||
std::map<BasicBlock *, BasicBlock *> emptyBlockRedirectMap;
|
||||
|
||||
// 为了避免在遍历 func->getBasicBlocks() 时修改它导致迭代器失效,
|
||||
// 我们先收集所有的基本块。
|
||||
std::vector<BasicBlock *> allBlocks;
|
||||
for (auto &blockPtr : func->getBasicBlocks()) {
|
||||
allBlocks.push_back(blockPtr.get());
|
||||
}
|
||||
// 更新基本块信息,增加必要指令
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
// 把空块转换成只有跳转指令的不可达块 (这段逻辑在优化遍中可能需要调整,这里是原样保留)
|
||||
// 通常,DelEmptyBlock 应该在BlockMerge之后运行,如果存在完全空块,它会尝试填充一个Br指令。
|
||||
// 但是,它主要目的是重定向跳转。
|
||||
if (distance(basicBlock->begin(), basicBlock->end()) == 0) {
|
||||
if (basicBlock->getNumSuccessors() == 0) {
|
||||
continue;
|
||||
}
|
||||
if (basicBlock->getNumSuccessors() > 1) {
|
||||
// 如果一个空块有多个后继,说明CFG结构有问题或者需要特殊处理,这里简单assert
|
||||
assert(false && "Empty block with multiple successors found during SysYDelEmptyBlock");
|
||||
}
|
||||
// 这里的逻辑有点问题,如果一个块是空的,且只有一个后继,应该直接跳转到后继。
|
||||
// 如果这个块最终被删除了,那么其前驱也需要重定向。
|
||||
// 这个循环的目的是重定向现有的跳转指令,而不是创建新的。
|
||||
// 所以下面的逻辑才是核心。
|
||||
// pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||
// pBuilder->createUncondBrInst(basicBlock->getSuccessors()[0], {});
|
||||
|
||||
for (BasicBlock *block : allBlocks) {
|
||||
// 入口块通常不应该被认为是空块并删除,除非它没有实际指令且只有一个后继,
|
||||
// 但为了安全起见,通常会跳过入口块的删除。
|
||||
// 如果入口块是空的,它应该被合并到它的后继,但处理起来更复杂,这里先不处理入口块为空的情况
|
||||
if (block == func->getEntryBlock()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto thelastinst = basicBlock->getInstructions().end();
|
||||
--thelastinst;
|
||||
|
||||
// 根据br指令传递的后继块信息,跳过空块链
|
||||
if (thelastinst->get()->isUnconditional()) {
|
||||
BasicBlock* OldBrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
||||
BasicBlock *thelastBlockOld = nullptr;
|
||||
// 如果空块链表为多个块
|
||||
while (EmptyBlocks.count(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0)))) {
|
||||
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
||||
thelastinst->get()->replaceOperand(0, EmptyBlocks[thelastBlockOld]);
|
||||
}
|
||||
|
||||
// 如果有重定向发生
|
||||
if (thelastBlockOld != nullptr) {
|
||||
basicBlock->removeSuccessor(OldBrBlock);
|
||||
OldBrBlock->removePredecessor(basicBlock.get());
|
||||
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0)));
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->addPredecessor(basicBlock.get());
|
||||
changed = true; // 标记IR被修改
|
||||
}
|
||||
|
||||
|
||||
if (thelastBlockOld != nullptr) {
|
||||
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getInstructions()) {
|
||||
if (InstInNew->isPhi()) {
|
||||
// 使用 delBlk 方法删除 oldBlock 对应的传入值
|
||||
dynamic_cast<PhiInst *>(InstInNew.get())->delBlk(thelastBlockOld);
|
||||
} else {
|
||||
// 检查基本块是否是空的:除了Phi指令外,只包含一个终止指令 (Terminator)
|
||||
// 且该终止指令必须是无条件跳转。
|
||||
// 空块必须只有一个后继才能被简化
|
||||
if (block->getNumSuccessors() == 1) {
|
||||
bool hasNonPhiNonTerminator = false;
|
||||
// 遍历除了最后一个指令之外的指令
|
||||
for (auto instIter = block->getInstructions().begin(); instIter != block->getInstructions().end();) {
|
||||
// 如果是终止指令(例如 br, ret),且不是最后一个指令,则该块有问题
|
||||
if ((*instIter)->isTerminator() && instIter != block->terminator()) {
|
||||
hasNonPhiNonTerminator = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (thelastinst->get()->getKind() == Instruction::kCondBr) {
|
||||
auto OldThenBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||
auto OldElseBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2));
|
||||
bool thenChanged = false;
|
||||
bool elseChanged = false;
|
||||
|
||||
|
||||
BasicBlock *thelastBlockOld = nullptr;
|
||||
while (EmptyBlocks.count(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)))) {
|
||||
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||
thelastinst->get()->replaceOperand(
|
||||
1, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))]);
|
||||
thenChanged = true;
|
||||
}
|
||||
|
||||
if (thenChanged) {
|
||||
basicBlock->removeSuccessor(OldThenBlock);
|
||||
OldThenBlock->removePredecessor(basicBlock.get());
|
||||
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)));
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->addPredecessor(basicBlock.get());
|
||||
changed = true; // 标记IR被修改
|
||||
}
|
||||
|
||||
// 处理 then 和 else 分支合并的情况
|
||||
if (dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)) ==
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) {
|
||||
auto thebrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||
thelastinst = SysYIROptUtils::usedelete(thelastinst);
|
||||
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||
pBuilder->createUncondBrInst(thebrBlock);
|
||||
changed = true; // 标记IR被修改
|
||||
continue;
|
||||
}
|
||||
|
||||
if (thelastBlockOld != nullptr) {
|
||||
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->getInstructions()) {
|
||||
if (InstInNew->isPhi()) {
|
||||
// 使用 delBlk 方法删除 oldBlock 对应的传入值
|
||||
dynamic_cast<PhiInst *>(InstInNew.get())->delBlk(thelastBlockOld);
|
||||
} else {
|
||||
break;
|
||||
// 如果不是 Phi 指令且不是终止指令
|
||||
if (!(*instIter)->isPhi() && !(*instIter)->isTerminator()) {
|
||||
hasNonPhiNonTerminator = true;
|
||||
break;
|
||||
}
|
||||
++instIter;
|
||||
if (!hasNonPhiNonTerminator &&
|
||||
instIter == block->getInstructions().end()) { // 如果块中只有 Phi 指令和一个 Terminator
|
||||
// 确保最后一个指令是无条件跳转
|
||||
auto lastInst = block->terminator()->get();
|
||||
if (lastInst && lastInst->isUnconditional()) {
|
||||
emptyBlockRedirectMap[block] = block->getSuccessors().front();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thelastBlockOld = nullptr;
|
||||
while (EmptyBlocks.count(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2)))) {
|
||||
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2));
|
||||
thelastinst->get()->replaceOperand(
|
||||
2, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))]);
|
||||
elseChanged = true;
|
||||
}
|
||||
|
||||
if (elseChanged) {
|
||||
basicBlock->removeSuccessor(OldElseBlock);
|
||||
OldElseBlock->removePredecessor(basicBlock.get());
|
||||
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2)));
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->addPredecessor(basicBlock.get());
|
||||
changed = true; // 标记IR被修改
|
||||
}
|
||||
|
||||
// 处理 then 和 else 分支合并的情况
|
||||
if (dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)) ==
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) {
|
||||
auto thebrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||
thelastinst = SysYIROptUtils::usedelete(thelastinst);
|
||||
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||
pBuilder->createUncondBrInst(thebrBlock);
|
||||
changed = true; // 标记IR被修改
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// 如果有重定向发生
|
||||
// 需要更新后继块的前驱关系
|
||||
if (thelastBlockOld != nullptr) {
|
||||
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->getInstructions()) {
|
||||
if (InstInNew->isPhi()) {
|
||||
// 使用 delBlk 方法删除 oldBlock 对应的传入值
|
||||
dynamic_cast<PhiInst *>(InstInNew.get())->delBlk(thelastBlockOld);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// 如果不是终止指令,但有后继 (例如,末尾没有显式终止指令的块)
|
||||
// 这段逻辑可能需要更严谨的CFG检查来确保正确性
|
||||
if (basicBlock->getNumSuccessors() == 1) {
|
||||
// 这里的逻辑似乎是想为没有terminator的块添加一个,但通常这应该在CFG构建阶段完成。
|
||||
// 如果这里仍然执行,确保它符合预期。
|
||||
// pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||
// pBuilder->createUncondBrInst(basicBlock->getSuccessors()[0], {});
|
||||
// auto thelastinst = basicBlock->getInstructions().end();
|
||||
// (--thelastinst);
|
||||
// auto OldBrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
||||
// sysy::BasicBlock *thelastBlockOld = nullptr;
|
||||
// while (EmptyBlocks.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))) !=
|
||||
// EmptyBlocks.end()) {
|
||||
// thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
||||
|
||||
// thelastinst->get()->replaceOperand(
|
||||
// 0, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))]);
|
||||
// }
|
||||
|
||||
// basicBlock->removeSuccessor(OldBrBlock);
|
||||
// OldBrBlock->removePredecessor(basicBlock.get());
|
||||
// basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0)));
|
||||
// dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->addPredecessor(basicBlock.get());
|
||||
// changed = true; // 标记IR被修改
|
||||
// if (thelastBlockOld != nullptr) {
|
||||
// int indexphi = 0;
|
||||
// for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getPredecessors()) {
|
||||
// if (pred == thelastBlockOld) {
|
||||
// break;
|
||||
// }
|
||||
// indexphi++;
|
||||
// }
|
||||
|
||||
// for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getInstructions()) {
|
||||
// if (InstInNew->isPhi()) {
|
||||
// dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 真正的删除空块
|
||||
for (auto iter = func->getBasicBlocks().begin(); iter != func->getBasicBlocks().end();) {
|
||||
|
||||
if (EmptyBlocks.count(iter->get())) {
|
||||
// EntryBlock跳过
|
||||
if (iter->get() == func->getEntryBlock()) {
|
||||
++iter;
|
||||
continue;
|
||||
// 步骤 2: 遍历 emptyBlockRedirectMap,处理空块链
|
||||
// 确保每个空块都直接重定向到其最终的非空后继块
|
||||
for (auto const &[emptyBlock, directSucc] : emptyBlockRedirectMap) {
|
||||
BasicBlock *targetBlock = directSucc;
|
||||
// 沿着空块链一直找到最终的非空块目标
|
||||
while (emptyBlockRedirectMap.count(targetBlock)) {
|
||||
targetBlock = emptyBlockRedirectMap[targetBlock];
|
||||
}
|
||||
emptyBlockRedirectMap[emptyBlock] = targetBlock; // 更新映射到最终目标
|
||||
}
|
||||
|
||||
// 步骤 3: 遍历所有基本块,重定向其终止指令,绕过空块
|
||||
// 注意:这里需要再次遍历所有块,包括可能成为新目标的块
|
||||
for (BasicBlock *currentBlock : allBlocks) {
|
||||
// 如果 currentBlock 本身就是个空块,它会通过其前驱的重定向被处理,这里跳过
|
||||
if (emptyBlockRedirectMap.count(currentBlock)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取当前块的最后一个指令(终止指令)
|
||||
if (currentBlock->getInstructions().empty()) {
|
||||
// 理论上,除了入口块和可能被合并的空块外,所有块都应该有终止指令
|
||||
// 如果这里碰到空块,可能是逻辑错误或者需要特殊处理
|
||||
continue;
|
||||
}
|
||||
|
||||
std::function<Value *(Value *, BasicBlock *)> getUltimateSourceValue = [&](Value *val,
|
||||
BasicBlock *currentDefBlock) -> Value * {
|
||||
// 如果值不是指令,例如常量或函数参数,则它本身就是最终来源
|
||||
if (auto instr = dynamic_cast<Instruction *>(val)) { // Assuming Value* has a method to check if it's an instruction
|
||||
return val;
|
||||
}
|
||||
|
||||
for (auto instIter = iter->get()->getInstructions().begin();
|
||||
instIter != iter->get()->getInstructions().end();) {
|
||||
instIter = SysYIROptUtils::usedelete(instIter);
|
||||
Instruction *inst = dynamic_cast<Instruction *>(val);
|
||||
// 如果定义指令不在任何空块中,它就是最终来源
|
||||
if (!emptyBlockRedirectMap.count(currentDefBlock)) {
|
||||
return val;
|
||||
}
|
||||
// 删除不可达基本块的phi指令的操作数
|
||||
for (auto &succ : iter->get()->getSuccessors()) {
|
||||
for (auto &instinsucc : succ->getInstructions()) {
|
||||
if (instinsucc->isPhi()) {
|
||||
// iter->get() 就是当前被删除的空基本块,它作为前驱连接到这里的Phi指令
|
||||
dynamic_cast<PhiInst *>(instinsucc.get())->delBlk(iter->get());
|
||||
|
||||
// 如果是 Phi 指令,且它在空块中,则继续追溯其在空块链中前驱的传入值
|
||||
if (inst->getKind() == Instruction::kPhi) {
|
||||
PhiInst *phi = dynamic_cast<PhiInst *>(inst);
|
||||
// 查找哪个前驱是空块链中的上一个块
|
||||
for (size_t i = 0; i < phi->getNumOperands(); i += 2) {
|
||||
BasicBlock *incomingBlock = dynamic_cast<BasicBlock *>(phi->getOperand(i + 1));
|
||||
// 检查 incomingBlock 是否是当前空块的前驱,且也在空块映射中(或就是 P)
|
||||
// 找到在空块链中导致 currentDefBlock 的那个前驱块
|
||||
if (emptyBlockRedirectMap.count(incomingBlock) || incomingBlock == currentBlock) {
|
||||
// 递归追溯该传入值
|
||||
return getUltimateSourceValue(phi->getValfromBlk(incomingBlock), incomingBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 如果是其他指令或者无法追溯到Phi链,则认为它在空块中产生,无法安全传播,返回null或原值
|
||||
// 在严格的空块定义下,除了Phi和Terminator,不应有其他指令产生值。
|
||||
return val; // Fallback: If not a Phi, or unable to trace, return itself (may be dangling)
|
||||
};
|
||||
|
||||
auto lastInst = currentBlock->getInstructions().back().get();
|
||||
|
||||
if (lastInst->isUnconditional()) { // 无条件跳转
|
||||
UncondBrInst *brInst = dynamic_cast<UncondBrInst *>(lastInst);
|
||||
BasicBlock *oldTarget = dynamic_cast<BasicBlock *>(brInst->getBlock()); // 原始跳转目标
|
||||
|
||||
if (emptyBlockRedirectMap.count(oldTarget)) { // 如果目标是空块
|
||||
BasicBlock *newTarget = emptyBlockRedirectMap[oldTarget]; // 获取最终目标
|
||||
|
||||
// 更新 CFG 关系
|
||||
currentBlock->removeSuccessor(oldTarget);
|
||||
oldTarget->removePredecessor(currentBlock);
|
||||
|
||||
brInst->replaceOperand(0, newTarget); // 更新跳转指令的操作数
|
||||
currentBlock->addSuccessor(newTarget);
|
||||
newTarget->addPredecessor(currentBlock);
|
||||
|
||||
changed = true; // 标记发生改变
|
||||
|
||||
for (auto &phiInstPtr : newTarget->getInstructions()) {
|
||||
if (phiInstPtr->getKind() == Instruction::kPhi) {
|
||||
PhiInst *phiInst = dynamic_cast<PhiInst *>(phiInstPtr.get());
|
||||
BasicBlock *actualEmptyPredecessorOfS = nullptr;
|
||||
for (size_t i = 0; i < phiInst->getNumOperands(); i += 2) {
|
||||
BasicBlock *incomingBlock = dynamic_cast<BasicBlock *>(phiInst->getOperand(i + 1));
|
||||
if (incomingBlock && emptyBlockRedirectMap.count(incomingBlock) &&
|
||||
emptyBlockRedirectMap[incomingBlock] == newTarget) {
|
||||
actualEmptyPredecessorOfS = incomingBlock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (actualEmptyPredecessorOfS) {
|
||||
// 获取 Phi 节点原本从 actualEmptyPredecessorOfS 接收的值
|
||||
Value *valueFromEmptyPredecessor = phiInst->getValfromBlk(actualEmptyPredecessorOfS);
|
||||
|
||||
// 追溯这个值,找到它在非空块中的最终来源
|
||||
// currentBlock 是 P
|
||||
// oldTarget 是 E1 (链的起点)
|
||||
// actualEmptyPredecessorOfS 是 En (链的终点,S 的前驱)
|
||||
Value *ultimateSourceValue = getUltimateSourceValue(valueFromEmptyPredecessor, actualEmptyPredecessorOfS);
|
||||
|
||||
// 替换 Phi 节点的传入块和传入值
|
||||
if (ultimateSourceValue) { // 确保成功追溯到有效来源
|
||||
// phiInst->replaceIncoming(actualEmptyPredecessorOfS, currentBlock, ultimateSourceValue);
|
||||
phiInst->replaceIncomingBlock(actualEmptyPredecessorOfS, currentBlock, ultimateSourceValue);
|
||||
} else {
|
||||
assert(false && "[DelEmptyBlock] Unable to trace a valid source for Phi instruction");
|
||||
// 无法追溯到有效来源,这可能是个错误或特殊情况
|
||||
// 此时可能需要移除该 Phi 项,或者插入一个 undef 值
|
||||
phiInst->getValfromBlk(actualEmptyPredecessorOfS);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Phi 指令通常在基本块的开头,如果不是 Phi 指令就停止检查
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func->removeBasicBlock((iter++)->get());
|
||||
changed = true;
|
||||
} else {
|
||||
++iter;
|
||||
} else if (lastInst->getKind() == Instruction::kCondBr) { // 条件跳转
|
||||
CondBrInst *condBrInst = dynamic_cast<CondBrInst *>(lastInst);
|
||||
BasicBlock *oldThenTarget = dynamic_cast<BasicBlock *>(condBrInst->getThenBlock());
|
||||
BasicBlock *oldElseTarget = dynamic_cast<BasicBlock *>(condBrInst->getElseBlock());
|
||||
|
||||
bool thenPathChanged = false;
|
||||
bool elsePathChanged = false;
|
||||
|
||||
// 处理 Then 分支
|
||||
if (emptyBlockRedirectMap.count(oldThenTarget)) {
|
||||
BasicBlock *newThenTarget = emptyBlockRedirectMap[oldThenTarget];
|
||||
condBrInst->replaceOperand(1, newThenTarget); // 更新跳转指令操作数
|
||||
|
||||
currentBlock->removeSuccessor(oldThenTarget);
|
||||
oldThenTarget->removePredecessor(currentBlock);
|
||||
currentBlock->addSuccessor(newThenTarget);
|
||||
newThenTarget->addPredecessor(currentBlock);
|
||||
thenPathChanged = true;
|
||||
changed = true;
|
||||
|
||||
// 处理新 Then 目标块中的 Phi 指令
|
||||
// for (auto &phiInstPtr : newThenTarget->getInstructions()) {
|
||||
// if (phiInstPtr->getKind() == Instruction::kPhi) {
|
||||
// dynamic_cast<PhiInst *>(phiInstPtr.get())->delBlk(oldThenTarget);
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
for (auto &phiInstPtr : newThenTarget->getInstructions()) {
|
||||
if (phiInstPtr->getKind() == Instruction::kPhi) {
|
||||
PhiInst *phiInst = dynamic_cast<PhiInst *>(phiInstPtr.get());
|
||||
BasicBlock *actualEmptyPredecessorOfS = nullptr;
|
||||
for (size_t i = 0; i < phiInst->getNumOperands(); i += 2) {
|
||||
BasicBlock *incomingBlock = dynamic_cast<BasicBlock *>(phiInst->getOperand(i + 1));
|
||||
if (incomingBlock && emptyBlockRedirectMap.count(incomingBlock) &&
|
||||
emptyBlockRedirectMap[incomingBlock] == newThenTarget) {
|
||||
actualEmptyPredecessorOfS = incomingBlock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (actualEmptyPredecessorOfS) {
|
||||
// 获取 Phi 节点原本从 actualEmptyPredecessorOfS 接收的值
|
||||
Value *valueFromEmptyPredecessor = phiInst->getValfromBlk(actualEmptyPredecessorOfS);
|
||||
|
||||
// 追溯这个值,找到它在非空块中的最终来源
|
||||
// currentBlock 是 P
|
||||
// oldTarget 是 E1 (链的起点)
|
||||
// actualEmptyPredecessorOfS 是 En (链的终点,S 的前驱)
|
||||
Value *ultimateSourceValue = getUltimateSourceValue(valueFromEmptyPredecessor, actualEmptyPredecessorOfS);
|
||||
|
||||
// 替换 Phi 节点的传入块和传入值
|
||||
if (ultimateSourceValue) { // 确保成功追溯到有效来源
|
||||
// phiInst->replaceIncoming(actualEmptyPredecessorOfS, currentBlock, ultimateSourceValue);
|
||||
phiInst->replaceIncomingBlock(actualEmptyPredecessorOfS, currentBlock, ultimateSourceValue);
|
||||
} else {
|
||||
assert(false && "[DelEmptyBlock] Unable to trace a valid source for Phi instruction");
|
||||
// 无法追溯到有效来源,这可能是个错误或特殊情况
|
||||
// 此时可能需要移除该 Phi 项,或者插入一个 undef 值
|
||||
phiInst->removeIncomingBlock(actualEmptyPredecessorOfS);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 处理 Else 分支
|
||||
if (emptyBlockRedirectMap.count(oldElseTarget)) {
|
||||
BasicBlock *newElseTarget = emptyBlockRedirectMap[oldElseTarget];
|
||||
condBrInst->replaceOperand(2, newElseTarget); // 更新跳转指令操作数
|
||||
|
||||
currentBlock->removeSuccessor(oldElseTarget);
|
||||
oldElseTarget->removePredecessor(currentBlock);
|
||||
currentBlock->addSuccessor(newElseTarget);
|
||||
newElseTarget->addPredecessor(currentBlock);
|
||||
elsePathChanged = true;
|
||||
changed = true;
|
||||
|
||||
// 处理新 Else 目标块中的 Phi 指令
|
||||
// for (auto &phiInstPtr : newElseTarget->getInstructions()) {
|
||||
// if (phiInstPtr->getKind() == Instruction::kPhi) {
|
||||
// dynamic_cast<PhiInst *>(phiInstPtr.get())->delBlk(oldElseTarget);
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
for (auto &phiInstPtr : newElseTarget->getInstructions()) {
|
||||
if (phiInstPtr->getKind() == Instruction::kPhi) {
|
||||
PhiInst *phiInst = dynamic_cast<PhiInst *>(phiInstPtr.get());
|
||||
BasicBlock *actualEmptyPredecessorOfS = nullptr;
|
||||
for (size_t i = 0; i < phiInst->getNumOperands(); i += 2) {
|
||||
BasicBlock *incomingBlock = dynamic_cast<BasicBlock *>(phiInst->getOperand(i + 1));
|
||||
if (incomingBlock && emptyBlockRedirectMap.count(incomingBlock) &&
|
||||
emptyBlockRedirectMap[incomingBlock] == newElseTarget) {
|
||||
actualEmptyPredecessorOfS = incomingBlock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (actualEmptyPredecessorOfS) {
|
||||
// 获取 Phi 节点原本从 actualEmptyPredecessorOfS 接收的值
|
||||
Value *valueFromEmptyPredecessor = phiInst->getValfromBlk(actualEmptyPredecessorOfS);
|
||||
|
||||
// 追溯这个值,找到它在非空块中的最终来源
|
||||
// currentBlock 是 P
|
||||
// oldTarget 是 E1 (链的起点)
|
||||
// actualEmptyPredecessorOfS 是 En (链的终点,S 的前驱)
|
||||
Value *ultimateSourceValue = getUltimateSourceValue(valueFromEmptyPredecessor, actualEmptyPredecessorOfS);
|
||||
|
||||
// 替换 Phi 节点的传入块和传入值
|
||||
if (ultimateSourceValue) { // 确保成功追溯到有效来源
|
||||
// phiInst->replaceIncoming(actualEmptyPredecessorOfS, currentBlock, ultimateSourceValue);
|
||||
phiInst->replaceIncomingBlock(actualEmptyPredecessorOfS, currentBlock, ultimateSourceValue);
|
||||
} else {
|
||||
assert(false && "[DelEmptyBlock] Unable to trace a valid source for Phi instruction");
|
||||
// 无法追溯到有效来源,这可能是个错误或特殊情况
|
||||
// 此时可能需要移除该 Phi 项,或者插入一个 undef 值
|
||||
phiInst->removeIncomingBlock(actualEmptyPredecessorOfS);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 额外处理:如果条件跳转的两个分支现在指向同一个块,则可以简化为无条件跳转
|
||||
if (condBrInst->getThenBlock() == condBrInst->getElseBlock()) {
|
||||
BasicBlock *commonTarget = dynamic_cast<BasicBlock *>(condBrInst->getThenBlock());
|
||||
SysYIROptUtils::usedelete(lastInst); // 删除旧的条件跳转指令
|
||||
pBuilder->setPosition(currentBlock, currentBlock->end());
|
||||
pBuilder->createUncondBrInst(commonTarget); // 插入新的无条件跳转指令
|
||||
|
||||
// 更安全地更新 CFG 关系
|
||||
std::set<BasicBlock *> currentSuccessors;
|
||||
currentSuccessors.insert(oldThenTarget);
|
||||
currentSuccessors.insert(oldElseTarget);
|
||||
|
||||
// 移除旧的后继关系
|
||||
for (BasicBlock *succ : currentSuccessors) {
|
||||
currentBlock->removeSuccessor(succ);
|
||||
succ->removePredecessor(currentBlock);
|
||||
}
|
||||
// 添加新的后继关系
|
||||
currentBlock->addSuccessor(commonTarget);
|
||||
commonTarget->addPredecessor(currentBlock);
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 步骤 4: 真正地删除空基本块
|
||||
// 注意:只能在所有跳转和 Phi 指令都更新完毕后才能删除这些块
|
||||
for (auto blockIter = func->getBasicBlocks().begin(); blockIter != func->getBasicBlocks().end();) {
|
||||
BasicBlock *currentBlock = blockIter->get();
|
||||
if (emptyBlockRedirectMap.count(currentBlock)) { // 如果在空块映射中
|
||||
// 入口块不应该被删除,即使它符合空块定义,因为函数需要一个入口
|
||||
if (currentBlock == func->getEntryBlock()) {
|
||||
++blockIter;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 在删除块之前,确保其内部指令被正确删除(虽然这类块指令很少)
|
||||
for (auto instIter = currentBlock->getInstructions().begin();
|
||||
instIter != currentBlock->getInstructions().end();) {
|
||||
instIter = SysYIROptUtils::usedelete(instIter);
|
||||
}
|
||||
|
||||
// 移除块
|
||||
func->removeBasicBlock((blockIter++)->get());
|
||||
changed = true;
|
||||
} else {
|
||||
++blockIter;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
// 如果函数没有返回指令,则添加一个默认返回指令(主要解决void函数没有返回指令的问题)
|
||||
bool SysYCFGOptUtils::SysYAddReturn(Function *func, IRBuilder* pBuilder) {
|
||||
bool SysYCFGOptUtils::SysYAddReturn(Function *func, IRBuilder *pBuilder) {
|
||||
bool changed = false;
|
||||
auto basicBlocks = func->getBasicBlocks();
|
||||
for (auto &block : basicBlocks) {
|
||||
@@ -460,7 +577,8 @@ bool SysYCFGOptUtils::SysYAddReturn(Function *func, IRBuilder* pBuilder) {
|
||||
auto thelastinst = block->getInstructions().end();
|
||||
--thelastinst;
|
||||
if (thelastinst->get()->getKind() != Instruction::kReturn) {
|
||||
// std::cout << "Warning: Function " << func->getName() << " has no return instruction, adding default return." << std::endl;
|
||||
// std::cout << "Warning: Function " << func->getName() << " has no return instruction, adding default
|
||||
// return." << std::endl;
|
||||
|
||||
pBuilder->setPosition(block.get(), block->end());
|
||||
// TODO: 如果int float函数缺少返回值是否需要报错
|
||||
@@ -476,7 +594,7 @@ bool SysYCFGOptUtils::SysYAddReturn(Function *func, IRBuilder* pBuilder) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -484,18 +602,18 @@ bool SysYCFGOptUtils::SysYAddReturn(Function *func, IRBuilder* pBuilder) {
|
||||
// 主要针对已知条件值的分支转换为无条件分支
|
||||
// 例如 if (cond) { ... } else { ... } 中的 cond 已经
|
||||
// 确定为 true 或 false 的情况
|
||||
bool SysYCFGOptUtils::SysYCondBr2Br(Function *func, IRBuilder* pBuilder) {
|
||||
bool SysYCFGOptUtils::SysYCondBr2Br(Function *func, IRBuilder *pBuilder) {
|
||||
bool changed = false;
|
||||
|
||||
for (auto &basicblock : func->getBasicBlocks()) {
|
||||
if (basicblock->getNumInstructions() == 0)
|
||||
continue;
|
||||
|
||||
auto thelast = basicblock->getInstructions().end();
|
||||
--thelast;
|
||||
|
||||
if (thelast->get()->isConditional()){
|
||||
ConstantValue *constOperand = dynamic_cast<ConstantValue *>(thelast->get()->getOperand(0));
|
||||
auto thelast = basicblock->terminator();
|
||||
|
||||
if (thelast->get()->isConditional()) {
|
||||
auto condBrInst = dynamic_cast<CondBrInst *>(thelast->get());
|
||||
ConstantValue *constOperand = dynamic_cast<ConstantValue *>(condBrInst->getCondition());
|
||||
std::string opname;
|
||||
int constint = 0;
|
||||
float constfloat = 0.0F;
|
||||
@@ -514,27 +632,27 @@ bool SysYCFGOptUtils::SysYCondBr2Br(Function *func, IRBuilder* pBuilder) {
|
||||
if (constfloat_Use || constint_Use) {
|
||||
changed = true;
|
||||
|
||||
auto thenBlock = dynamic_cast<BasicBlock *>(thelast->get()->getOperand(1));
|
||||
auto elseBlock = dynamic_cast<BasicBlock *>(thelast->get()->getOperand(2));
|
||||
auto thenBlock = dynamic_cast<BasicBlock *>(condBrInst->getThenBlock());
|
||||
auto elseBlock = dynamic_cast<BasicBlock *>(condBrInst->getElseBlock());
|
||||
thelast = SysYIROptUtils::usedelete(thelast);
|
||||
if ((constfloat_Use && constfloat == 1.0F) || (constint_Use && constint == 1)) {
|
||||
// cond为true或非0
|
||||
pBuilder->setPosition(basicblock.get(), basicblock->end());
|
||||
pBuilder->createUncondBrInst(thenBlock);
|
||||
|
||||
|
||||
// 更新CFG关系
|
||||
basicblock->removeSuccessor(elseBlock);
|
||||
elseBlock->removePredecessor(basicblock.get());
|
||||
|
||||
|
||||
// 删除elseBlock的phi指令中对应的basicblock.get()的传入值
|
||||
for (auto &phiinst : elseBlock->getInstructions()) {
|
||||
if (phiinst->getKind() != Instruction::kPhi) {
|
||||
break;
|
||||
}
|
||||
// 使用 delBlk 方法删除 basicblock.get() 对应的传入值
|
||||
dynamic_cast<PhiInst *>(phiinst.get())->delBlk(basicblock.get());
|
||||
dynamic_cast<PhiInst *>(phiinst.get())->removeIncomingBlock(basicblock.get());
|
||||
}
|
||||
|
||||
|
||||
} else { // cond为false或0
|
||||
|
||||
pBuilder->setPosition(basicblock.get(), basicblock->end());
|
||||
@@ -550,9 +668,8 @@ bool SysYCFGOptUtils::SysYCondBr2Br(Function *func, IRBuilder* pBuilder) {
|
||||
break;
|
||||
}
|
||||
// 使用 delBlk 方法删除 basicblock.get() 对应的传入值
|
||||
dynamic_cast<PhiInst *>(phiinst.get())->delBlk(basicblock.get());
|
||||
dynamic_cast<PhiInst *>(phiinst.get())->removeIncomingBlock(basicblock.get());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -565,28 +682,28 @@ bool SysYCFGOptUtils::SysYCondBr2Br(Function *func, IRBuilder* pBuilder) {
|
||||
// 独立的CFG优化遍的实现
|
||||
// ======================================================================
|
||||
|
||||
bool SysYDelInstAfterBrPass::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
bool SysYDelInstAfterBrPass::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
return SysYCFGOptUtils::SysYDelInstAfterBr(F);
|
||||
}
|
||||
|
||||
bool SysYDelEmptyBlockPass::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
bool SysYDelEmptyBlockPass::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
return SysYCFGOptUtils::SysYDelEmptyBlock(F, pBuilder);
|
||||
}
|
||||
|
||||
bool SysYDelNoPreBLockPass::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
bool SysYDelNoPreBLockPass::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
return SysYCFGOptUtils::SysYDelNoPreBLock(F);
|
||||
}
|
||||
|
||||
bool SysYBlockMergePass::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
return SysYCFGOptUtils::SysYBlockMerge(F);
|
||||
bool SysYBlockMergePass::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
return SysYCFGOptUtils::SysYBlockMerge(F);
|
||||
}
|
||||
|
||||
bool SysYAddReturnPass::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
bool SysYAddReturnPass::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
return SysYCFGOptUtils::SysYAddReturn(F, pBuilder);
|
||||
}
|
||||
|
||||
bool SysYCondBr2BrPass::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
bool SysYCondBr2BrPass::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
return SysYCFGOptUtils::SysYCondBr2Br(F, pBuilder);
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
} // namespace sysy
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "Mem2Reg.h"
|
||||
#include "Reg2Mem.h"
|
||||
#include "SCCP.h"
|
||||
#include "BuildCFG.h"
|
||||
#include "LargeArrayToGlobal.h"
|
||||
#include "Pass.h"
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
@@ -35,10 +37,13 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
||||
3. 添加优化passid
|
||||
*/
|
||||
// 注册分析遍
|
||||
registerAnalysisPass<sysy::DominatorTreeAnalysisPass>();
|
||||
registerAnalysisPass<sysy::LivenessAnalysisPass>();
|
||||
registerAnalysisPass<DominatorTreeAnalysisPass>();
|
||||
registerAnalysisPass<LivenessAnalysisPass>();
|
||||
|
||||
// 注册优化遍
|
||||
registerOptimizationPass<BuildCFG>();
|
||||
registerOptimizationPass<LargeArrayToGlobalPass>();
|
||||
|
||||
registerOptimizationPass<SysYDelInstAfterBrPass>();
|
||||
registerOptimizationPass<SysYDelNoPreBLockPass>();
|
||||
registerOptimizationPass<SysYBlockMergePass>();
|
||||
@@ -58,6 +63,16 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
||||
if (DEBUG) std::cout << "Applying -O1 optimizations.\n";
|
||||
if (DEBUG) std::cout << "--- Running custom optimization sequence ---\n";
|
||||
|
||||
if(DEBUG) {
|
||||
std::cout << "=== IR Before CFGOpt Optimizations ===\n";
|
||||
printPasses();
|
||||
}
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&BuildCFG::ID);
|
||||
this->addPass(&LargeArrayToGlobalPass::ID);
|
||||
this->run();
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&SysYDelInstAfterBrPass::ID);
|
||||
this->addPass(&SysYDelNoPreBLockPass::ID);
|
||||
@@ -67,6 +82,10 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
||||
this->addPass(&SysYAddReturnPass::ID);
|
||||
this->run();
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&BuildCFG::ID);
|
||||
this->run();
|
||||
|
||||
if(DEBUG) {
|
||||
std::cout << "=== IR After CFGOpt Optimizations ===\n";
|
||||
printPasses();
|
||||
@@ -107,7 +126,9 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
||||
std::cout << "=== IR After Reg2Mem Optimizations ===\n";
|
||||
printPasses();
|
||||
}
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&BuildCFG::ID);
|
||||
this->run();
|
||||
if (DEBUG) std::cout << "--- Custom optimization sequence finished ---\n";
|
||||
}
|
||||
|
||||
@@ -122,6 +143,7 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
||||
SysYPrinter printer(moduleIR);
|
||||
printer.printIR();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void PassManager::clearPasses() {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,10 @@
|
||||
#include "SysYIRPrinter.h"
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include "IR.h" // 确保IR.h包含了ArrayType、GetElementPtrInst等的定义
|
||||
|
||||
@@ -61,16 +64,21 @@ std::string SysYPrinter::getValueName(Value *value) {
|
||||
} else if (auto constInt = dynamic_cast<ConstantInteger*>(value)) { // 优先匹配具体的常量类型
|
||||
return std::to_string(constInt->getInt());
|
||||
} else if (auto constFloat = dynamic_cast<ConstantFloating*>(value)) { // 优先匹配具体的常量类型
|
||||
return std::to_string(constFloat->getFloat());
|
||||
std::ostringstream oss;
|
||||
oss << std::scientific << std::setprecision(std::numeric_limits<float>::max_digits10) << constFloat->getFloat();
|
||||
return oss.str();
|
||||
} else if (auto constUndef = dynamic_cast<UndefinedValue*>(value)) { // 如果有Undef类型
|
||||
return "undef";
|
||||
} else if (auto constVal = dynamic_cast<ConstantValue*>(value)) { // fallback for generic ConstantValue
|
||||
// 这里的逻辑可能需要根据你ConstantValue的实际设计调整
|
||||
// 确保它能处理所有可能的ConstantValue
|
||||
if (constVal->getType()->isFloat()) {
|
||||
return std::to_string(constVal->getFloat());
|
||||
if (auto constInt = dynamic_cast<ConstantInteger*>(value)) { // 优先匹配具体的常量类型
|
||||
return std::to_string(constInt->getInt());
|
||||
} else if (auto constFloat = dynamic_cast<ConstantFloating*>(value)) { // 优先匹配具体的常量类型
|
||||
std::ostringstream oss;
|
||||
oss << std::scientific << std::setprecision(std::numeric_limits<float>::max_digits10) << constFloat->getFloat();
|
||||
return oss.str();
|
||||
}
|
||||
return std::to_string(constVal->getInt());
|
||||
} else if (auto constVar = dynamic_cast<ConstantVariable*>(value)) {
|
||||
return constVar->getName(); // 假设ConstantVariable有自己的名字或通过getByIndices获取值
|
||||
} else if (auto argVar = dynamic_cast<Argument*>(value)) {
|
||||
@@ -232,6 +240,8 @@ void SysYPrinter::printInst(Instruction *pInst) {
|
||||
case Kind::kMul:
|
||||
case Kind::kDiv:
|
||||
case Kind::kRem:
|
||||
case Kind::kSRA:
|
||||
case Kind::kMulh:
|
||||
case Kind::kFAdd:
|
||||
case Kind::kFSub:
|
||||
case Kind::kFMul:
|
||||
@@ -264,6 +274,8 @@ void SysYPrinter::printInst(Instruction *pInst) {
|
||||
case Kind::kMul: std::cout << "mul"; break;
|
||||
case Kind::kDiv: std::cout << "sdiv"; break;
|
||||
case Kind::kRem: std::cout << "srem"; break;
|
||||
case Kind::kSRA: std::cout << "ashr"; break;
|
||||
case Kind::kMulh: std::cout << "mulh"; break;
|
||||
case Kind::kFAdd: std::cout << "fadd"; break;
|
||||
case Kind::kFSub: std::cout << "fsub"; break;
|
||||
case Kind::kFMul: std::cout << "fmul"; break;
|
||||
@@ -287,7 +299,12 @@ void SysYPrinter::printInst(Instruction *pInst) {
|
||||
|
||||
// Types and operands
|
||||
std::cout << " ";
|
||||
printType(binInst->getType());
|
||||
// For comparison operations, print operand types instead of result type
|
||||
if (pInst->getKind() >= Kind::kICmpEQ && pInst->getKind() <= Kind::kFCmpGE) {
|
||||
printType(binInst->getLhs()->getType());
|
||||
} else {
|
||||
printType(binInst->getType());
|
||||
}
|
||||
std::cout << " ";
|
||||
printValue(binInst->getLhs());
|
||||
std::cout << ", ";
|
||||
@@ -500,9 +517,9 @@ void SysYPrinter::printInst(Instruction *pInst) {
|
||||
if (!firstPair) std::cout << ", ";
|
||||
firstPair = false;
|
||||
std::cout << "[ ";
|
||||
printValue(phiInst->getValue(i));
|
||||
printValue(phiInst->getIncomingValue(i));
|
||||
std::cout << ", %";
|
||||
printBlock(phiInst->getBlock(i));
|
||||
printBlock(phiInst->getIncomingBlock(i));
|
||||
std::cout << " ]";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
@@ -21,6 +21,8 @@ using namespace sysy;
|
||||
|
||||
int DEBUG = 0;
|
||||
int DEEPDEBUG = 0;
|
||||
int DEEPERDEBUG = 0;
|
||||
int DEBUGLENGTH = 50;
|
||||
|
||||
static string argStopAfter;
|
||||
static string argInputFile;
|
||||
|
||||
Reference in New Issue
Block a user