Compare commits
100 Commits
midend-llv
...
deploy-202
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71b9f42400 | ||
|
|
54edd65fcb | ||
|
|
3add3f1f7a | ||
|
|
54fec11184 | ||
|
|
ef68235446 | ||
|
|
363ead0ddd | ||
| d465fb02a5 | |||
|
|
71d08850df | ||
|
|
d0321b7a88 | ||
| 3c49183280 | |||
| 7af3827098 | |||
|
|
f9432a9531 | ||
|
|
9c961be40a | ||
|
|
773a99bef7 | ||
|
|
26427e0986 | ||
|
|
1ab937961f | ||
|
|
06b4df79ee | ||
|
|
d79857feb9 | ||
| 75bcd0f883 | |||
|
|
17e5875c10 | ||
|
|
91d4a39c9a | ||
|
|
f27af6544c | ||
| 042b1a5d99 | |||
|
|
0fdcd0dd69 | ||
|
|
d7bf4b061f | ||
| 937833117e | |||
|
|
094b4c7c39 | ||
|
|
f4617b357e | ||
|
|
babb576317 | ||
|
|
0720a622c1 | ||
|
|
ad74e435ba | ||
|
|
acb0302a29 | ||
|
|
5c34cbc7b8 | ||
|
|
c9a0c700e1 | ||
|
|
b57a3f1953 | ||
|
|
f317010d76 | ||
|
|
8ca64610eb | ||
|
|
969a78a088 | ||
|
|
d77aedaf8b | ||
|
|
8763c0a11a | ||
|
|
d83dc7a2e7 | ||
|
|
e32585fd25 | ||
| 07fd22def1 | |||
|
|
c4eb1c3980 | ||
|
|
5ef01ada90 | ||
|
|
072cd3e9b5 | ||
|
|
d038884ffb | ||
|
|
467f2f6b24 | ||
|
|
7be5d25372 | ||
|
|
fdba73d5e1 | ||
|
|
8cabb1f195 | ||
|
|
fa33bf5134 | ||
|
|
a3435e7c26 | ||
|
|
7547d34598 | ||
|
|
06a368db39 | ||
|
|
48865fa805 | ||
|
|
8b5123460b | ||
|
|
cd27f5fda9 | ||
|
|
60cb8d6e49 | ||
|
|
ea944f6ba0 | ||
|
|
0c8a156485 | ||
|
|
debda205cc | ||
|
|
baef82677b | ||
|
|
f634273852 | ||
|
|
70f6a25ebc | ||
|
|
8cb807c8b9 | ||
|
|
1fab6a43f9 | ||
|
|
1e3791a801 | ||
|
|
6a7355ed28 | ||
|
|
be9ac89584 | ||
|
|
ac3358d7e3 | ||
|
|
a958435836 | ||
|
|
bd23f6154d | ||
|
|
126c38a1d9 | ||
|
|
c4c91412d1 | ||
|
|
f17e44f8d4 | ||
|
|
a406e44df3 | ||
|
|
b1a46b7d58 | ||
|
|
bd02f5f1eb | ||
|
|
f083e38615 | ||
|
|
33ca8ecf34 | ||
| d439ef7e8e | |||
|
|
926e765451 | ||
|
|
c4d1e31273 | ||
|
|
de1f74c425 | ||
|
|
3ba12bf320 | ||
|
|
167c2ac2ae | ||
|
|
32684d8255 | ||
| f2477c4af3 | |||
| b1efd481b4 | |||
|
|
676880ca05 | ||
|
|
df50eedaeb | ||
|
|
dcc075b39c | ||
|
|
f7f1cf2b41 | ||
|
|
881c2a9723 | ||
|
|
b5f14d9385 | ||
|
|
72b06c67ca | ||
|
|
ef9d7c4d03 | ||
|
|
1c7c85dd2f | ||
|
|
aa7f2bb0f5 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -36,7 +36,7 @@ doxygen
|
||||
|
||||
!/testdata/functional/*.out
|
||||
!/testdata/h_functional/*.out
|
||||
!/testdata/performance/*.out
|
||||
testdata/performance/
|
||||
build/
|
||||
.antlr
|
||||
.vscode/
|
||||
|
||||
185
Pass_ID_List.md
185
Pass_ID_List.md
@@ -228,10 +228,193 @@ Branch 和 Return 指令: 这些是终结符指令,不产生一个可用于其
|
||||
|
||||
在提供的代码中,SSAPValue 的 constantVal 是 int 类型。这使得浮点数常量传播变得复杂。对于浮点数相关的指令(kFAdd, kFMul, kFCmp, kFNeg, kFNot, kItoF, kFtoI 等),如果不能将浮点值准确地存储在 int 中,或者不能可靠地执行浮点运算,那么通常会保守地将结果设置为 Bottom。一个更完善的 SCCP 实现会使用 std::variant<int, float> 或独立的浮点常量存储来处理浮点数。
|
||||
|
||||
## LoopSR循环归纳变量强度削弱 关于魔数计算的说明
|
||||
|
||||
魔数除法的核心思想是:将除法转换为乘法和移位
|
||||
|
||||
数学原理:x / d ≈ (x * m) >> (32 + s)
|
||||
|
||||
m 是魔数 (magic number)
|
||||
s 是额外的移位量 (shift)
|
||||
>> 是算术右移
|
||||
|
||||
2^(32+s) / d ≤ m < 2^(32+s) / d + 2^s / d
|
||||
|
||||
cd /home/downright/Compiler_Opt/mysysy && python3 -c "
|
||||
# 真正的迭代原因:精度要求
|
||||
def explain_precision_requirement():
|
||||
d = 10
|
||||
|
||||
print('魔数算法需要找到精确的边界值:')
|
||||
print('目标:2^p > d * (2^31 - r),其中r是余数')
|
||||
print()
|
||||
|
||||
# 模拟我们算法的迭代过程
|
||||
p = 31
|
||||
two_p = 2**p
|
||||
r = two_p % d # 余数
|
||||
m = two_p // d # 商
|
||||
|
||||
print(f'初始状态 (p={p}):')
|
||||
print(f' 2^{p} = {two_p:,}')
|
||||
print(f' 2^{p} / {d} = {m:,} 余 {r}')
|
||||
print(f' 需要检查: 2^{p} > {d} * (2^31 - {r}) = {d * (2**31 - r):,}')
|
||||
print(f' 条件满足: {two_p > d * (2**31 - r)}')
|
||||
print()
|
||||
|
||||
# 继续迭代直到条件满足
|
||||
iteration = 0
|
||||
while r != 0 and m < 2**31:
|
||||
iteration += 1
|
||||
p += 1
|
||||
two_p *= 2
|
||||
m *= 2
|
||||
r *= 2
|
||||
if r >= d:
|
||||
m += 1
|
||||
r -= d
|
||||
|
||||
print(f'迭代 {iteration} (p={p}):')
|
||||
print(f' m = {m:,}, r = {r}')
|
||||
print(f' m < 2^31? {m < 2**31} (2^31 = {2**31:,})')
|
||||
|
||||
if m >= 2**31:
|
||||
print(f' ✗ 魔数 {m:,} 超出32位范围!')
|
||||
break
|
||||
elif r == 0:
|
||||
print(f' ✓ 余数为0,找到精确解')
|
||||
break
|
||||
|
||||
if iteration > 10: # 防止无限循环
|
||||
print(' ... (限制迭代次数)')
|
||||
break
|
||||
|
||||
explain_precision_requirement()
|
||||
"
|
||||
|
||||
问题在于精度要求。理论魔数需要非常精确,不能简单地用 2^32 / d。让我展示真正的迭代原因:
|
||||
|
||||
cd /home/downright/Compiler_Opt/mysysy && python3 -c "
|
||||
# 真正的迭代原因:精度要求
|
||||
def explain_precision_requirement():
|
||||
d = 10
|
||||
|
||||
print('魔数算法需要找到精确的边界值:')
|
||||
print('目标:2^p > d * (2^31 - r),其中r是余数')
|
||||
print()
|
||||
|
||||
# 模拟我们算法的迭代过程
|
||||
p = 31
|
||||
two_p = 2**p
|
||||
r = two_p % d # 余数
|
||||
m = two_p // d # 商
|
||||
|
||||
print(f'初始状态 (p={p}):')
|
||||
print(f' 2^{p} = {two_p:,}')
|
||||
print(f' 2^{p} / {d} = {m:,} 余 {r}')
|
||||
print(f' 需要检查: 2^{p} > {d} * (2^31 - {r}) = {d * (2**31 - r):,}')
|
||||
print(f' 条件满足: {two_p > d * (2**31 - r)}')
|
||||
print()
|
||||
|
||||
# 继续迭代直到条件满足
|
||||
iteration = 0
|
||||
while r != 0 and m < 2**31:
|
||||
iteration += 1
|
||||
p += 1
|
||||
two_p *= 2
|
||||
m *= 2
|
||||
r *= 2
|
||||
if r >= d:
|
||||
m += 1
|
||||
r -= d
|
||||
|
||||
print(f'迭代 {iteration} (p={p}):')
|
||||
print(f' m = {m:,}, r = {r}')
|
||||
print(f' m < 2^31? {m < 2**31} (2^31 = {2**31:,})')
|
||||
|
||||
if m >= 2**31:
|
||||
print(f' ✗ 魔数 {m:,} 超出32位范围!')
|
||||
break
|
||||
elif r == 0:
|
||||
print(f' ✓ 余数为0,找到精确解')
|
||||
break
|
||||
|
||||
if iteration > 10: # 防止无限循环
|
||||
print(' ... (限制迭代次数)')
|
||||
break
|
||||
|
||||
explain_precision_requirement()
|
||||
"
|
||||
|
||||
|
||||
cd /home/downright/Compiler_Opt/mysysy && python3 -c "
|
||||
# 检查初始状态是否会溢出
|
||||
def check_initial_overflow():
|
||||
int32_max = 2**31 - 1
|
||||
|
||||
print('检查不同除数的初始魔数是否会溢出:')
|
||||
print(f'32位有符号整数最大值: {int32_max:,}')
|
||||
print()
|
||||
|
||||
# 检查各种除数
|
||||
divisors = [2, 3, 5, 7, 9, 10, 11, 13, 17, 25, 100, 1000]
|
||||
|
||||
for d in divisors:
|
||||
# 初始魔数 = 2^31 / d
|
||||
initial_magic = (2**31) // d
|
||||
|
||||
overflow = initial_magic > int32_max
|
||||
status = \"溢出\" if overflow else \"安全\"
|
||||
|
||||
print(f'd={d:4d}: 初始魔数 = 2^31/{d} = {initial_magic:10,} [{status}]')
|
||||
|
||||
print()
|
||||
print('结论: 初始状态下魔数不会溢出,溢出发生在迭代过程中')
|
||||
|
||||
check_initial_overflow()
|
||||
"
|
||||
|
||||
总结
|
||||
迭代的必要性:
|
||||
|
||||
不是为了避免初始溢出(初始状态安全)
|
||||
是为了找到最精确的魔数,减少舍入误差
|
||||
每次迭代提高一倍精度,但魔数也翻倍
|
||||
溢出发生时机:
|
||||
|
||||
初始状态:2^31 / d 总是在32位范围内
|
||||
迭代过程:2^32 / d, 2^33 / d, ... 逐渐超出32位范围
|
||||
回退值的正确性:
|
||||
|
||||
回退值是基于数学理论和实践验证的标准值
|
||||
来自LLVM、GCC等成熟编译器的实现
|
||||
通过测试验证,对各种输入都能产生正确结果
|
||||
算法设计哲学:
|
||||
|
||||
先尝试最优解:通过迭代寻找最精确的魔数
|
||||
检测边界条件:当超出32位范围时及时发现
|
||||
智能回退:使用已验证的标准值保证正确性
|
||||
保持通用性:对于没有预设值的除数仍然可以工作
|
||||
|
||||
## 死归纳变量消除
|
||||
|
||||
整体架构和工作流程
|
||||
当前的归纳变量消除优化分为三个清晰的阶段:
|
||||
|
||||
识别阶段:找出所有潜在的死归纳变量
|
||||
安全性分析阶段:验证每个变量消除的安全性
|
||||
消除执行阶段:实际删除安全的死归纳变量
|
||||
|
||||
|
||||
逃逸点检测 (已修复的关键安全机制)
|
||||
数组索引检测:GEP指令被正确识别为逃逸点
|
||||
循环退出条件:用于比较和条件分支的归纳变量不会被消除
|
||||
控制流指令:condBr、br、return等被特殊处理为逃逸点
|
||||
内存操作:store/load指令经过别名分析检查
|
||||
|
||||
# 后续优化可能涉及的改动
|
||||
|
||||
## 1)将所有的alloca集中到entryblock中
|
||||
## 1)将所有的alloca集中到entryblock中(已实现)
|
||||
|
||||
好处:优化友好性,方便mem2reg提升
|
||||
目前没有实现这个机制,如果想要实现首先解决同一函数不同域的同名变量命名区分
|
||||
|
||||
266
doc/CompilerDesign.md
Normal file
266
doc/CompilerDesign.md
Normal file
@@ -0,0 +1,266 @@
|
||||
# 编译器核心技术与优化详解
|
||||
|
||||
本文档深入剖析 mysysy 编译器的内部实现,重点阐述其在前端、中端和后端所采用的核心编译技术及优化算法,并结合具体实现函数进行说明。
|
||||
|
||||
## 1. 编译器整体架构
|
||||
|
||||
本编译器采用经典的三段式架构,将编译过程清晰地划分为前端、中端和后端三个主要部分。每个部分处理不同的抽象层级,并通过定义良好的接口(AST, IR)进行通信,实现了高度的模块化。
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[源代码 .sy] --> B{前端 Frontend};
|
||||
B --> C[抽象语法树 AST];
|
||||
C --> D{中端 Midend};
|
||||
D --> E[SSA-based IR];
|
||||
E -- 优化 --> F[优化后的 IR];
|
||||
F --> G{后端 Backend};
|
||||
G --> H[目标机代码 MachineInstr];
|
||||
H --> I[RISC-V 64 汇编代码 .s];
|
||||
|
||||
subgraph 前端
|
||||
B
|
||||
end
|
||||
subgraph 中端
|
||||
D
|
||||
end
|
||||
subgraph 后端
|
||||
G
|
||||
end
|
||||
```
|
||||
|
||||
- **前端 (Frontend)**:负责词法、语法、语义分析,将 SysY 源代码解析为抽象语法树 (AST)。
|
||||
- **中端 (Midend)**:基于 AST 生成与具体机器无关的中间表示 (IR),并在此基础上进行深入的分析和优化。
|
||||
- **后端 (Backend)**:将优化后的 IR 翻译成目标平台(RISC-V 64)的汇编代码。
|
||||
|
||||
---
|
||||
|
||||
## 2. 前端技术 (Frontend)
|
||||
|
||||
前端的核心任务是进行语法和语义的分析与验证,其工作流程如下:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "前端处理流程"
|
||||
Source["源文件 (.sy)"] --> Lexer["词法分析器 (SysYLexer)"];
|
||||
Lexer --> TokenStream["Token 流"];
|
||||
TokenStream --> Parser["语法分析器 (SysYParser)"];
|
||||
Parser --> ParseTree["解析树"];
|
||||
ParseTree --> Visitor["AST构建 (SysYVisitor)"];
|
||||
Visitor --> AST[抽象语法树];
|
||||
end
|
||||
```
|
||||
|
||||
- **词法与语法分析**:
|
||||
- **技术**: 采用 **ANTLR (ANother Tool for Language Recognition)** 框架。通过在 `frontend/SysY.g4` 文件中定义的上下文无关文法,ANTLR 能够自动生成高效的 LL(*) 词法分析器 (`SysYLexer.cpp`) 和语法分析器 (`SysYParser.cpp`)。
|
||||
- **实现**: 词法分析器将字符流转换为记号 (Token) 流,语法分析器则根据文法规则将记号流组织成一棵解析树 (Parse Tree)。这棵树精确地反映了源代码的语法结构。
|
||||
|
||||
- **AST 构建**:
|
||||
- **技术**: 应用 **访问者 (Visitor) 设计模式** 遍历 ANTLR 生成的解析树。该模式将数据结构(解析树)与作用于其上的操作(AST构建逻辑)解耦。
|
||||
- **实现**: `frontend/SysYVisitor.cpp` 中定义了具体的遍历逻辑。在遍历过程中,会构建一个比解析树更抽象、更面向编译需求的**抽象语法树 (Abstract Syntax Tree, AST)**。AST 忽略了纯粹的语法细节(如括号、分号),只保留了核心的语义结构,是前端传递给中端的接口。
|
||||
|
||||
---
|
||||
|
||||
## 3. 中端技术与优化 (Midend)
|
||||
|
||||
中端是编译器的核心,所有与目标机器无关的分析和优化都在此阶段完成。
|
||||
|
||||
### 3.1. 中间表示 (IR) 及设计要点
|
||||
|
||||
- **技术**: 设计了一种三地址码(Three-Address Code)风格的中间表示,其形式和设计哲学深受 **LLVM IR** 的启发。IR 的核心特征是采用了**静态单赋值 (Static Single Assignment, SSA)** 形式。
|
||||
- **实现**: `midend/IR.cpp` 定义了 IR 的核心数据结构,如 `Instruction`, `BasicBlock`, `Function` 和 `Module`。`midend/SysYIRGenerator.cpp` 负责将前端的 AST 转换为这种 IR。在 SSA 形式下,每个变量只被赋值一次,使得变量的定义-使用关系(Def-Use Chain)变得异常清晰,极大地简化了后续的优化算法。通过继承并重写 SysYBaseVisitor 类,遍历 AST 节点生成自定义 IR,并在 IR 生成阶段实现了简单的常量传播和公共子表达式消除(CSE)。
|
||||
- **设计要点**:
|
||||
- **`alloca` 指令集中管理**:
|
||||
所有 `alloca` 指令统一放置在入口基本块,并与实际计算指令分离。这有助于后续指令调度器专注于优化计算密集型指令的执行顺序,避免内存分配指令的干扰。
|
||||
- **消除 `fallthrough` 现象**:
|
||||
通过确保所有基本块均以终结指令结尾,消除基本块间的 `fallthrough`,简化了控制流图(CFG)的构建和分析。这一做法提升了编译器整体质量,使中端各类 Pass 的编写和维护更加规范和高效。
|
||||
|
||||
### 3.2. 核心优化详解
|
||||
|
||||
编译器的分析和优化被组织成一系列独立的“遍”(Pass)。每个 Pass 都是一个独立的算法模块,对 IR 进行特定的分析或变换。这种设计具有高度的模块化和可扩展性。
|
||||
|
||||
#### 3.2.1. SSA 构建与解构
|
||||
|
||||
- **Mem2Reg (`Mem2Reg.cpp`)**:
|
||||
- **目标**: 将对栈内存 (`alloca`) 的 `load`/`store` 操作,提升为对虚拟寄存器的直接操作,并构建 SSA 形式。
|
||||
- **技术**: 该过程是实现 SSA 的关键。它依赖于**支配树 (Dominator Tree)** 分析,通过寻找变量定义块的**支配边界 (Dominance Frontier)** 来确定在何处插入 **Φ (Phi) 函数**。
|
||||
- **实现**: `Mem2RegContext::run` 驱动此过程。首先调用 `isPromotableAlloca` 识别所有仅被 `load`/`store` 使用的标量 `alloca`。然后,`insertPhis` 根据支配边界信息在必要的控制流汇合点插入 `phi` 指令。最后,`renameVariables` 递归地遍历支配树,用一个模拟的值栈来将 `load` 替换为栈顶的 SSA 值,将 `store` 视为对栈的一次 `push` 操作,从而完成重命名。值得一提的是,由于我们在IR生成阶段就将所有alloca指令统一放置在入口块,极大地简化了Mem2Reg遍的实现和支配树分析的计算。
|
||||
|
||||
- **Reg2Mem (`Reg2Mem.cpp`)**:
|
||||
- **目标**: 执行 `Mem2Reg` 的逆操作,将程序从 SSA 形式转换回基于内存的表示。这通常是为不支持 SSA 的后端做准备的**SSA解构 (SSA Destruction)** 步骤。
|
||||
- **技术**: 为每个 SSA 值(指令结果、函数参数)在函数入口创建一个 `alloca` 栈槽。然后,在每个 SSA 值的定义点之后插入一个 `store` 将其存入对应的栈槽;在每个使用点之前插入一个 `load` 从栈槽中取出值。
|
||||
- **实现**: `Reg2MemContext::run` 驱动此过程。`allocateMemoryForSSAValues` 为所有需要转换的 SSA 值创建 `alloca` 指令。`rewritePhis` 特殊处理 `phi` 指令,在每个前驱块的末尾插入 `store`。`insertLoadsAndStores` 则处理所有非 `phi` 指令的定义和使用,插入相应的 `store` 和 `load`。虽然
|
||||
|
||||
#### 3.2.2. 常量与死代码优化
|
||||
|
||||
- **SCCP (`SCCP.cpp`)**:
|
||||
- **目标**: 稀疏条件常量传播。在编译期计算常量表达式,并利用分支条件为常数的信息来消除死代码,比简单的常量传播更强大。
|
||||
- **技术**: 这是一种基于数据流分析的格理论(Lattice Theory)的优化。它为每个变量维护一个值状态,可能为 `Top` (未定义), `Constant` (某个常量值), 或 `Bottom` (非常量)。同时,它跟踪基本块的可达性,如果一个分支的条件被推断为常量,则其不可达的后继分支在分析中会被直接忽略。
|
||||
- **实现**: `SCCPContext::run` 驱动整个分析过程。它维护一个指令工作列表和一个边工作列表。`ProcessInstruction` 和 `ProcessEdge` 函数交替执行,不断地从 IR 中传播常量和可达性信息,直到达到不动点为止。最后,`PropagateConstants` 和 `SimplifyControlFlow` 将推断出的常量替换到代码中,并移除死块。
|
||||
|
||||
- **DCE (`DCE.cpp`)**:
|
||||
- **目标**: 简单死代码消除。移除那些计算结果对程序输出没有贡献的指令。
|
||||
- **技术**: 采用**标记-清除 (Mark and Sweep)** 算法。从具有副作用的指令(如 `store`, `call`, `return`)开始,反向追溯其操作数,标记所有相关的指令为“活跃”。
|
||||
- **实现**: `DCEContext::run` 实现了此算法。第一次遍历时,通过 `isAlive` 函数识别出具有副作用的“根”指令,然后调用 `addAlive` 递归地将所有依赖的指令加入 `alive_insts` 集合。第二次遍历时,所有未被标记为活跃的指令都将被删除。
|
||||
- **未来规划**: 后续开发更多分析遍会为DCE收集更多的IR信息,能够迭代出更健壮的DEC遍。
|
||||
|
||||
#### 3.2.3. 控制流图 (CFG) 优化
|
||||
|
||||
- **实现**: `SysYIRCFGOpt.cpp` 中定义了一系列用于清理和简化控制流图的 Pass。
|
||||
- **`SysYDelInstAfterBrPass`**: 删除分支指令后的死代码。
|
||||
- **`SysYDelNoPreBLockPass`**: 通过从入口块开始的图遍历(BFS),识别并删除所有不可达的基本块。
|
||||
- **`SysYDelEmptyBlockPass`**: 识别并删除仅包含一条无条件跳转指令的空块,将其前驱直接重定向到其后继。
|
||||
- **`SysYBlockMergePass`**: 如果一个块 A 只有一个后继 B,且 B 只有一个前驱 A,则将 A 和 B 合并为一个块。
|
||||
- **`SysYCondBr2BrPass`**: 如果一个条件分支的条件是常量,则将其转换为一个无条件分支。
|
||||
- **`SysYAddReturnPass`**: 确保所有没有终结指令的函数出口路径都有一个 `return` 指令,以保证 CFG 的完整性。
|
||||
|
||||
#### 3.2.4. 其他优化
|
||||
|
||||
#### 3.3. 核心分析遍
|
||||
|
||||
为了为优化遍收集信息,最大程度发掘程序优化潜力,我们目前设计并实现了以下关键的分析遍:
|
||||
|
||||
- **支配树分析 (Dominator Tree Analysis)**:
|
||||
- **技术**: 通过计算每个基本块的支配节点,构建出一棵支配树结构。我们在计算支配节点时采用了**逆后序遍历(RPO, Reverse Post Order)**,以保证数据流分析的收敛速度和正确性。在计算直接支配者(Idom, Immediate Dominator)时,采用了经典的**Lengauer-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.
@@ -20,18 +20,19 @@ QEMU_RISCV64="qemu-riscv64"
|
||||
|
||||
# --- 初始化变量 ---
|
||||
EXECUTE_MODE=false
|
||||
IR_EXECUTE_MODE=false # 新增
|
||||
IR_EXECUTE_MODE=false
|
||||
CLEAN_MODE=false
|
||||
OPTIMIZE_FLAG=""
|
||||
SYSYC_TIMEOUT=30
|
||||
LLC_TIMEOUT=10 # 新增
|
||||
LLC_TIMEOUT=10
|
||||
GCC_TIMEOUT=10
|
||||
EXEC_TIMEOUT=30
|
||||
MAX_OUTPUT_LINES=20
|
||||
MAX_OUTPUT_CHARS=1000
|
||||
SY_FILES=()
|
||||
PASSED_CASES=0
|
||||
FAILED_CASES_LIST=""
|
||||
INTERRUPTED=false # 新增
|
||||
INTERRUPTED=false
|
||||
|
||||
# =================================================================
|
||||
# --- 函数定义 ---
|
||||
@@ -50,22 +51,31 @@ show_help() {
|
||||
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
||||
echo " -et N 设置 qemu 自动化执行超时为 N 秒 (默认: 30)。"
|
||||
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 20)。"
|
||||
echo " -mc N, --max-chars N 当输出对比失败时,最多显示 N 个字符 (默认: 1000)。"
|
||||
echo " -h, --help 显示此帮助信息并退出。"
|
||||
echo ""
|
||||
echo "可在任何时候按 Ctrl+C 来中断测试并显示当前已完成的测例总结。"
|
||||
}
|
||||
|
||||
# 显示文件内容并根据行数和字符数截断的函数
|
||||
display_file_content() {
|
||||
local file_path="$1"
|
||||
local title="$2"
|
||||
local max_lines="$3"
|
||||
local max_chars="$4" # 新增参数
|
||||
if [ ! -f "$file_path" ]; then return; fi
|
||||
echo -e "$title"
|
||||
local line_count
|
||||
local char_count
|
||||
line_count=$(wc -l < "$file_path")
|
||||
char_count=$(wc -c < "$file_path")
|
||||
|
||||
if [ "$line_count" -gt "$max_lines" ]; then
|
||||
head -n "$max_lines" "$file_path"
|
||||
echo -e "\e[33m[... 输出已截断,共 ${line_count} 行 ...]\e[0m"
|
||||
echo -e "\e[33m[... 输出因行数过多 (共 ${line_count} 行) 而截断 ...]\e[0m"
|
||||
elif [ "$char_count" -gt "$max_chars" ]; then
|
||||
head -c "$max_chars" "$file_path"
|
||||
echo -e "\n\e[33m[... 输出因字符数过多 (共 ${char_count} 字符) 而截断 ...]\e[0m"
|
||||
else
|
||||
cat "$file_path"
|
||||
fi
|
||||
@@ -131,6 +141,7 @@ while [[ "$#" -gt 0 ]]; do
|
||||
-gct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-et) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-mc|--max-chars) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_CHARS="$2"; shift 2; else echo "错误: --max-chars 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-h|--help) show_help; exit 0 ;;
|
||||
-*) echo "未知选项: $1"; show_help; exit 1 ;;
|
||||
*)
|
||||
@@ -180,6 +191,8 @@ TOTAL_CASES=${#SY_FILES[@]}
|
||||
echo "SysY 单例测试运行器启动..."
|
||||
if [ -n "$OPTIMIZE_FLAG" ]; then echo "优化等级: ${OPTIMIZE_FLAG}"; fi
|
||||
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, llc=${LLC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
|
||||
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
|
||||
echo "失败输出最大字符数: ${MAX_OUTPUT_CHARS}"
|
||||
echo ""
|
||||
|
||||
for sy_file in "${SY_FILES[@]}"; do
|
||||
@@ -207,13 +220,13 @@ for sy_file in "${SY_FILES[@]}"; do
|
||||
|
||||
if [ "$compilation_ok" -eq 1 ]; then
|
||||
echo " [2/3] 使用 llc 编译为汇编 (超时 ${LLC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${LLC_TIMEOUT} "${LLC_CMD}" -march=riscv64 -mcpu=generic-rv64 -mattr=+m,+a,+f,+d,+c -filetype=asm "${ir_file}" -o "${assembly_file}"
|
||||
timeout -s KILL ${LLC_TIMEOUT} "${LLC_CMD}" -O3 -march=riscv64 -mcpu=generic-rv64 -mattr=+m,+a,+f,+d,+c -filetype=asm "${ir_file}" -o "${assembly_file}"
|
||||
if [ $? -ne 0 ]; then echo -e "\e[31m错误: llc 编译失败或超时。\e[0m"; compilation_ok=0; fi
|
||||
fi
|
||||
|
||||
if [ "$compilation_ok" -eq 1 ]; then
|
||||
echo " [3/3] 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
|
||||
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -O3 -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
|
||||
if [ $? -ne 0 ]; then echo -e "\e[31m错误: GCC 编译失败或超时。\e[0m"; compilation_ok=0; fi
|
||||
fi
|
||||
else # EXECUTE_MODE
|
||||
@@ -224,7 +237,7 @@ for sy_file in "${SY_FILES[@]}"; do
|
||||
|
||||
if [ "$compilation_ok" -eq 1 ]; then
|
||||
echo " [2/2] 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
|
||||
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -O3 -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
|
||||
if [ $? -ne 0 ]; then echo -e "\e[31m错误: GCC 编译失败或超时。\e[0m"; compilation_ok=0; fi
|
||||
fi
|
||||
fi
|
||||
@@ -260,8 +273,8 @@ for sy_file in "${SY_FILES[@]}"; do
|
||||
out_ok=1
|
||||
if ! diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
||||
echo -e "\e[31m 标准输出测试失败。\e[0m"; out_ok=0
|
||||
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
fi
|
||||
|
||||
if [ "$ret_ok" -eq 1 ] && [ "$out_ok" -eq 1 ]; then echo -e "\e[32m 返回码与标准输出测试成功。\e[0m"; else is_passed=0; fi
|
||||
@@ -271,8 +284,8 @@ for sy_file in "${SY_FILES[@]}"; do
|
||||
echo -e "\e[32m 标准输出测试成功。\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 标准输出测试失败。\e[0m"; is_passed=0
|
||||
display_file_content "${output_reference_file}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
display_file_content "${output_reference_file}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
@@ -301,4 +314,4 @@ for sy_file in "${SY_FILES[@]}"; do
|
||||
done
|
||||
|
||||
# --- 打印最终总结 ---
|
||||
print_summary
|
||||
print_summary
|
||||
|
||||
@@ -27,11 +27,12 @@ LLC_TIMEOUT=10
|
||||
GCC_TIMEOUT=10
|
||||
EXEC_TIMEOUT=30
|
||||
MAX_OUTPUT_LINES=20
|
||||
MAX_OUTPUT_CHARS=1000
|
||||
TEST_SETS=()
|
||||
TOTAL_CASES=0
|
||||
PASSED_CASES=0
|
||||
FAILED_CASES_LIST=""
|
||||
INTERRUPTED=false # 新增:用于标记是否被中断
|
||||
INTERRUPTED=false
|
||||
|
||||
# =================================================================
|
||||
# --- 函数定义 ---
|
||||
@@ -53,6 +54,7 @@ show_help() {
|
||||
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
||||
echo " -et N 设置 qemu 执行超时为 N 秒 (默认: 30)。"
|
||||
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 20)。"
|
||||
echo " -mc N, --max-chars N 当输出对比失败时,最多显示 N 个字符 (默认: 1000)。"
|
||||
echo " -h, --help 显示此帮助信息并退出。"
|
||||
echo ""
|
||||
echo "注意: 默认行为 (无 -e 或 -eir) 是将 .sy 文件同时编译为 .s (汇编) 和 .ll (IR),不执行。"
|
||||
@@ -60,18 +62,25 @@ show_help() {
|
||||
}
|
||||
|
||||
|
||||
# 显示文件内容并根据行数截断的函数
|
||||
# 显示文件内容并根据行数和字符数截断的函数
|
||||
display_file_content() {
|
||||
local file_path="$1"
|
||||
local title="$2"
|
||||
local max_lines="$3"
|
||||
local max_chars="$4" # 新增参数
|
||||
if [ ! -f "$file_path" ]; then return; fi
|
||||
echo -e "$title"
|
||||
local line_count
|
||||
local char_count
|
||||
line_count=$(wc -l < "$file_path")
|
||||
char_count=$(wc -c < "$file_path")
|
||||
|
||||
if [ "$line_count" -gt "$max_lines" ]; then
|
||||
head -n "$max_lines" "$file_path"
|
||||
echo -e "\e[33m[... 输出已截断,共 ${line_count} 行 ...]\e[0m"
|
||||
echo -e "\e[33m[... 输出因行数过多 (共 ${line_count} 行) 而截断 ...]\e[0m"
|
||||
elif [ "$char_count" -gt "$max_chars" ]; then
|
||||
head -c "$max_chars" "$file_path"
|
||||
echo -e "\n\e[33m[... 输出因字符数过多 (共 ${char_count} 字符) 而截断 ...]\e[0m"
|
||||
else
|
||||
cat "$file_path"
|
||||
fi
|
||||
@@ -151,6 +160,7 @@ while [[ "$#" -gt 0 ]]; do
|
||||
-gct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-et) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-mc|--max-chars) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_CHARS="$2"; shift 2; else echo "错误: --max-chars 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-h|--help) show_help; exit 0 ;;
|
||||
*) echo "未知选项: $1"; show_help; exit 1 ;;
|
||||
esac
|
||||
@@ -204,6 +214,7 @@ echo "运行模式: ${RUN_MODE_INFO}"
|
||||
echo "${TIMEOUT_INFO}"
|
||||
if ${EXECUTE_MODE} || ${IR_EXECUTE_MODE}; then
|
||||
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
|
||||
echo "失败输出最大字符数: ${MAX_OUTPUT_CHARS}"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
@@ -298,8 +309,8 @@ while IFS= read -r sy_file; do
|
||||
[ "$test_logic_passed" -eq 1 ] && echo -e "\e[32m 标准输出测试成功\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 标准输出测试失败\e[0m"
|
||||
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
display_file_content "${output_actual_file_from_ir}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
display_file_content "${output_actual_file_from_ir}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
test_logic_passed=0
|
||||
fi
|
||||
else
|
||||
@@ -308,8 +319,8 @@ while IFS= read -r sy_file; do
|
||||
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 失败: 输出不匹配\e[0m"
|
||||
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
display_file_content "${output_actual_file_from_ir}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
display_file_content "${output_actual_file_from_ir}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
test_logic_passed=0
|
||||
fi
|
||||
fi
|
||||
@@ -375,8 +386,8 @@ while IFS= read -r sy_file; do
|
||||
[ "$test_logic_passed" -eq 1 ] && echo -e "\e[32m 标准输出测试成功\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 标准输出测试失败\e[0m"
|
||||
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
display_file_content "${output_actual_file_S}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
display_file_content "${output_actual_file_S}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
test_logic_passed=0
|
||||
fi
|
||||
else
|
||||
@@ -385,8 +396,8 @@ while IFS= read -r sy_file; do
|
||||
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 失败: 输出不匹配\e[0m"
|
||||
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
display_file_content "${output_actual_file_S}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
display_file_content "${output_actual_file_S}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
test_logic_passed=0
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -5,6 +5,9 @@ add_library(riscv64_backend_lib STATIC
|
||||
RISCv64ISel.cpp
|
||||
RISCv64LLIR.cpp
|
||||
RISCv64RegAlloc.cpp
|
||||
RISCv64LinearScan.cpp
|
||||
RISCv64SimpleRegAlloc.cpp
|
||||
RISCv64BasicBlockAlloc.cpp
|
||||
Handler/CalleeSavedHandler.cpp
|
||||
Handler/LegalizeImmediates.cpp
|
||||
Handler/PrologueEpilogueInsertion.cpp
|
||||
|
||||
@@ -95,7 +95,7 @@ void LegalizeImmediatesPass::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
case RVOpcodes::LB: case RVOpcodes::LH: case RVOpcodes::LW: case RVOpcodes::LD:
|
||||
case RVOpcodes::LBU: case RVOpcodes::LHU: case RVOpcodes::LWU:
|
||||
case RVOpcodes::SB: case RVOpcodes::SH: case RVOpcodes::SW: case RVOpcodes::SD:
|
||||
case RVOpcodes::FLW: case RVOpcodes::FSW: {
|
||||
case RVOpcodes::FLW: case RVOpcodes::FSW: case RVOpcodes::FLD: case RVOpcodes::FSD: {
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
auto mem_op = static_cast<MemOperand*>(operands.back().get());
|
||||
auto offset_op = mem_op->getOffset();
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
namespace sysy {
|
||||
|
||||
char PeepholeOptimizer::ID = 0;
|
||||
bool PeepholeOptimizer::fusedMulAddEnabled = true; // 默认启用浮点乘加融合优化
|
||||
|
||||
bool PeepholeOptimizer::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
// This pass works on MachineFunction level, not IR level
|
||||
@@ -634,6 +635,99 @@ void PeepholeOptimizer::runOnMachineFunction(MachineFunction *mfunc) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 8. 浮点乘加融合优化
|
||||
// 8.1 fmul.s t1, t2, t3; fadd.s t4, t1, t5 -> fmadd.s t4, t2, t3, t5
|
||||
else if (isFusedMulAddEnabled() &&
|
||||
mi1->getOpcode() == RVOpcodes::FMUL_S &&
|
||||
mi2->getOpcode() == RVOpcodes::FADD_S) {
|
||||
if (mi1->getOperands().size() == 3 && mi2->getOperands().size() == 3) {
|
||||
auto *fmul_dst = static_cast<RegOperand *>(mi1->getOperands()[0].get());
|
||||
auto *fmul_src1 = static_cast<RegOperand *>(mi1->getOperands()[1].get());
|
||||
auto *fmul_src2 = static_cast<RegOperand *>(mi1->getOperands()[2].get());
|
||||
|
||||
auto *fadd_dst = static_cast<RegOperand *>(mi2->getOperands()[0].get());
|
||||
auto *fadd_src1 = static_cast<RegOperand *>(mi2->getOperands()[1].get());
|
||||
auto *fadd_src2 = static_cast<RegOperand *>(mi2->getOperands()[2].get());
|
||||
|
||||
// 检查fmul的目标是否是fadd的第一个源操作数
|
||||
if (areRegsEqual(fmul_dst, fadd_src1)) {
|
||||
// 检查中间寄存器是否在后续还会被使用
|
||||
bool canOptimize = true;
|
||||
for (size_t j = i + 2; j < instrs.size(); ++j) {
|
||||
auto *later_instr = instrs[j].get();
|
||||
|
||||
// 如果中间寄存器被重新定义,则可以优化
|
||||
if (isRegRedefinedAt(later_instr, fmul_dst, areRegsEqual)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 如果中间寄存器被使用,则不能优化
|
||||
if (isRegUsedLater(instrs, fmul_dst, j)) {
|
||||
canOptimize = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (canOptimize) {
|
||||
// 创建新的FMADD_S指令: fmadd.s t4, t2, t3, t5
|
||||
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::FMADD_S);
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*fadd_dst));
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*fmul_src1));
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*fmul_src2));
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*fadd_src2));
|
||||
instrs[i + 1] = std::move(newInstr);
|
||||
instrs.erase(instrs.begin() + i);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 8.2 fmul.s t1, t2, t3; fadd.s t4, t5, t1 -> fmadd.s t4, t2, t3, t5
|
||||
else if (isFusedMulAddEnabled() &&
|
||||
mi1->getOpcode() == RVOpcodes::FMUL_S &&
|
||||
mi2->getOpcode() == RVOpcodes::FADD_S) {
|
||||
if (mi1->getOperands().size() == 3 && mi2->getOperands().size() == 3) {
|
||||
auto *fmul_dst = static_cast<RegOperand *>(mi1->getOperands()[0].get());
|
||||
auto *fmul_src1 = static_cast<RegOperand *>(mi1->getOperands()[1].get());
|
||||
auto *fmul_src2 = static_cast<RegOperand *>(mi1->getOperands()[2].get());
|
||||
|
||||
auto *fadd_dst = static_cast<RegOperand *>(mi2->getOperands()[0].get());
|
||||
auto *fadd_src1 = static_cast<RegOperand *>(mi2->getOperands()[1].get());
|
||||
auto *fadd_src2 = static_cast<RegOperand *>(mi2->getOperands()[2].get());
|
||||
|
||||
// 检查fmul的目标是否是fadd的第二个源操作数
|
||||
if (areRegsEqual(fmul_dst, fadd_src2)) {
|
||||
// 检查中间寄存器是否在后续还会被使用
|
||||
bool canOptimize = true;
|
||||
for (size_t j = i + 2; j < instrs.size(); ++j) {
|
||||
auto *later_instr = instrs[j].get();
|
||||
|
||||
// 如果中间寄存器被重新定义,则可以优化
|
||||
if (isRegRedefinedAt(later_instr, fmul_dst, areRegsEqual)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 如果中间寄存器被使用,则不能优化
|
||||
if (isRegUsedLater(instrs, fmul_dst, j)) {
|
||||
canOptimize = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (canOptimize) {
|
||||
// 创建新的FMADD_S指令: fmadd.s t4, t2, t3, t5
|
||||
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::FMADD_S);
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*fadd_dst));
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*fmul_src1));
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*fmul_src2));
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*fadd_src1));
|
||||
instrs[i + 1] = std::move(newInstr);
|
||||
instrs.erase(instrs.begin() + i);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 根据是否发生变化调整遍历索引
|
||||
if (!changed) {
|
||||
|
||||
@@ -5,23 +5,6 @@
|
||||
#include <iostream>
|
||||
namespace sysy {
|
||||
|
||||
// 检查是否为内存加载/存储指令,以处理特殊的打印格式
|
||||
bool isMemoryOp(RVOpcodes opcode) {
|
||||
switch (opcode) {
|
||||
// --- 整数加载/存储 (原有逻辑) ---
|
||||
case RVOpcodes::LB: case RVOpcodes::LH: case RVOpcodes::LW: case RVOpcodes::LD:
|
||||
case RVOpcodes::LBU: case RVOpcodes::LHU: case RVOpcodes::LWU:
|
||||
case RVOpcodes::SB: case RVOpcodes::SH: case RVOpcodes::SW: case RVOpcodes::SD:
|
||||
case RVOpcodes::FLW:
|
||||
case RVOpcodes::FSW:
|
||||
// 如果未来支持双精度,也在这里添加FLD/FSD
|
||||
// case RVOpcodes::FLD:
|
||||
// case RVOpcodes::FSD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
RISCv64AsmPrinter::RISCv64AsmPrinter(MachineFunction* mfunc) : MFunc(mfunc) {}
|
||||
|
||||
@@ -82,7 +65,7 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
|
||||
case RVOpcodes::SB: *OS << "sb "; break; case RVOpcodes::LD: *OS << "ld "; break;
|
||||
case RVOpcodes::SD: *OS << "sd "; break; case RVOpcodes::FLW: *OS << "flw "; break;
|
||||
case RVOpcodes::FSW: *OS << "fsw "; break; case RVOpcodes::FLD: *OS << "fld "; break;
|
||||
case RVOpcodes::FSD: *OS << "fsd "; break;
|
||||
case RVOpcodes::FSD: *OS << "fsd "; break;
|
||||
case RVOpcodes::J: *OS << "j "; break; case RVOpcodes::JAL: *OS << "jal "; break;
|
||||
case RVOpcodes::JALR: *OS << "jalr "; break; case RVOpcodes::RET: *OS << "ret"; break;
|
||||
case RVOpcodes::BEQ: *OS << "beq "; break; case RVOpcodes::BNE: *OS << "bne "; break;
|
||||
@@ -96,15 +79,18 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
|
||||
case RVOpcodes::FSUB_S: *OS << "fsub.s "; break;
|
||||
case RVOpcodes::FMUL_S: *OS << "fmul.s "; break;
|
||||
case RVOpcodes::FDIV_S: *OS << "fdiv.s "; break;
|
||||
case RVOpcodes::FMADD_S: *OS << "fmadd.s "; break;
|
||||
case RVOpcodes::FNEG_S: *OS << "fneg.s "; break;
|
||||
case RVOpcodes::FEQ_S: *OS << "feq.s "; break;
|
||||
case RVOpcodes::FLT_S: *OS << "flt.s "; break;
|
||||
case RVOpcodes::FLE_S: *OS << "fle.s "; break;
|
||||
case RVOpcodes::FCVT_S_W: *OS << "fcvt.s.w "; break;
|
||||
case RVOpcodes::FCVT_W_S: *OS << "fcvt.w.s "; break;
|
||||
case RVOpcodes::FCVT_W_S_RTZ: *OS << "fcvt.w.s "; break;
|
||||
case RVOpcodes::FMV_S: *OS << "fmv.s "; break;
|
||||
case RVOpcodes::FMV_W_X: *OS << "fmv.w.x "; break;
|
||||
case RVOpcodes::FMV_X_W: *OS << "fmv.x.w "; break;
|
||||
case RVOpcodes::FSRMI: *OS << "fsrmi "; break;
|
||||
case RVOpcodes::CALL: { // 为CALL指令添加特殊处理逻辑
|
||||
*OS << "call ";
|
||||
// 遍历所有操作数,只寻找并打印函数名标签
|
||||
@@ -199,7 +185,7 @@ void RISCv64AsmPrinter::printOperand(MachineOperand* op) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string RISCv64AsmPrinter::regToString(PhysicalReg reg) {
|
||||
std::string RISCv64AsmPrinter::regToString(PhysicalReg reg) const {
|
||||
switch (reg) {
|
||||
case PhysicalReg::ZERO: return "x0"; case PhysicalReg::RA: return "ra";
|
||||
case PhysicalReg::SP: return "sp"; case PhysicalReg::GP: return "gp";
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
#include "RISCv64Backend.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include "RISCv64RegAlloc.h"
|
||||
#include "RISCv64LinearScan.h"
|
||||
#include "RISCv64SimpleRegAlloc.h"
|
||||
#include "RISCv64BasicBlockAlloc.h"
|
||||
#include "RISCv64AsmPrinter.h"
|
||||
#include "RISCv64Passes.h"
|
||||
#include <sstream>
|
||||
|
||||
#include <future>
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
namespace sysy {
|
||||
|
||||
// 顶层入口
|
||||
@@ -100,13 +108,14 @@ std::string RISCv64CodeGen::module_gen() {
|
||||
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);
|
||||
// bool is_large_zero_array = is_all_zeros && (total_size > 64);
|
||||
|
||||
if (is_large_zero_array) {
|
||||
bss_globals.push_back(global);
|
||||
} else {
|
||||
data_globals.push_back(global);
|
||||
}
|
||||
// if (is_large_zero_array) {
|
||||
// bss_globals.push_back(global);
|
||||
// } else {
|
||||
// data_globals.push_back(global);
|
||||
// }
|
||||
data_globals.push_back(global);
|
||||
}
|
||||
|
||||
// --- 步骤2:生成 .bss 段的代码 ---
|
||||
@@ -133,7 +142,7 @@ std::string RISCv64CodeGen::module_gen() {
|
||||
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";
|
||||
@@ -193,29 +202,20 @@ std::string RISCv64CodeGen::module_gen() {
|
||||
}
|
||||
|
||||
std::string RISCv64CodeGen::function_gen(Function* func) {
|
||||
// === 完整的后端处理流水线 ===
|
||||
|
||||
// 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers)
|
||||
DEBUG = 0;
|
||||
DEEPDEBUG = 0;
|
||||
|
||||
RISCv64ISel isel;
|
||||
std::unique_ptr<MachineFunction> mfunc = isel.runOnFunction(func);
|
||||
|
||||
// 第一次调试打印输出
|
||||
std::stringstream ss_after_isel;
|
||||
RISCv64AsmPrinter printer_isel(mfunc.get());
|
||||
printer_isel.run(ss_after_isel, true);
|
||||
if (DEBUG) {
|
||||
std::cout << ss_after_isel.str();
|
||||
}
|
||||
// DEBUG = 1;
|
||||
if (DEBUG) {
|
||||
std::cerr << "====== Intermediate Representation after Instruction Selection ======\n"
|
||||
<< ss_after_isel.str();
|
||||
}
|
||||
|
||||
// DEBUG = 0;
|
||||
// 阶段 2: 消除帧索引 (展开伪指令,计算局部变量偏移)
|
||||
// 这个Pass必须在寄存器分配之前运行
|
||||
EliminateFrameIndicesPass efi_pass;
|
||||
efi_pass.runOnMachineFunction(mfunc.get());
|
||||
|
||||
@@ -228,18 +228,106 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
||||
<< ss_after_eli.str();
|
||||
}
|
||||
|
||||
// 阶段 2: 除法强度削弱优化 (Division Strength Reduction)
|
||||
// 阶段 2.1: 除法强度削弱优化 (Division Strength Reduction)
|
||||
DivStrengthReduction div_strength_reduction;
|
||||
div_strength_reduction.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 2.1: 指令调度 (Instruction Scheduling)
|
||||
PreRA_Scheduler scheduler;
|
||||
scheduler.runOnMachineFunction(mfunc.get());
|
||||
// // 阶段 2.2: 指令调度 (Instruction Scheduling)
|
||||
// PreRA_Scheduler scheduler;
|
||||
// scheduler.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 3: 物理寄存器分配 (Register Allocation)
|
||||
RISCv64RegAlloc reg_alloc(mfunc.get());
|
||||
reg_alloc.run();
|
||||
bool allocation_succeeded = false;
|
||||
|
||||
// 尝试迭代图着色 (IRC)
|
||||
if (!irc_failed) {
|
||||
if (DEBUG) std::cerr << "Attempting Register Allocation with Iterated Register Coloring (IRC)...\n";
|
||||
RISCv64RegAlloc irc_alloc(mfunc.get());
|
||||
auto stop_flag = std::make_shared<std::atomic<bool>>(false);
|
||||
auto future = std::async(std::launch::async, &RISCv64RegAlloc::run, &irc_alloc, stop_flag);
|
||||
std::future_status status = future.wait_for(std::chrono::seconds(25));
|
||||
bool success_irc = false;
|
||||
if (status == std::future_status::ready) {
|
||||
try {
|
||||
if (future.get()) {
|
||||
success_irc = true;
|
||||
} else {
|
||||
std::cerr << "Warning: IRC explicitly returned failure for function '" << func->getName() << "'.\n";
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Error: IRC allocation threw an exception: " << e.what() << std::endl;
|
||||
}
|
||||
} else if (status == std::future_status::timeout) {
|
||||
std::cerr << "Warning: IRC allocation timed out after 25 seconds. Requesting cancellation...\n";
|
||||
stop_flag->store(true);
|
||||
try {
|
||||
future.get();
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Exception occurred during IRC thread shutdown after timeout: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (success_irc) {
|
||||
allocation_succeeded = true;
|
||||
if (DEBUG) std::cerr << "IRC allocation succeeded.\n";
|
||||
} else {
|
||||
std::cerr << "Info: Blacklisting IRC for subsequent functions and falling back.\n";
|
||||
irc_failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试简单图着色 (SGC)
|
||||
if (!allocation_succeeded) {
|
||||
// 如果是从IRC失败回退过来的,需要重新创建干净的mfunc和ISel
|
||||
RISCv64ISel isel_for_sgc;
|
||||
if (irc_failed) {
|
||||
if (DEBUG) std::cerr << "Info: Resetting MachineFunction for SGC attempt.\n";
|
||||
mfunc = isel_for_sgc.runOnFunction(func);
|
||||
EliminateFrameIndicesPass efi_pass_for_sgc;
|
||||
efi_pass_for_sgc.runOnMachineFunction(mfunc.get());
|
||||
}
|
||||
|
||||
if (DEBUG) std::cerr << "Attempting Register Allocation with Simple Graph Coloring (SGC)...\n";
|
||||
|
||||
bool sgc_completed_in_time = false;
|
||||
{
|
||||
RISCv64SimpleRegAlloc sgc_alloc(mfunc.get());
|
||||
auto future = std::async(std::launch::async, &RISCv64SimpleRegAlloc::run, &sgc_alloc);
|
||||
std::future_status status = future.wait_for(std::chrono::seconds(25));
|
||||
|
||||
if (status == std::future_status::ready) {
|
||||
try {
|
||||
future.get(); // 检查是否有异常
|
||||
sgc_completed_in_time = true;
|
||||
if (DEBUG) std::cerr << "SGC allocation completed successfully within the time limit.\n";
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Error: SGC allocation threw an exception: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sgc_completed_in_time) {
|
||||
allocation_succeeded = true;
|
||||
} else {
|
||||
std::cerr << "Warning: SGC allocation timed out or failed for function '" << func->getName()
|
||||
<< "'. Falling back.\n";
|
||||
}
|
||||
}
|
||||
|
||||
// 如果都失败了,则使用基本块分配器 (BBA)
|
||||
if (!allocation_succeeded) {
|
||||
// 为BBA准备干净的mfunc和ISel
|
||||
std::cerr << "Info: Resetting MachineFunction for BBA fallback.\n";
|
||||
RISCv64ISel isel_for_bba;
|
||||
mfunc = isel_for_bba.runOnFunction(func);
|
||||
EliminateFrameIndicesPass efi_pass_for_bba;
|
||||
efi_pass_for_bba.runOnMachineFunction(mfunc.get());
|
||||
|
||||
std::cerr << "Info: Using Basic Block Allocator as final fallback.\n";
|
||||
RISCv64BasicBlockAlloc bb_alloc(mfunc.get());
|
||||
bb_alloc.run();
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cerr << "====== stack info after reg alloc ======\n";
|
||||
mfunc->dumpStackFrameInfo(std::cerr);
|
||||
@@ -258,9 +346,9 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
||||
PeepholeOptimizer peephole;
|
||||
peephole.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 5: 局部指令调度 (Local Scheduling)
|
||||
PostRA_Scheduler local_scheduler;
|
||||
local_scheduler.runOnMachineFunction(mfunc.get());
|
||||
// // 阶段 5: 局部指令调度 (Local Scheduling)
|
||||
// PostRA_Scheduler local_scheduler;
|
||||
// local_scheduler.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 3.2: 插入序言和尾声
|
||||
PrologueEpilogueInsertionPass pei_pass;
|
||||
@@ -276,7 +364,6 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
||||
printer.run(ss);
|
||||
|
||||
return ss.str();
|
||||
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
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
|
||||
@@ -103,6 +103,60 @@ void RISCv64ISel::select() {
|
||||
}
|
||||
}
|
||||
|
||||
if (optLevel > 0) {
|
||||
if (F && !F->getBasicBlocks().empty()) {
|
||||
// 定位到第一个MachineBasicBlock,也就是函数入口
|
||||
BasicBlock* first_ir_block = F->getBasicBlocks_NoRange().front().get();
|
||||
CurMBB = bb_map.at(first_ir_block);
|
||||
|
||||
int int_arg_idx = 0;
|
||||
int fp_arg_idx = 0;
|
||||
|
||||
for (Argument* arg : F->getArguments()) {
|
||||
Type* arg_type = arg->getType();
|
||||
|
||||
// --- 处理整数/指针参数 ---
|
||||
if (!arg_type->isFloat() && int_arg_idx < 8) {
|
||||
// 1. 获取参数原始的、将被预着色为 a0-a7 的 vreg
|
||||
unsigned original_vreg = getVReg(arg);
|
||||
|
||||
// 2. 创建一个新的、安全的 vreg 来持有参数的值
|
||||
unsigned saved_vreg = getNewVReg(arg_type);
|
||||
|
||||
// 3. 生成 mv saved_vreg, original_vreg 指令
|
||||
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
mv->addOperand(std::make_unique<RegOperand>(saved_vreg));
|
||||
mv->addOperand(std::make_unique<RegOperand>(original_vreg));
|
||||
CurMBB->addInstruction(std::move(mv));
|
||||
|
||||
// 4.【关键】更新vreg映射表,将arg的vreg指向新的、安全的vreg
|
||||
// 这样,后续所有对该参数的 getVReg(arg) 调用都会自动获得 saved_vreg,
|
||||
// 使得函数体内的代码都使用这个被保存过的值。
|
||||
vreg_map[arg] = saved_vreg;
|
||||
|
||||
int_arg_idx++;
|
||||
}
|
||||
// --- 处理浮点参数 ---
|
||||
else if (arg_type->isFloat() && fp_arg_idx < 8) {
|
||||
unsigned original_vreg = getVReg(arg);
|
||||
unsigned saved_vreg = getNewVReg(arg_type);
|
||||
|
||||
// 对于浮点数,使用 fmv.s 指令
|
||||
auto fmv = std::make_unique<MachineInstr>(RVOpcodes::FMV_S);
|
||||
fmv->addOperand(std::make_unique<RegOperand>(saved_vreg));
|
||||
fmv->addOperand(std::make_unique<RegOperand>(original_vreg));
|
||||
CurMBB->addInstruction(std::move(fmv));
|
||||
|
||||
// 同样更新映射
|
||||
vreg_map[arg] = saved_vreg;
|
||||
|
||||
fp_arg_idx++;
|
||||
}
|
||||
// 对于栈传递的参数,则无需处理
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 遍历基本块,进行指令选择
|
||||
for (const auto& bb_ptr : F->getBasicBlocks()) {
|
||||
selectBasicBlock(bb_ptr.get());
|
||||
@@ -181,7 +235,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
// 加载其值的责任,被转移给了使用它们的父节点(如STORE, BINARY等)。
|
||||
case DAGNode::ARGUMENT:
|
||||
case DAGNode::CONSTANT:
|
||||
case DAGNode::ALLOCA_ADDR:
|
||||
case DAGNode::ALLOCA_ADDR: {
|
||||
if (node->value) {
|
||||
// GlobalValue objects (global variables) should not get virtual registers
|
||||
// since they represent memory addresses, not register-allocated values
|
||||
@@ -191,6 +245,8 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case DAGNode::FP_CONSTANT: {
|
||||
// RISC-V没有直接加载浮点立即数的指令
|
||||
@@ -517,7 +573,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kSRA: {
|
||||
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));
|
||||
@@ -526,6 +582,22 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case BinaryInst::kSll: { // 逻辑左移
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SLLW);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case BinaryInst::kSrl: { // 逻辑右移
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SRLW);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case BinaryInst::kICmpEQ: { // 等于 (a == b) -> (subw; seqz)
|
||||
auto sub = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
|
||||
sub->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
@@ -582,7 +654,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
CurMBB->addInstruction(std::move(xori));
|
||||
break;
|
||||
}
|
||||
case BinaryInst::kICmpGE: { // 大于等于 (a >= b) -> !(a < b) -> (slt; xori)
|
||||
case BinaryInst::kICmpGE: { // 大于等于 (a >= b) -> !(a < b) -> (slt; xori)
|
||||
auto slt = std::make_unique<MachineInstr>(RVOpcodes::SLT);
|
||||
slt->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
slt->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
@@ -745,83 +817,29 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kFtoI: { // 浮点 to 整数 (带向下取整)
|
||||
// 目标:实现 floor(x) 的效果, C/C++中浮点转整数是截断(truncate)
|
||||
// 对于正数,floor(x) == truncate(x)
|
||||
// RISC-V的 fcvt.w.s 默认是“四舍五入到偶数”
|
||||
// 我们需要手动实现截断逻辑
|
||||
// 逻辑:
|
||||
// temp_i = fcvt.w.s(x) // 四舍五入
|
||||
// temp_f = fcvt.s.w(temp_i) // 转回浮点
|
||||
// if (x < temp_f) { // 如果原数更小,说明被“五入”了
|
||||
// result = temp_i - 1
|
||||
// } else {
|
||||
// result = temp_i
|
||||
// }
|
||||
|
||||
auto temp_i_vreg = getNewVReg(Type::getIntType());
|
||||
auto temp_f_vreg = getNewVReg(Type::getFloatType());
|
||||
auto cmp_vreg = getNewVReg(Type::getIntType());
|
||||
case Instruction::kFtoI: { // 浮点 to 整数 (C/C++: 截断)
|
||||
// C/C++ 标准要求向零截断 (truncate), 对应的RISC-V舍入模式是 RTZ (Round Towards Zero).
|
||||
// fcvt.w.s 指令使用 fcsr 中的 frm 字段来决定舍入模式。
|
||||
// 我们需要手动设置 frm=1 (RTZ), 执行转换, 然后恢复 frm=0 (RNE, 默认).
|
||||
|
||||
// 1. fcvt.w.s temp_i_vreg, src_vreg
|
||||
auto fcvt_w = std::make_unique<MachineInstr>(RVOpcodes::FCVT_W_S);
|
||||
fcvt_w->addOperand(std::make_unique<RegOperand>(temp_i_vreg));
|
||||
fcvt_w->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
CurMBB->addInstruction(std::move(fcvt_w));
|
||||
// 1. fsrmi x0, 1 (set rounding mode to RTZ)
|
||||
auto fsrmi1 = std::make_unique<MachineInstr>(RVOpcodes::FSRMI);
|
||||
fsrmi1->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||
fsrmi1->addOperand(std::make_unique<ImmOperand>(1));
|
||||
CurMBB->addInstruction(std::move(fsrmi1));
|
||||
|
||||
// 2. fcvt.s.w temp_f_vreg, temp_i_vreg
|
||||
auto fcvt_s = std::make_unique<MachineInstr>(RVOpcodes::FCVT_S_W);
|
||||
fcvt_s->addOperand(std::make_unique<RegOperand>(temp_f_vreg));
|
||||
fcvt_s->addOperand(std::make_unique<RegOperand>(temp_i_vreg));
|
||||
CurMBB->addInstruction(std::move(fcvt_s));
|
||||
// 2. fcvt.w.s dest_vreg, src_vreg
|
||||
auto fcvt = std::make_unique<MachineInstr>(RVOpcodes::FCVT_W_S);
|
||||
fcvt->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
fcvt->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
CurMBB->addInstruction(std::move(fcvt));
|
||||
|
||||
// 3. flt.s cmp_vreg, src_vreg, temp_f_vreg
|
||||
auto flt = std::make_unique<MachineInstr>(RVOpcodes::FLT_S);
|
||||
flt->addOperand(std::make_unique<RegOperand>(cmp_vreg));
|
||||
flt->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
flt->addOperand(std::make_unique<RegOperand>(temp_f_vreg));
|
||||
CurMBB->addInstruction(std::move(flt));
|
||||
// 3. fsrmi x0, 0 (restore rounding mode to RNE)
|
||||
auto fsrmi0 = std::make_unique<MachineInstr>(RVOpcodes::FSRMI);
|
||||
fsrmi0->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||
fsrmi0->addOperand(std::make_unique<ImmOperand>(0));
|
||||
CurMBB->addInstruction(std::move(fsrmi0));
|
||||
|
||||
// 创建标签
|
||||
int unique_id = this->local_label_counter++;
|
||||
std::string rounded_up_label = MFunc->getName() + "_ftoi_rounded_up_" + std::to_string(unique_id);
|
||||
std::string done_label = MFunc->getName() + "_ftoi_done_" + std::to_string(unique_id);
|
||||
|
||||
// 4. bne cmp_vreg, x0, rounded_up_label
|
||||
auto bne = std::make_unique<MachineInstr>(RVOpcodes::BNE);
|
||||
bne->addOperand(std::make_unique<RegOperand>(cmp_vreg));
|
||||
bne->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||
bne->addOperand(std::make_unique<LabelOperand>(rounded_up_label));
|
||||
CurMBB->addInstruction(std::move(bne));
|
||||
|
||||
// 5. else 分支: mv dest_vreg, temp_i_vreg
|
||||
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
mv->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
mv->addOperand(std::make_unique<RegOperand>(temp_i_vreg));
|
||||
CurMBB->addInstruction(std::move(mv));
|
||||
|
||||
// 6. j done_label
|
||||
auto j = std::make_unique<MachineInstr>(RVOpcodes::J);
|
||||
j->addOperand(std::make_unique<LabelOperand>(done_label));
|
||||
CurMBB->addInstruction(std::move(j));
|
||||
|
||||
// 7. rounded_up_label:
|
||||
auto label_up = std::make_unique<MachineInstr>(RVOpcodes::LABEL);
|
||||
label_up->addOperand(std::make_unique<LabelOperand>(rounded_up_label));
|
||||
CurMBB->addInstruction(std::move(label_up));
|
||||
|
||||
// 8. addiw dest_vreg, temp_i_vreg, -1
|
||||
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDIW);
|
||||
addi->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
addi->addOperand(std::make_unique<RegOperand>(temp_i_vreg));
|
||||
addi->addOperand(std::make_unique<ImmOperand>(-1));
|
||||
CurMBB->addInstruction(std::move(addi));
|
||||
|
||||
// 9. done_label:
|
||||
auto label_done = std::make_unique<MachineInstr>(RVOpcodes::LABEL);
|
||||
label_done->addOperand(std::make_unique<LabelOperand>(done_label));
|
||||
CurMBB->addInstruction(std::move(label_done));
|
||||
|
||||
break;
|
||||
}
|
||||
case Instruction::kFNeg: { // 浮点取负
|
||||
@@ -1202,10 +1220,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) {
|
||||
@@ -1252,15 +1271,13 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
std::string loop_end_label = MFunc->getName() + "_memset_loop_end_" + std::to_string(unique_id);
|
||||
std::string remainder_label = MFunc->getName() + "_memset_remainder_" + std::to_string(unique_id);
|
||||
std::string done_label = MFunc->getName() + "_memset_done_" + std::to_string(unique_id);
|
||||
|
||||
// 构造64位的填充值
|
||||
addi_instr(RVOpcodes::ANDI, r_temp_val, r_value_byte, 255);
|
||||
addi_instr(RVOpcodes::SLLI, r_value_byte, r_temp_val, 8);
|
||||
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte);
|
||||
addi_instr(RVOpcodes::SLLI, r_value_byte, r_temp_val, 16);
|
||||
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte);
|
||||
addi_instr(RVOpcodes::SLLI, r_value_byte, r_temp_val, 32);
|
||||
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte);
|
||||
|
||||
// 构造32位的填充值 (将一个字节复制4次)
|
||||
addi_instr(RVOpcodes::ANDI, r_temp_val, r_value_byte, 255); // 提取低8位: 000000XX
|
||||
addi_instr(RVOpcodes::SLLI, r_value_byte, r_temp_val, 8); // 左移8位: 0000XX00
|
||||
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte); // 合并得到: 0000XXXX
|
||||
addi_instr(RVOpcodes::SLLI, r_value_byte, r_temp_val, 16); // 左移16位: XXXX0000
|
||||
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte); // 合并得到完整的32位值: XXXXXXXX
|
||||
|
||||
// 计算循环边界
|
||||
add_instr(RVOpcodes::ADD, r_end_addr, r_dest_addr, r_num_bytes);
|
||||
@@ -1268,16 +1285,18 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
mv->addOperand(std::make_unique<RegOperand>(r_current_addr));
|
||||
mv->addOperand(std::make_unique<RegOperand>(r_dest_addr));
|
||||
CurMBB->addInstruction(std::move(mv));
|
||||
addi_instr(RVOpcodes::ANDI, r_counter, r_num_bytes, -8);
|
||||
// 计算主循环部分的总字节数 (向下舍入到4的倍数)
|
||||
addi_instr(RVOpcodes::ANDI, r_counter, r_num_bytes, -4);
|
||||
// 计算主循环的结束地址
|
||||
add_instr(RVOpcodes::ADD, r_counter, r_dest_addr, r_counter);
|
||||
|
||||
// 8字节主循环
|
||||
// 4字节主循环
|
||||
label_instr(loop_start_label);
|
||||
branch_instr(RVOpcodes::BGEU, r_current_addr, r_counter, loop_end_label);
|
||||
store_instr(RVOpcodes::SD, r_temp_val, r_current_addr, 0);
|
||||
addi_instr(RVOpcodes::ADDI, r_current_addr, r_current_addr, 8);
|
||||
store_instr(RVOpcodes::SW, r_temp_val, r_current_addr, 0); // 使用 sw (存储字)
|
||||
addi_instr(RVOpcodes::ADDI, r_current_addr, r_current_addr, 4); // 步长改为4
|
||||
jump_instr(loop_start_label);
|
||||
|
||||
|
||||
// 1字节收尾循环
|
||||
label_instr(loop_end_label);
|
||||
label_instr(remainder_label);
|
||||
@@ -1296,7 +1315,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
|
||||
// --- Step 1: 获取基地址 (此部分逻辑正确,保持不变) ---
|
||||
auto base_ptr_node = node->operands[0];
|
||||
auto current_addr_vreg = getNewVReg();
|
||||
auto current_addr_vreg = getNewVReg(gep->getType());
|
||||
|
||||
if (auto alloca_base = dynamic_cast<AllocaInst*>(base_ptr_node->value)) {
|
||||
auto frame_addr_instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_ADDR);
|
||||
@@ -1338,13 +1357,13 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
// 如果步长为0(例如对一个void类型或空结构体索引),则不产生任何偏移
|
||||
if (stride != 0) {
|
||||
// --- 为当前索引和步长生成偏移计算指令 ---
|
||||
auto offset_vreg = getNewVReg();
|
||||
auto offset_vreg = getNewVReg(Type::getIntType());
|
||||
|
||||
// 处理索引 - 区分常量与动态值
|
||||
unsigned index_vreg;
|
||||
if (auto const_index = dynamic_cast<ConstantValue*>(indexValue)) {
|
||||
// 对于常量索引,直接创建新的虚拟寄存器
|
||||
index_vreg = getNewVReg();
|
||||
index_vreg = getNewVReg(Type::getIntType());
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(index_vreg));
|
||||
li->addOperand(std::make_unique<ImmOperand>(const_index->getInt()));
|
||||
@@ -1362,7 +1381,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));
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "RISCv64Info.h"
|
||||
#include <vector>
|
||||
#include <iostream> // 用于 std::ostream 和 std::cerr
|
||||
#include <string> // 用于 std::string
|
||||
@@ -119,4 +120,76 @@ void MachineFunction::dumpStackFrameInfo(std::ostream& os) const {
|
||||
os << "---------------------------------------------------\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief (为紧急溢出模式添加)将指令中所有对特定虚拟寄存器的引用替换为指定的物理寄存器。
|
||||
*/
|
||||
void MachineInstr::replaceVRegWithPReg(unsigned old_vreg, PhysicalReg preg) {
|
||||
for (auto& op : operands) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||
if (reg_op->isVirtual() && reg_op->getVRegNum() == old_vreg) {
|
||||
// 将虚拟寄存器操作数直接转换为物理寄存器操作数
|
||||
reg_op->setPReg(preg);
|
||||
}
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
// 同时处理内存操作数中的基址寄存器
|
||||
auto mem_op = static_cast<MemOperand*>(op.get());
|
||||
auto base_reg = mem_op->getBase();
|
||||
if (base_reg->isVirtual() && base_reg->getVRegNum() == old_vreg) {
|
||||
base_reg->setPReg(preg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief (为常规溢出模式添加)根据提供的映射表,重映射指令中的虚拟寄存器。
|
||||
* 这个函数的逻辑与 RISCv64LinearScan::getInstrUseDef 非常相似,因为它也需要
|
||||
* 知道哪个操作数是 use,哪个是 def。
|
||||
*/
|
||||
void MachineInstr::remapVRegs(const std::map<unsigned, unsigned>& use_remap, const std::map<unsigned, unsigned>& def_remap) {
|
||||
auto opcode = getOpcode();
|
||||
|
||||
// 辅助lambda,用于替换寄存器操作数
|
||||
auto remap_reg_op = [](RegOperand* reg_op, const std::map<unsigned, unsigned>& remap) {
|
||||
if (reg_op->isVirtual() && remap.count(reg_op->getVRegNum())) {
|
||||
reg_op->setVRegNum(remap.at(reg_op->getVRegNum()));
|
||||
}
|
||||
};
|
||||
|
||||
// 根据指令信息表(op_info)来确定 use 和 def
|
||||
if (op_info.count(opcode)) {
|
||||
const auto& info = op_info.at(opcode);
|
||||
// 替换 def 操作数
|
||||
for (int idx : info.first) {
|
||||
if (idx < operands.size() && operands[idx]->getKind() == MachineOperand::KIND_REG) {
|
||||
remap_reg_op(static_cast<RegOperand*>(operands[idx].get()), def_remap);
|
||||
}
|
||||
}
|
||||
// 替换 use 操作数
|
||||
for (int idx : info.second) {
|
||||
if (idx < operands.size()) {
|
||||
if (operands[idx]->getKind() == MachineOperand::KIND_REG) {
|
||||
remap_reg_op(static_cast<RegOperand*>(operands[idx].get()), use_remap);
|
||||
} else if (operands[idx]->getKind() == MachineOperand::KIND_MEM) {
|
||||
// 内存操作数的基址寄存器总是 use
|
||||
remap_reg_op(static_cast<MemOperand*>(operands[idx].get())->getBase(), use_remap);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (opcode == RVOpcodes::CALL) {
|
||||
// 处理 CALL 指令的特殊情况
|
||||
// 第一个操作数(如果存在且是寄存器)是 def
|
||||
if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) {
|
||||
remap_reg_op(static_cast<RegOperand*>(operands[0].get()), def_remap);
|
||||
}
|
||||
// 其余寄存器操作数是 use
|
||||
for (size_t i = 1; i < operands.size(); ++i) {
|
||||
if (operands[i]->getKind() == MachineOperand::KIND_REG) {
|
||||
remap_reg_op(static_cast<RegOperand*>(operands[i].get()), use_remap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
@@ -1,9 +1,13 @@
|
||||
#include "RISCv64RegAlloc.h"
|
||||
#include "RISCv64AsmPrinter.h"
|
||||
#include "RISCv64Info.h"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
@@ -44,7 +48,7 @@ RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc)
|
||||
}
|
||||
|
||||
// 主入口: 迭代运行分配算法直到无溢出
|
||||
void RISCv64RegAlloc::run() {
|
||||
bool RISCv64RegAlloc::run(std::shared_ptr<std::atomic<bool>> stop_flag) {
|
||||
if (DEBUG) std::cerr << "===== LLIR Before Running Graph Coloring Register Allocation " << MFunc->getName() << " =====\n";
|
||||
std::stringstream ss_before_reg_alloc;
|
||||
if (DEBUG) {
|
||||
@@ -59,36 +63,21 @@ void RISCv64RegAlloc::run() {
|
||||
int iteration = 0;
|
||||
|
||||
while (iteration++ < MAX_ITERATIONS) {
|
||||
// std::cerr << "Iteration Step: " << iteration << "\n";
|
||||
// std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
if (doAllocation()) {
|
||||
break;
|
||||
} else {
|
||||
rewriteProgram();
|
||||
if (stop_flag && stop_flag->load()) {
|
||||
// 如果从外部接收到停止信号
|
||||
std::cerr << "Info: IRC allocation cancelled due to timeout.\n";
|
||||
return false; // 提前退出,并返回失败
|
||||
}
|
||||
if (DEBUG) std::cerr << "--- Spilling detected, re-running allocation (iteration " << iteration << ") ---\n";
|
||||
|
||||
if (iteration >= MAX_ITERATIONS) {
|
||||
std::cerr << "ERROR: Register allocation failed to converge after " << MAX_ITERATIONS << " iterations\n";
|
||||
std::cerr << " Spill worklist size: " << spillWorklist.size() << "\n";
|
||||
std::cerr << " Total nodes: " << (initial.size() + coloredNodes.size()) << "\n";
|
||||
|
||||
// Emergency spill remaining nodes to break the loop
|
||||
std::cerr << " Emergency spilling remaining spill worklist nodes...\n";
|
||||
for (unsigned node : spillWorklist) {
|
||||
spilledNodes.insert(node);
|
||||
}
|
||||
|
||||
// Also spill any nodes that didn't get colors
|
||||
std::set<unsigned> uncolored;
|
||||
for (unsigned node : initial) {
|
||||
if (color_map.find(node) == color_map.end()) {
|
||||
uncolored.insert(node);
|
||||
}
|
||||
}
|
||||
for (unsigned node : uncolored) {
|
||||
spilledNodes.insert(node);
|
||||
}
|
||||
|
||||
// Force completion
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -98,10 +87,13 @@ void RISCv64RegAlloc::run() {
|
||||
MFunc->getFrameInfo().vreg_to_preg_map = this->color_map;
|
||||
collectUsedCalleeSavedRegs();
|
||||
if (DEBUG) std::cerr << "===== Finished Graph Coloring Register Allocation =====\n\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
// 单次分配的核心流程
|
||||
bool RISCv64RegAlloc::doAllocation() {
|
||||
const int MAX_ITERATIONS = 50;
|
||||
int iteration = 0;
|
||||
initialize();
|
||||
precolorByCallingConvention();
|
||||
analyzeLiveness();
|
||||
@@ -109,14 +101,16 @@ bool RISCv64RegAlloc::doAllocation() {
|
||||
makeWorklist();
|
||||
|
||||
while (!simplifyWorklist.empty() || !worklistMoves.empty() || !freezeWorklist.empty() || !spillWorklist.empty()) {
|
||||
if (DEEPDEBUG) dumpState("Loop Start");
|
||||
// if (DEBUG) std::cerr << "Inner Iteration Step: " << ++iteration << "\n";
|
||||
// std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
// if (DEEPDEBUG) dumpState("Loop Start");
|
||||
if (!simplifyWorklist.empty()) simplify();
|
||||
else if (!worklistMoves.empty()) coalesce();
|
||||
else if (!freezeWorklist.empty()) freeze();
|
||||
else if (!spillWorklist.empty()) selectSpill();
|
||||
}
|
||||
|
||||
if (DEEPDEBUG) dumpState("Before AssignColors");
|
||||
// if (DEEPDEBUG) dumpState("Before AssignColors");
|
||||
assignColors();
|
||||
return spilledNodes.empty();
|
||||
}
|
||||
@@ -133,20 +127,46 @@ void RISCv64RegAlloc::precolorByCallingConvention() {
|
||||
int int_arg_idx = 0;
|
||||
int float_arg_idx = 0;
|
||||
|
||||
for (Argument* arg : F->getArguments()) {
|
||||
unsigned vreg = ISel->getVReg(arg);
|
||||
|
||||
if (arg->getType()->isFloat()) {
|
||||
if (float_arg_idx < 8) { // fa0-fa7
|
||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + float_arg_idx);
|
||||
color_map[vreg] = preg;
|
||||
float_arg_idx++;
|
||||
if (optLevel > 0)
|
||||
{
|
||||
for (const auto& pair : vreg_to_value_map) {
|
||||
unsigned vreg = pair.first;
|
||||
Value* val = pair.second;
|
||||
|
||||
// 检查这个 Value* 是不是一个 Argument 对象
|
||||
if (auto arg = dynamic_cast<Argument*>(val)) {
|
||||
// 如果是,那么 vreg 就是最初分配给这个参数的 vreg
|
||||
int arg_idx = arg->getIndex();
|
||||
|
||||
if (arg->getType()->isFloat()) {
|
||||
if (arg_idx < 8) { // fa0-fa7
|
||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + arg_idx);
|
||||
color_map[vreg] = preg;
|
||||
}
|
||||
} else { // 整数或指针
|
||||
if (arg_idx < 8) { // a0-a7
|
||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + arg_idx);
|
||||
color_map[vreg] = preg;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // 整数或指针
|
||||
if (int_arg_idx < 8) { // a0-a7
|
||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_arg_idx);
|
||||
color_map[vreg] = preg;
|
||||
int_arg_idx++;
|
||||
}
|
||||
} else {
|
||||
for (Argument* arg : F->getArguments()) {
|
||||
unsigned vreg = ISel->getVReg(arg);
|
||||
|
||||
if (arg->getType()->isFloat()) {
|
||||
if (float_arg_idx < 8) { // fa0-fa7
|
||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + float_arg_idx);
|
||||
color_map[vreg] = preg;
|
||||
float_arg_idx++;
|
||||
}
|
||||
} else { // 整数或指针
|
||||
if (int_arg_idx < 8) { // a0-a7
|
||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_arg_idx);
|
||||
color_map[vreg] = preg;
|
||||
int_arg_idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -483,16 +503,18 @@ void RISCv64RegAlloc::coalesce() {
|
||||
unsigned x = getAlias(*def.begin());
|
||||
unsigned y = getAlias(*use.begin());
|
||||
unsigned u, v;
|
||||
if (precolored.count(y)) { u = y; v = x; } else { u = x; v = y; }
|
||||
|
||||
// 进一步修正:标准化u和v的逻辑,必须同时考虑物理寄存器和已预着色的虚拟寄存器。
|
||||
// 目标是确保如果两个操作数中有一个是预着色的,它一定会被赋给 u。
|
||||
if (precolored.count(y) || coloredNodes.count(y)) {
|
||||
u = y; v = x;
|
||||
} else {
|
||||
u = x; v = y;
|
||||
}
|
||||
|
||||
// 防御性检查,处理物理寄存器之间的传送指令
|
||||
if (precolored.count(u) && precolored.count(v)) {
|
||||
// 如果 u 和 v 都是物理寄存器,我们不能合并它们。
|
||||
// 这通常是一条寄存器拷贝指令,例如 `mv a2, a1`。
|
||||
// 把它加入 constrainedMoves 列表,然后直接返回,不再处理。
|
||||
constrainedMoves.insert(move);
|
||||
// addWorklist(u) 和 addWorklist(v) 在这里也不需要调用,
|
||||
// 因为它们只对虚拟寄存器有意义。
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -504,7 +526,7 @@ void RISCv64RegAlloc::coalesce() {
|
||||
if (DEEPERDEBUG) std::cerr << " -> Trivial coalesce (u == v).\n";
|
||||
coalescedMoves.insert(move);
|
||||
addWorklist(u);
|
||||
return; // 处理完毕,提前返回
|
||||
return;
|
||||
}
|
||||
|
||||
if (isFPVReg(u) != isFPVReg(v)) {
|
||||
@@ -514,10 +536,13 @@ void RISCv64RegAlloc::coalesce() {
|
||||
constrainedMoves.insert(move);
|
||||
addWorklist(u);
|
||||
addWorklist(v);
|
||||
return; // 立即返回,不再进行后续检查
|
||||
return;
|
||||
}
|
||||
|
||||
bool pre_interfere = adjList.at(v).count(u);
|
||||
// 注意:如果v已经是u的邻居, pre_interfere 会为true。
|
||||
// 但如果v不在adjList中(例如v是预着色节点),我们需要检查u是否在v的邻居中。
|
||||
// 为了简化,我们假设adjList包含了所有虚拟寄存器。对于(Phys, Virt)对,冲突信息存储在Virt节点的邻接表中。
|
||||
bool pre_interfere = (adjList.count(v) && adjList.at(v).count(u)) || (adjList.count(u) && adjList.at(u).count(v));
|
||||
|
||||
if (pre_interfere) {
|
||||
if (DEEPERDEBUG) std::cerr << " -> Constrained (nodes already interfere).\n";
|
||||
@@ -527,63 +552,50 @@ void RISCv64RegAlloc::coalesce() {
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_u_precolored = precolored.count(u);
|
||||
// 考虑物理寄存器和已预着色的虚拟寄存器
|
||||
bool u_is_effectively_precolored = precolored.count(u) || coloredNodes.count(u);
|
||||
bool can_coalesce = false;
|
||||
|
||||
if (is_u_precolored) {
|
||||
// --- 场景1:u是物理寄存器,使用 George 启发式 ---
|
||||
if (DEEPERDEBUG) std::cerr << " -> Trying George Heuristic (u is precolored)...\n";
|
||||
if (u_is_effectively_precolored) {
|
||||
// --- 场景1:u是物理寄存器或已预着色虚拟寄存器,使用 George 启发式 ---
|
||||
if (DEEPERDEBUG) std::cerr << " -> Trying George Heuristic (u is effectively precolored)...\n";
|
||||
|
||||
// 步骤 1: 独立调用 adjacent(v) 获取邻居集合
|
||||
VRegSet neighbors_of_v = adjacent(v);
|
||||
if (DEEPERDEBUG) {
|
||||
std::cerr << " - Neighbors of " << regIdToString(v) << " to check are (" << neighbors_of_v.size() << "): { ";
|
||||
for (unsigned id : neighbors_of_v) std::cerr << regIdToString(id) << " ";
|
||||
std::cerr << "}\n";
|
||||
}
|
||||
|
||||
// 步骤 2: 使用显式的 for 循环来代替 std::all_of
|
||||
bool george_ok = true; // 默认假设成功,任何一个邻居失败都会将此设为 false
|
||||
|
||||
bool george_ok = true;
|
||||
for (unsigned t : neighbors_of_v) {
|
||||
if (DEEPERDEBUG) {
|
||||
std::cerr << " - Checking neighbor " << regIdToString(t) << ":\n";
|
||||
}
|
||||
if (DEEPERDEBUG) std::cerr << " - Checking neighbor " << regIdToString(t) << ":\n";
|
||||
|
||||
// 步骤 3: 独立调用启发式函数
|
||||
bool heuristic_result = georgeHeuristic(t, u);
|
||||
unsigned u_phys_id = precolored.count(u) ? u : (static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID) + static_cast<unsigned>(color_map.at(u)));
|
||||
bool heuristic_result = georgeHeuristic(t, u_phys_id);
|
||||
|
||||
if (DEEPERDEBUG) {
|
||||
std::cerr << " - georgeHeuristic(" << regIdToString(t) << ", " << regIdToString(u) << ") -> " << (heuristic_result ? "OK" : "FAIL") << "\n";
|
||||
std::cerr << " - georgeHeuristic(" << regIdToString(t) << ", " << regIdToString(u_phys_id) << ") -> " << (heuristic_result ? "OK" : "FAIL") << "\n";
|
||||
}
|
||||
|
||||
if (!heuristic_result) {
|
||||
george_ok = false; // 只要有一个邻居不满足条件,整个检查就失败
|
||||
break; // 并且可以立即停止检查其他邻居
|
||||
george_ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (DEEPERDEBUG) {
|
||||
std::cerr << " -> George Heuristic final result: " << (george_ok ? "OK" : "FAIL") << "\n";
|
||||
}
|
||||
|
||||
if (george_ok) {
|
||||
can_coalesce = true;
|
||||
}
|
||||
if (DEEPERDEBUG) std::cerr << " -> George Heuristic final result: " << (george_ok ? "OK" : "FAIL") << "\n";
|
||||
if (george_ok) can_coalesce = true;
|
||||
|
||||
} else {
|
||||
// --- 场景2:u和v都是虚拟寄存器,使用 Briggs 启发式 ---
|
||||
// --- 场景2:u和v都是未着色的虚拟寄存器,使用 Briggs 启发式 ---
|
||||
if (DEEPERDEBUG) std::cerr << " -> Trying Briggs Heuristic (u and v are virtual)...\n";
|
||||
|
||||
bool briggs_ok = briggsHeuristic(u, v);
|
||||
if (DEEPERDEBUG) std::cerr << " - briggsHeuristic(" << regIdToString(u) << ", " << regIdToString(v) << ") -> " << (briggs_ok ? "OK" : "FAIL") << "\n";
|
||||
|
||||
if (briggs_ok) {
|
||||
can_coalesce = true;
|
||||
}
|
||||
if (briggs_ok) can_coalesce = true;
|
||||
}
|
||||
|
||||
// --- 根据启发式结果进行最终决策 ---
|
||||
|
||||
if (can_coalesce) {
|
||||
if (DEEPERDEBUG) std::cerr << " -> Heuristic OK. Combining " << regIdToString(v) << " into " << regIdToString(u) << ".\n";
|
||||
coalescedMoves.insert(move);
|
||||
@@ -884,53 +896,6 @@ void RISCv64RegAlloc::getInstrUseDef_Liveness(const MachineInstr* instr, VRegSet
|
||||
auto opcode = instr->getOpcode();
|
||||
const auto& operands = instr->getOperands();
|
||||
|
||||
// 映射表:指令操作码 -> {Def操作数索引列表, Use操作数索引列表}
|
||||
static const std::map<RVOpcodes, std::pair<std::vector<int>, std::vector<int>>> op_info = {
|
||||
// ===== 整数算术与逻辑指令 (R-type & I-type) =====
|
||||
{RVOpcodes::ADD, {{0}, {1, 2}}}, {RVOpcodes::SUB, {{0}, {1, 2}}}, {RVOpcodes::MUL, {{0}, {1, 2}}},
|
||||
{RVOpcodes::DIV, {{0}, {1, 2}}}, {RVOpcodes::REM, {{0}, {1, 2}}}, {RVOpcodes::ADDW, {{0}, {1, 2}}},
|
||||
{RVOpcodes::SUBW, {{0}, {1, 2}}}, {RVOpcodes::MULW, {{0}, {1, 2}}}, {RVOpcodes::DIVW, {{0}, {1, 2}}},
|
||||
{RVOpcodes::REMW, {{0}, {1, 2}}}, {RVOpcodes::SLT, {{0}, {1, 2}}}, {RVOpcodes::SLTU, {{0}, {1, 2}}},
|
||||
{RVOpcodes::XOR, {{0}, {1, 2}}}, {RVOpcodes::OR, {{0}, {1, 2}}}, {RVOpcodes::AND, {{0}, {1, 2}}},
|
||||
{RVOpcodes::ADDI, {{0}, {1}}}, {RVOpcodes::ADDIW, {{0}, {1}}}, {RVOpcodes::XORI, {{0}, {1}}},
|
||||
{RVOpcodes::ORI, {{0}, {1}}}, {RVOpcodes::ANDI, {{0}, {1}}},
|
||||
{RVOpcodes::SLTI, {{0}, {1}}}, {RVOpcodes::SLTIU, {{0}, {1}}},
|
||||
|
||||
// ===== 移位指令 =====
|
||||
{RVOpcodes::SLL, {{0}, {1, 2}}}, {RVOpcodes::SLLI, {{0}, {1}}},
|
||||
{RVOpcodes::SLLW, {{0}, {1, 2}}}, {RVOpcodes::SLLIW, {{0}, {1}}},
|
||||
{RVOpcodes::SRL, {{0}, {1, 2}}}, {RVOpcodes::SRLI, {{0}, {1}}},
|
||||
{RVOpcodes::SRLW, {{0}, {1, 2}}}, {RVOpcodes::SRLIW, {{0}, {1}}},
|
||||
{RVOpcodes::SRA, {{0}, {1, 2}}}, {RVOpcodes::SRAI, {{0}, {1}}},
|
||||
{RVOpcodes::SRAW, {{0}, {1, 2}}}, {RVOpcodes::SRAIW, {{0}, {1}}},
|
||||
|
||||
// ===== 内存加载指令 (Def: 0, Use: MemBase) =====
|
||||
{RVOpcodes::LB, {{0}, {}}}, {RVOpcodes::LH, {{0}, {}}}, {RVOpcodes::LW, {{0}, {}}}, {RVOpcodes::LD, {{0}, {}}},
|
||||
{RVOpcodes::LBU, {{0}, {}}}, {RVOpcodes::LHU, {{0}, {}}}, {RVOpcodes::LWU, {{0}, {}}},
|
||||
{RVOpcodes::FLW, {{0}, {}}}, {RVOpcodes::FLD, {{0}, {}}},
|
||||
|
||||
// ===== 内存存储指令 (Def: None, Use: ValToStore, MemBase) =====
|
||||
{RVOpcodes::SB, {{}, {0, 1}}}, {RVOpcodes::SH, {{}, {0, 1}}}, {RVOpcodes::SW, {{}, {0, 1}}}, {RVOpcodes::SD, {{}, {0, 1}}},
|
||||
{RVOpcodes::FSW, {{}, {0, 1}}}, {RVOpcodes::FSD, {{}, {0, 1}}},
|
||||
|
||||
// ===== 控制流指令 =====
|
||||
{RVOpcodes::BEQ, {{}, {0, 1}}}, {RVOpcodes::BNE, {{}, {0, 1}}}, {RVOpcodes::BLT, {{}, {0, 1}}},
|
||||
{RVOpcodes::BGE, {{}, {0, 1}}}, {RVOpcodes::BLTU, {{}, {0, 1}}}, {RVOpcodes::BGEU, {{}, {0, 1}}},
|
||||
{RVOpcodes::JALR, {{0}, {1}}}, // def: ra (implicit) and op0, use: op1
|
||||
|
||||
// ===== 浮点指令 =====
|
||||
{RVOpcodes::FADD_S, {{0}, {1, 2}}}, {RVOpcodes::FSUB_S, {{0}, {1, 2}}},
|
||||
{RVOpcodes::FMUL_S, {{0}, {1, 2}}}, {RVOpcodes::FDIV_S, {{0}, {1, 2}}}, {RVOpcodes::FEQ_S, {{0}, {1, 2}}},
|
||||
{RVOpcodes::FLT_S, {{0}, {1, 2}}}, {RVOpcodes::FLE_S, {{0}, {1, 2}}}, {RVOpcodes::FCVT_S_W, {{0}, {1}}},
|
||||
{RVOpcodes::FCVT_W_S, {{0}, {1}}}, {RVOpcodes::FMV_S, {{0}, {1}}}, {RVOpcodes::FMV_W_X, {{0}, {1}}},
|
||||
{RVOpcodes::FMV_X_W, {{0}, {1}}}, {RVOpcodes::FNEG_S, {{0}, {1}}},
|
||||
|
||||
// ===== 伪指令 =====
|
||||
{RVOpcodes::LI, {{0}, {}}}, {RVOpcodes::LA, {{0}, {}}},
|
||||
{RVOpcodes::MV, {{0}, {1}}}, {RVOpcodes::SEQZ, {{0}, {1}}}, {RVOpcodes::SNEZ, {{0}, {1}}},
|
||||
{RVOpcodes::NEG, {{0}, {1}}}, {RVOpcodes::NEGW, {{0}, {1}}},
|
||||
};
|
||||
|
||||
// lambda表达式用于获取操作数的寄存器ID(虚拟或物理)
|
||||
const unsigned offset = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID);
|
||||
auto get_any_reg_id = [&](const MachineOperand* op) -> unsigned {
|
||||
@@ -1186,7 +1151,7 @@ unsigned RISCv64RegAlloc::getAlias(unsigned n) {
|
||||
}
|
||||
|
||||
void RISCv64RegAlloc::addWorklist(unsigned u) {
|
||||
if (precolored.count(u)) return;
|
||||
if (precolored.count(u) || color_map.count(u)) return;
|
||||
|
||||
int K = isFPVReg(u) ? K_fp : K_int;
|
||||
if (!moveRelated(u) && degree.at(u) < K) {
|
||||
@@ -1261,8 +1226,12 @@ bool RISCv64RegAlloc::georgeHeuristic(unsigned t, unsigned u) {
|
||||
}
|
||||
|
||||
int K = isFPVReg(t) ? K_fp : K_int;
|
||||
// adjList.at(t) 现在是安全的,因为 degree.count(t) > 0 保证了 adjList.count(t) > 0
|
||||
return degree.at(t) < K || precolored.count(u) || adjList.at(t).count(u);
|
||||
|
||||
// 缺陷 #2 修正: 移除了致命的 || precolored.count(u) 条件。
|
||||
// 在此函数的上下文中,u 总是预着色的物理寄存器ID,导致旧的条件永远为true,使整个启发式失效。
|
||||
// 正确的逻辑是检查:邻居t的度数是否小于K,或者t是否已经与u冲突。
|
||||
// return degree.at(t) < K || adjList.at(t).count(u);
|
||||
return degree.at(t) < K || !adjList.at(t).count(u);
|
||||
}
|
||||
|
||||
void RISCv64RegAlloc::combine(unsigned u, unsigned v) {
|
||||
@@ -1310,7 +1279,7 @@ void RISCv64RegAlloc::freezeMoves(unsigned u) {
|
||||
activeMoves.erase(move);
|
||||
frozenMoves.insert(move);
|
||||
|
||||
if (!precolored.count(v_alias) && nodeMoves(v_alias).empty() && degree.at(v_alias) < (isFPVReg(v_alias) ? K_fp : K_int)) {
|
||||
if (!precolored.count(v_alias) && !coloredNodes.count(v_alias) && nodeMoves(v_alias).empty() && degree.at(v_alias) < (isFPVReg(v_alias) ? K_fp : K_int)) {
|
||||
freezeWorklist.erase(v_alias);
|
||||
simplifyWorklist.insert(v_alias);
|
||||
if (DEEPERDEBUG) {
|
||||
|
||||
716
src/backend/RISCv64/RISCv64SimpleRegAlloc.cpp
Normal file
716
src/backend/RISCv64/RISCv64SimpleRegAlloc.cpp
Normal file
@@ -0,0 +1,716 @@
|
||||
#include "RISCv64SimpleRegAlloc.h"
|
||||
#include "RISCv64AsmPrinter.h"
|
||||
#include "RISCv64Info.h"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
// 外部调试级别控制变量的定义
|
||||
// 假设这些变量在其他地方定义,例如主程序或一个通用的cpp文件
|
||||
extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
RISCv64SimpleRegAlloc::RISCv64SimpleRegAlloc(MachineFunction* mfunc) : MFunc(mfunc), ISel(mfunc->getISel()) {
|
||||
// 1. 初始化可分配的整数寄存器池
|
||||
// T5 被大立即数传送逻辑保留
|
||||
// T2, T3, T4 被本分配器保留为专用的溢出/临时寄存器
|
||||
allocable_int_regs = {
|
||||
PhysicalReg::T0, PhysicalReg::T1, /* T2,T3,T4,T5,T6 reserved */
|
||||
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3, PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7,
|
||||
PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3, PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
|
||||
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
|
||||
};
|
||||
|
||||
// 2. 初始化可分配的浮点寄存器池
|
||||
// F0, F1, F2 被本分配器保留为专用的溢出/临时寄存器
|
||||
allocable_fp_regs = {
|
||||
/* F0,F1,F2 reserved */ PhysicalReg::F3, PhysicalReg::F4, PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7,
|
||||
PhysicalReg::F10, PhysicalReg::F11, PhysicalReg::F12, PhysicalReg::F13, PhysicalReg::F14, PhysicalReg::F15, PhysicalReg::F16, PhysicalReg::F17,
|
||||
PhysicalReg::F8, PhysicalReg::F9, PhysicalReg::F18, PhysicalReg::F19, PhysicalReg::F20, PhysicalReg::F21, PhysicalReg::F22,
|
||||
PhysicalReg::F23, PhysicalReg::F24, PhysicalReg::F25, PhysicalReg::F26, PhysicalReg::F27,
|
||||
PhysicalReg::F28, PhysicalReg::F29, PhysicalReg::F30, PhysicalReg::F31,
|
||||
};
|
||||
|
||||
// 3. 映射所有物理寄存器到特殊的虚拟寄存器ID (保持不变)
|
||||
const unsigned offset = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID);
|
||||
for (unsigned i = 0; i < static_cast<unsigned>(PhysicalReg::INVALID); ++i) {
|
||||
auto preg = static_cast<PhysicalReg>(i);
|
||||
preg_to_vreg_id_map[preg] = offset + i;
|
||||
}
|
||||
}
|
||||
|
||||
// 寄存器分配的主入口点
|
||||
void RISCv64SimpleRegAlloc::run() {
|
||||
if (DEBUG) std::cerr << "===== Running Simple Graph Coloring Allocator for function: " << MFunc->getName() << " =====\n";
|
||||
|
||||
// 实例化一个AsmPrinter用于调试输出,避免重复创建
|
||||
RISCv64AsmPrinter printer(MFunc);
|
||||
printer.setStream(std::cerr);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cerr << "\n===== LLIR after VReg Unification =====\n";
|
||||
printer.run(std::cerr, true);
|
||||
std::cerr << "===== End of Unified LLIR =====\n\n";
|
||||
}
|
||||
|
||||
// 阶段 1: 处理函数调用约定(参数寄存器预着色)
|
||||
handleCallingConvention();
|
||||
if (DEBUG) {
|
||||
std::cerr << "--- After HandleCallingConvention ---\n";
|
||||
std::cerr << "Pre-colored vregs:\n";
|
||||
for (const auto& pair : color_map) {
|
||||
std::cerr << " %vreg" << pair.first << " -> " << printer.regToString(pair.second) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// 阶段 2: 活跃性分析
|
||||
analyzeLiveness();
|
||||
|
||||
// 阶段 3: 构建干扰图
|
||||
buildInterferenceGraph();
|
||||
|
||||
// 阶段 4: 图着色算法分配物理寄存器
|
||||
colorGraph();
|
||||
if (DEBUG) {
|
||||
std::cerr << "\n--- After GraphColoring ---\n";
|
||||
std::cerr << "Assigned colors:\n";
|
||||
for (const auto& pair : color_map) {
|
||||
std::cerr << " %vreg" << pair.first << " -> " << printer.regToString(pair.second) << "\n";
|
||||
}
|
||||
std::cerr << "Spilled vregs:\n";
|
||||
if (spilled_vregs.empty()) {
|
||||
std::cerr << " (None)\n";
|
||||
} else {
|
||||
for (unsigned vreg : spilled_vregs) {
|
||||
std::cerr << " %vreg" << vreg << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 阶段 5: 重写函数(插入溢出/填充代码,替换虚拟寄存器为物理寄存器)
|
||||
rewriteFunction();
|
||||
|
||||
// 将最终的寄存器分配结果保存到MachineFunction的帧信息中,供后续Pass使用
|
||||
MFunc->getFrameInfo().vreg_to_preg_map = this->color_map;
|
||||
|
||||
if (DEBUG) {
|
||||
std::cerr << "\n===== Final LLIR after Simple Register Allocation =====\n";
|
||||
printer.run(std::cerr, false); // 使用false来打印最终的物理寄存器
|
||||
std::cerr << "===== Finished Simple Graph Coloring Allocator =====\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief [新增] 虚拟寄存器统一预处理
|
||||
* 扫描函数,找到通过栈帧传递的参数,并将后续从该栈帧加载的VReg统一为原始的参数VReg。
|
||||
*/
|
||||
void RISCv64SimpleRegAlloc::unifyArgumentVRegs() {
|
||||
if (MFunc->getBlocks().size() < 2) return; // 至少需要入口和函数体两个块
|
||||
|
||||
std::map<int, unsigned> stack_slot_to_vreg; // 映射: <栈偏移, 原始参数vreg>
|
||||
MachineBasicBlock* entry_block = MFunc->getBlocks().front().get();
|
||||
|
||||
// 步骤 1: 扫描入口块,找到所有参数的“家(home)”在栈上的位置
|
||||
for (const auto& instr : entry_block->getInstructions()) {
|
||||
// 我们寻找 sw %vreg_arg, 0(%vreg_addr) 的模式
|
||||
if (instr->getOpcode() == RVOpcodes::SW || instr->getOpcode() == RVOpcodes::SD || instr->getOpcode() == RVOpcodes::FSW) {
|
||||
auto& operands = instr->getOperands();
|
||||
if (operands.size() == 2 && operands[0]->getKind() == MachineOperand::KIND_REG && operands[1]->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto src_reg_op = static_cast<RegOperand*>(operands[0].get());
|
||||
auto mem_op = static_cast<MemOperand*>(operands[1].get());
|
||||
unsigned addr_vreg = mem_op->getBase()->getVRegNum();
|
||||
|
||||
// 查找定义这个地址vreg的addi指令,以获取偏移量
|
||||
for (const auto& prev_instr : entry_block->getInstructions()) {
|
||||
if (prev_instr->getOpcode() == RVOpcodes::ADDI && prev_instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
||||
auto def_op = static_cast<RegOperand*>(prev_instr->getOperands().front().get());
|
||||
if (def_op->isVirtual() && def_op->getVRegNum() == addr_vreg) {
|
||||
int offset = static_cast<ImmOperand*>(prev_instr->getOperands()[2].get())->getValue();
|
||||
stack_slot_to_vreg[offset] = src_reg_op->getVRegNum();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stack_slot_to_vreg.empty()) return; // 没有找到参数存储,无需处理
|
||||
|
||||
// 步骤 2: 扫描函数体,构建本地vreg到参数vreg的重映射表
|
||||
std::map<unsigned, unsigned> vreg_remap; // 映射: <本地vreg, 原始参数vreg>
|
||||
MachineBasicBlock* body_block = MFunc->getBlocks()[1].get();
|
||||
|
||||
for (const auto& instr : body_block->getInstructions()) {
|
||||
if (instr->getOpcode() == RVOpcodes::LW || instr->getOpcode() == RVOpcodes::LD || instr->getOpcode() == RVOpcodes::FLW) {
|
||||
auto& operands = instr->getOperands();
|
||||
if (operands.size() == 2 && operands[0]->getKind() == MachineOperand::KIND_REG && operands[1]->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto dest_reg_op = static_cast<RegOperand*>(operands[0].get());
|
||||
auto mem_op = static_cast<MemOperand*>(operands[1].get());
|
||||
unsigned addr_vreg = mem_op->getBase()->getVRegNum();
|
||||
|
||||
// 同样地,查找定义地址的addi指令
|
||||
for (const auto& prev_instr : body_block->getInstructions()) {
|
||||
if (prev_instr->getOpcode() == RVOpcodes::ADDI && prev_instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
||||
auto def_op = static_cast<RegOperand*>(prev_instr->getOperands().front().get());
|
||||
if (def_op->isVirtual() && def_op->getVRegNum() == addr_vreg) {
|
||||
int offset = static_cast<ImmOperand*>(prev_instr->getOperands()[2].get())->getValue();
|
||||
if (stack_slot_to_vreg.count(offset)) {
|
||||
unsigned old_vreg = dest_reg_op->getVRegNum();
|
||||
unsigned new_vreg = stack_slot_to_vreg.at(offset);
|
||||
vreg_remap[old_vreg] = new_vreg;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vreg_remap.empty()) return;
|
||||
|
||||
// 步骤 3: 遍历所有指令,应用重映射
|
||||
// 定义一个lambda函数来替换vreg,避免代码重复
|
||||
auto replace_vreg_in_operand = [&](MachineOperand* op) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(op);
|
||||
if (reg_op->isVirtual() && vreg_remap.count(reg_op->getVRegNum())) {
|
||||
reg_op->setVRegNum(vreg_remap.at(reg_op->getVRegNum()));
|
||||
}
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto base_reg_op = static_cast<MemOperand*>(op)->getBase();
|
||||
if (base_reg_op->isVirtual() && vreg_remap.count(base_reg_op->getVRegNum())) {
|
||||
base_reg_op->setVRegNum(vreg_remap.at(base_reg_op->getVRegNum()));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
for (auto& instr : mbb->getInstructions()) {
|
||||
for (auto& op : instr->getOperands()) {
|
||||
replace_vreg_in_operand(op.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64SimpleRegAlloc::handleCallingConvention() {
|
||||
Function* F = MFunc->getFunc();
|
||||
if (!F) return;
|
||||
|
||||
// --- 1. 处理函数传入参数的预着色 ---
|
||||
int int_arg_idx = 0;
|
||||
int float_arg_idx = 0;
|
||||
|
||||
for (Argument* arg : F->getArguments()) {
|
||||
unsigned vreg = ISel->getVReg(arg);
|
||||
if (arg->getType()->isFloat()) {
|
||||
if (float_arg_idx < 8) { // fa0-fa7
|
||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + float_arg_idx);
|
||||
color_map[vreg] = preg;
|
||||
}
|
||||
float_arg_idx++;
|
||||
} else {
|
||||
if (int_arg_idx < 8) { // a0-a7
|
||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_arg_idx);
|
||||
color_map[vreg] = preg;
|
||||
}
|
||||
int_arg_idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64SimpleRegAlloc::analyzeLiveness() {
|
||||
if (DEBUG) std::cerr << "\n--- Starting Liveness Analysis ---\n";
|
||||
|
||||
// === 阶段 1: 预计算每个基本块的 use 和 def 集合 ===
|
||||
std::map<const MachineBasicBlock*, LiveSet> block_uses;
|
||||
std::map<const MachineBasicBlock*, LiveSet> block_defs;
|
||||
for (const auto& mbb_ptr : MFunc->getBlocks()) {
|
||||
const MachineBasicBlock* mbb = mbb_ptr.get();
|
||||
LiveSet uses, defs;
|
||||
for (const auto& instr_ptr : mbb->getInstructions()) {
|
||||
LiveSet instr_use, instr_def;
|
||||
getInstrUseDef_Liveness(instr_ptr.get(), instr_use, instr_def);
|
||||
// use[B] = use[B] U (instr_use - def[B])
|
||||
for (unsigned u : instr_use) {
|
||||
if (defs.find(u) == defs.end()) {
|
||||
uses.insert(u);
|
||||
}
|
||||
}
|
||||
// def[B] = def[B] U instr_def
|
||||
defs.insert(instr_def.begin(), instr_def.end());
|
||||
}
|
||||
block_uses[mbb] = uses;
|
||||
block_defs[mbb] = defs;
|
||||
}
|
||||
|
||||
// === 阶段 2: 在“块”粒度上进行迭代数据流分析,直到收敛 ===
|
||||
std::map<const MachineBasicBlock*, LiveSet> block_live_in;
|
||||
std::map<const MachineBasicBlock*, LiveSet> block_live_out;
|
||||
bool changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
// 逆序遍历基本块,加速收敛
|
||||
for (auto it = MFunc->getBlocks().rbegin(); it != MFunc->getBlocks().rend(); ++it) {
|
||||
const auto& mbb_ptr = *it;
|
||||
const MachineBasicBlock* mbb = mbb_ptr.get();
|
||||
|
||||
// 2.1 计算 live_out[B] = U_{S in succ(B)} live_in[S]
|
||||
LiveSet new_live_out;
|
||||
for (auto succ : mbb->successors) {
|
||||
new_live_out.insert(block_live_in[succ].begin(), block_live_in[succ].end());
|
||||
}
|
||||
|
||||
// 2.2 计算 live_in[B] = use[B] U (live_out[B] - def[B])
|
||||
LiveSet live_out_minus_def = new_live_out;
|
||||
for (unsigned d : block_defs.at(mbb)) {
|
||||
live_out_minus_def.erase(d);
|
||||
}
|
||||
LiveSet new_live_in = block_uses.at(mbb);
|
||||
new_live_in.insert(live_out_minus_def.begin(), live_out_minus_def.end());
|
||||
|
||||
// 2.3 检查是否达到不动点
|
||||
if (block_live_out[mbb] != new_live_out || block_live_in[mbb] != new_live_in) {
|
||||
changed = true;
|
||||
block_live_out[mbb] = new_live_out;
|
||||
block_live_in[mbb] = new_live_in;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// === 阶段 3: 进行一次指令粒度的遍历,填充最终的 live_in_map 和 live_out_map ===
|
||||
for (const auto& mbb_ptr : MFunc->getBlocks()) {
|
||||
const MachineBasicBlock* mbb = mbb_ptr.get();
|
||||
LiveSet live_out = block_live_out.at(mbb);
|
||||
|
||||
for (auto instr_it = mbb->getInstructions().rbegin(); instr_it != mbb->getInstructions().rend(); ++instr_it) {
|
||||
const MachineInstr* instr = instr_it->get();
|
||||
live_out_map[instr] = live_out;
|
||||
|
||||
LiveSet use, def;
|
||||
getInstrUseDef_Liveness(instr, use, def);
|
||||
|
||||
LiveSet live_in = use;
|
||||
LiveSet diff = live_out;
|
||||
for (auto vreg : def) {
|
||||
diff.erase(vreg);
|
||||
}
|
||||
live_in.insert(diff.begin(), diff.end());
|
||||
live_in_map[instr] = live_in;
|
||||
|
||||
// 更新 live_out,为块内的上一条指令做准备
|
||||
live_out = live_in;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64SimpleRegAlloc::buildInterferenceGraph() {
|
||||
if (DEBUG) std::cerr << "\n--- Starting Interference Graph Construction ---\n";
|
||||
RISCv64AsmPrinter printer(MFunc);
|
||||
printer.setStream(std::cerr);
|
||||
|
||||
// 1. 收集所有图中需要出现的节点 (所有虚拟寄存器和物理寄存器)
|
||||
std::set<unsigned> all_nodes;
|
||||
for (const auto& mbb : MFunc->getBlocks()) {
|
||||
for(const auto& instr : mbb->getInstructions()) {
|
||||
LiveSet use, def;
|
||||
getInstrUseDef_Liveness(instr.get(), use, def);
|
||||
all_nodes.insert(use.begin(), use.end());
|
||||
all_nodes.insert(def.begin(), def.end());
|
||||
}
|
||||
}
|
||||
// 确保所有物理寄存器节点也存在
|
||||
for (const auto& pair : preg_to_vreg_id_map) {
|
||||
all_nodes.insert(pair.second);
|
||||
}
|
||||
|
||||
// 2. 初始化干扰图邻接表
|
||||
for (unsigned vreg : all_nodes) { interference_graph[vreg] = {}; }
|
||||
|
||||
// 3. 遍历指令,添加冲突边
|
||||
for (const auto& mbb : MFunc->getBlocks()) {
|
||||
if (DEEPDEBUG) std::cerr << "--- Building Graph for Basic Block: " << mbb->getName() << " ---\n";
|
||||
for (const auto& instr_ptr : mbb->getInstructions()) {
|
||||
const MachineInstr* instr = instr_ptr.get();
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << " Instr: ";
|
||||
printer.printInstruction(const_cast<MachineInstr*>(instr), true);
|
||||
}
|
||||
|
||||
LiveSet def, use;
|
||||
getInstrUseDef_Liveness(instr, def, use); // 注意Use/Def顺序
|
||||
const LiveSet& live_out = live_out_map.at(instr);
|
||||
|
||||
if (DEEPDEBUG) {
|
||||
printLiveSet(use, "Use ", std::cerr, printer);
|
||||
printLiveSet(def, "Def ", std::cerr, printer);
|
||||
printLiveSet(live_out, "Live_Out", std::cerr, printer);
|
||||
}
|
||||
|
||||
// 规则1: 指令的定义(def)与该指令之后的所有活跃变量(live_out)冲突
|
||||
for (unsigned d : def) {
|
||||
for (unsigned l : live_out) {
|
||||
if (d != l) {
|
||||
if (DEEPDEBUG && interference_graph.at(d).find(l) == interference_graph.at(d).end()) {
|
||||
std::cerr << " Edge (Def-LiveOut): " << regIdToString(d, printer) << " <-> " << regIdToString(l, printer) << "\n";
|
||||
}
|
||||
interference_graph[d].insert(l);
|
||||
interference_graph[l].insert(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 规则2: 对于非MV指令, def与use也冲突
|
||||
if (instr->getOpcode() != RVOpcodes::MV) {
|
||||
for (unsigned d : def) {
|
||||
for (unsigned u : use) {
|
||||
if (d != u) {
|
||||
if (DEEPDEBUG && interference_graph.at(d).find(u) == interference_graph.at(d).end()) {
|
||||
std::cerr << " Edge (Def-Use): " << regIdToString(d, printer) << " <-> " << regIdToString(u, printer) << "\n";
|
||||
}
|
||||
interference_graph[d].insert(u);
|
||||
interference_graph[u].insert(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 所有在某一点上同时活跃的寄存器(即live_out集合中的所有成员),
|
||||
// 它们之间必须两两互相干扰。
|
||||
std::vector<unsigned> live_out_vec(live_out.begin(), live_out.end());
|
||||
for (size_t i = 0; i < live_out_vec.size(); ++i) {
|
||||
for (size_t j = i + 1; j < live_out_vec.size(); ++j) {
|
||||
unsigned u = live_out_vec[i];
|
||||
unsigned v = live_out_vec[j];
|
||||
if (DEEPDEBUG && interference_graph[u].find(v) == interference_graph[u].end()) {
|
||||
std::cerr << " Edge (Live-Live): %vreg" << u << " <-> %vreg" << v << "\n";
|
||||
}
|
||||
interference_graph[u].insert(v);
|
||||
interference_graph[v].insert(u);
|
||||
}
|
||||
}
|
||||
|
||||
// 规则3: CALL指令会破坏所有调用者保存(caller-saved)寄存器
|
||||
if (instr->getOpcode() == RVOpcodes::CALL) {
|
||||
const auto& caller_saved_int = getCallerSavedIntRegs();
|
||||
const auto& caller_saved_fp = getCallerSavedFpRegs();
|
||||
|
||||
for (unsigned live_vreg : live_out) {
|
||||
auto [type, size] = getTypeAndSize(live_vreg);
|
||||
if (type == Type::kFloat) {
|
||||
for (PhysicalReg cs_reg : caller_saved_fp) {
|
||||
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg);
|
||||
if (live_vreg != cs_vreg_id) {
|
||||
interference_graph[live_vreg].insert(cs_vreg_id);
|
||||
interference_graph[cs_vreg_id].insert(live_vreg);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (PhysicalReg cs_reg : caller_saved_int) {
|
||||
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg);
|
||||
if (live_vreg != cs_vreg_id) {
|
||||
interference_graph[live_vreg].insert(cs_vreg_id);
|
||||
interference_graph[cs_vreg_id].insert(live_vreg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end if CALL
|
||||
if (DEEPDEBUG) std::cerr << " ----------------\n";
|
||||
} // end for instr
|
||||
} // end for mbb
|
||||
}
|
||||
|
||||
void RISCv64SimpleRegAlloc::colorGraph() {
|
||||
// 1. 收集所有需要着色的虚拟寄存器
|
||||
std::vector<unsigned> vregs_to_color;
|
||||
for (auto const& [vreg, neighbors] : interference_graph) {
|
||||
// 只为未预着色的、真正的虚拟寄存器进行着色
|
||||
if (color_map.find(vreg) == color_map.end() && vreg < static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID)) {
|
||||
vregs_to_color.push_back(vreg);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 按冲突度从高到低排序,进行贪心着色
|
||||
std::sort(vregs_to_color.begin(), vregs_to_color.end(), [&](unsigned a, unsigned b) {
|
||||
return interference_graph.at(a).size() > interference_graph.at(b).size();
|
||||
});
|
||||
|
||||
// 3. 遍历并着色
|
||||
for (unsigned vreg : vregs_to_color) {
|
||||
std::set<PhysicalReg> used_colors;
|
||||
// 收集所有邻居的颜色
|
||||
for (unsigned neighbor_id : interference_graph.at(vreg)) {
|
||||
// A. 邻居是已着色的vreg
|
||||
if (color_map.count(neighbor_id)) {
|
||||
used_colors.insert(color_map.at(neighbor_id));
|
||||
}
|
||||
// B. 邻居是物理寄存器本身
|
||||
else if (neighbor_id >= static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID)) {
|
||||
PhysicalReg neighbor_preg = static_cast<PhysicalReg>(neighbor_id - static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID));
|
||||
used_colors.insert(neighbor_preg);
|
||||
}
|
||||
}
|
||||
|
||||
// 根据vreg类型选择寄存器池
|
||||
auto [type, size] = getTypeAndSize(vreg);
|
||||
const auto& allocable_regs = (type == Type::kFloat) ? allocable_fp_regs : allocable_int_regs;
|
||||
|
||||
bool colored = false;
|
||||
for (PhysicalReg preg : allocable_regs) {
|
||||
if (used_colors.find(preg) == used_colors.end()) {
|
||||
color_map[vreg] = preg;
|
||||
colored = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!colored) {
|
||||
spilled_vregs.insert(vreg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64SimpleRegAlloc::rewriteFunction() {
|
||||
if (DEBUG) std::cerr << "\n--- Starting Function Rewrite (Spilling & Substitution) ---\n";
|
||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||
|
||||
// 步骤 1: 为所有溢出的vreg计算唯一的栈偏移量 (此部分逻辑正确,予以保留)
|
||||
int current_offset = frame_info.locals_end_offset;
|
||||
for (unsigned vreg : spilled_vregs) {
|
||||
if (frame_info.spill_offsets.count(vreg)) continue;
|
||||
auto [type, size] = getTypeAndSize(vreg);
|
||||
current_offset -= size;
|
||||
current_offset = current_offset & ~7;
|
||||
frame_info.spill_offsets[vreg] = current_offset;
|
||||
}
|
||||
frame_info.spill_size = -(current_offset - frame_info.locals_end_offset);
|
||||
|
||||
// 步骤 2: 遍历所有指令,对CALL指令做简化处理
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
|
||||
if (instr_ptr->getOpcode() != RVOpcodes::CALL) {
|
||||
std::vector<PhysicalReg> int_spill_pool = {PhysicalReg::T2, PhysicalReg::T3, PhysicalReg::T4, /*PhysicalReg::T5,*/ PhysicalReg::T6};
|
||||
std::vector<PhysicalReg> fp_spill_pool = {PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3};
|
||||
std::map<unsigned, PhysicalReg> vreg_to_preg_map_for_this_instr;
|
||||
LiveSet use, def;
|
||||
getInstrUseDef(instr_ptr.get(), use, def);
|
||||
LiveSet all_vregs_in_instr = use;
|
||||
all_vregs_in_instr.insert(def.begin(), def.end());
|
||||
for(unsigned vreg : all_vregs_in_instr) {
|
||||
if (spilled_vregs.count(vreg)) {
|
||||
auto [type, size] = getTypeAndSize(vreg);
|
||||
if (type == Type::kFloat) {
|
||||
assert(!fp_spill_pool.empty() && "FP spill pool exhausted for generic instruction!");
|
||||
vreg_to_preg_map_for_this_instr[vreg] = fp_spill_pool.front();
|
||||
fp_spill_pool.erase(fp_spill_pool.begin());
|
||||
} else {
|
||||
assert(!int_spill_pool.empty() && "Int spill pool exhausted for generic instruction!");
|
||||
vreg_to_preg_map_for_this_instr[vreg] = int_spill_pool.front();
|
||||
int_spill_pool.erase(int_spill_pool.begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
for (unsigned vreg : use) {
|
||||
if (spilled_vregs.count(vreg)) {
|
||||
PhysicalReg target_preg = vreg_to_preg_map_for_this_instr.at(vreg);
|
||||
auto [type, size] = getTypeAndSize(vreg);
|
||||
RVOpcodes load_op = (type == Type::kFloat) ? RVOpcodes::FLW : ((type == Type::kPointer) ? RVOpcodes::LD : RVOpcodes::LW);
|
||||
auto load = std::make_unique<MachineInstr>(load_op);
|
||||
load->addOperand(std::make_unique<RegOperand>(target_preg));
|
||||
load->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(vreg))
|
||||
));
|
||||
new_instructions.push_back(std::move(load));
|
||||
}
|
||||
}
|
||||
auto new_instr = std::make_unique<MachineInstr>(instr_ptr->getOpcode());
|
||||
for (const auto& op : instr_ptr->getOperands()) {
|
||||
const RegOperand* reg_op = nullptr;
|
||||
if (op->getKind() == MachineOperand::KIND_REG) reg_op = static_cast<const RegOperand*>(op.get());
|
||||
else if (op->getKind() == MachineOperand::KIND_MEM) reg_op = static_cast<const MemOperand*>(op.get())->getBase();
|
||||
if (reg_op) {
|
||||
PhysicalReg final_preg;
|
||||
if (reg_op->isVirtual()) {
|
||||
unsigned vreg = reg_op->getVRegNum();
|
||||
if (spilled_vregs.count(vreg)) {
|
||||
final_preg = vreg_to_preg_map_for_this_instr.at(vreg);
|
||||
} else {
|
||||
assert(color_map.count(vreg));
|
||||
final_preg = color_map.at(vreg);
|
||||
}
|
||||
} else {
|
||||
final_preg = reg_op->getPReg();
|
||||
}
|
||||
auto new_reg_op = std::make_unique<RegOperand>(final_preg);
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
new_instr->addOperand(std::move(new_reg_op));
|
||||
} else {
|
||||
auto mem_op = static_cast<const MemOperand*>(op.get());
|
||||
new_instr->addOperand(std::make_unique<MemOperand>(std::move(new_reg_op), std::make_unique<ImmOperand>(*mem_op->getOffset())));
|
||||
}
|
||||
} else {
|
||||
if(op->getKind() == MachineOperand::KIND_IMM) new_instr->addOperand(std::make_unique<ImmOperand>(*static_cast<const ImmOperand*>(op.get())));
|
||||
else if (op->getKind() == MachineOperand::KIND_LABEL) new_instr->addOperand(std::make_unique<LabelOperand>(*static_cast<const LabelOperand*>(op.get())));
|
||||
}
|
||||
}
|
||||
new_instructions.push_back(std::move(new_instr));
|
||||
for (unsigned vreg : def) {
|
||||
if (spilled_vregs.count(vreg)) {
|
||||
PhysicalReg src_preg = vreg_to_preg_map_for_this_instr.at(vreg);
|
||||
auto [type, size] = getTypeAndSize(vreg);
|
||||
RVOpcodes store_op = (type == Type::kFloat) ? RVOpcodes::FSW : ((type == Type::kPointer) ? RVOpcodes::SD : RVOpcodes::SW);
|
||||
auto store = std::make_unique<MachineInstr>(store_op);
|
||||
store->addOperand(std::make_unique<RegOperand>(src_preg));
|
||||
store->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(vreg))
|
||||
));
|
||||
new_instructions.push_back(std::move(store));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// --- 对于CALL指令,只处理其自身和返回值,不再处理参数 ---
|
||||
const PhysicalReg INT_TEMP_REG = PhysicalReg::T6;
|
||||
const PhysicalReg FP_TEMP_REG = PhysicalReg::F7;
|
||||
|
||||
// 1. 克隆CALL指令本身,只保留标签操作数
|
||||
auto new_call = std::make_unique<MachineInstr>(RVOpcodes::CALL);
|
||||
for (const auto& op : instr_ptr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_LABEL) {
|
||||
new_call->addOperand(std::make_unique<LabelOperand>(*static_cast<const LabelOperand*>(op.get())));
|
||||
// 注意:只添加第一个标签,防止ISel的错误导致多个标签
|
||||
break;
|
||||
}
|
||||
}
|
||||
new_instructions.push_back(std::move(new_call));
|
||||
|
||||
// 2. 只处理返回值(def)的溢出和移动
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
if (!operands.empty() && operands.front()->getKind() == MachineOperand::KIND_REG) {
|
||||
unsigned def_vreg = static_cast<RegOperand*>(operands.front().get())->getVRegNum();
|
||||
auto [type, size] = getTypeAndSize(def_vreg);
|
||||
PhysicalReg result_reg_abi = type == Type::kFloat ? PhysicalReg::F10 : PhysicalReg::A0;
|
||||
|
||||
if (spilled_vregs.count(def_vreg)) {
|
||||
// 返回值被溢出:a0/fa0 -> temp -> 溢出槽
|
||||
PhysicalReg temp_reg = type == Type::kFloat ? FP_TEMP_REG : INT_TEMP_REG;
|
||||
RVOpcodes store_op = (type == Type::kFloat) ? RVOpcodes::FSW : ((type == Type::kPointer) ? RVOpcodes::SD : RVOpcodes::SW);
|
||||
|
||||
auto mv_from_abi = std::make_unique<MachineInstr>(type == Type::kFloat ? RVOpcodes::FMV_S : RVOpcodes::MV);
|
||||
mv_from_abi->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
mv_from_abi->addOperand(std::make_unique<RegOperand>(result_reg_abi));
|
||||
new_instructions.push_back(std::move(mv_from_abi));
|
||||
|
||||
auto store = std::make_unique<MachineInstr>(store_op);
|
||||
store->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
store->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(def_vreg))
|
||||
));
|
||||
new_instructions.push_back(std::move(store));
|
||||
} else {
|
||||
// 返回值未溢出:a0/fa0 -> 已着色的物理寄存器
|
||||
auto mv_to_dest = std::make_unique<MachineInstr>(type == Type::kFloat ? RVOpcodes::FMV_S : RVOpcodes::MV);
|
||||
mv_to_dest->addOperand(std::make_unique<RegOperand>(color_map.at(def_vreg)));
|
||||
mv_to_dest->addOperand(std::make_unique<RegOperand>(result_reg_abi));
|
||||
new_instructions.push_back(std::move(mv_to_dest));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mbb->getInstructions() = std::move(new_instructions);
|
||||
}
|
||||
}
|
||||
|
||||
// --- 辅助函数实现 ---
|
||||
|
||||
void RISCv64SimpleRegAlloc::getInstrUseDef_Liveness(const MachineInstr* instr, LiveSet& use, LiveSet& def) {
|
||||
auto opcode = instr->getOpcode();
|
||||
const auto& operands = instr->getOperands();
|
||||
const unsigned offset = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID);
|
||||
|
||||
auto get_any_reg_id = [&](const MachineOperand* op) -> unsigned {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<const RegOperand*>(op);
|
||||
return reg_op->isVirtual() ? reg_op->getVRegNum() : (offset + static_cast<unsigned>(reg_op->getPReg()));
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto reg_op = static_cast<const MemOperand*>(op)->getBase();
|
||||
return reg_op->isVirtual() ? reg_op->getVRegNum() : (offset + static_cast<unsigned>(reg_op->getPReg()));
|
||||
}
|
||||
return (unsigned)-1;
|
||||
};
|
||||
|
||||
if (op_info.count(opcode)) {
|
||||
const auto& info = op_info.at(opcode);
|
||||
for (int idx : info.first) if (idx < operands.size()) {
|
||||
unsigned reg_id = get_any_reg_id(operands[idx].get());
|
||||
if (reg_id != (unsigned)-1) def.insert(reg_id);
|
||||
}
|
||||
for (int idx : info.second) if (idx < operands.size()) {
|
||||
unsigned reg_id = get_any_reg_id(operands[idx].get());
|
||||
if (reg_id != (unsigned)-1) use.insert(reg_id);
|
||||
}
|
||||
for (const auto& op : operands) {
|
||||
if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
unsigned reg_id = get_any_reg_id(op.get());
|
||||
if (reg_id != (unsigned)-1) use.insert(reg_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (opcode == RVOpcodes::CALL) {
|
||||
if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) {
|
||||
def.insert(get_any_reg_id(operands[0].get()));
|
||||
}
|
||||
for (size_t i = 1; i < operands.size(); ++i) {
|
||||
if (operands[i]->getKind() == MachineOperand::KIND_REG) {
|
||||
use.insert(get_any_reg_id(operands[i].get()));
|
||||
}
|
||||
}
|
||||
for (auto preg : getCallerSavedIntRegs()) def.insert(offset + static_cast<unsigned>(preg));
|
||||
for (auto preg : getCallerSavedFpRegs()) def.insert(offset + static_cast<unsigned>(preg));
|
||||
def.insert(offset + static_cast<unsigned>(PhysicalReg::RA));
|
||||
}
|
||||
else if (opcode == RVOpcodes::RET) {
|
||||
use.insert(offset + static_cast<unsigned>(PhysicalReg::A0));
|
||||
use.insert(offset + static_cast<unsigned>(PhysicalReg::F10)); // fa0
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<Type::Kind, unsigned> RISCv64SimpleRegAlloc::getTypeAndSize(unsigned vreg) {
|
||||
const auto& vreg_type_map = ISel->getVRegTypeMap();
|
||||
if (vreg_type_map.count(vreg)) {
|
||||
Type* type = vreg_type_map.at(vreg);
|
||||
if (type->isFloat()) return {Type::kFloat, 4};
|
||||
if (type->isPointer()) return {Type::kPointer, 8};
|
||||
}
|
||||
// 默认或未知类型按32位整数处理
|
||||
return {Type::kInt, 4};
|
||||
}
|
||||
|
||||
std::string RISCv64SimpleRegAlloc::regIdToString(unsigned id, const RISCv64AsmPrinter& printer) const {
|
||||
const unsigned offset = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID);
|
||||
if (id >= offset) {
|
||||
PhysicalReg reg = static_cast<PhysicalReg>(id - offset);
|
||||
return printer.regToString(reg);
|
||||
} else {
|
||||
return "%vreg" + std::to_string(id);
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64SimpleRegAlloc::printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os, const RISCv64AsmPrinter& printer) {
|
||||
os << " " << name << " (" << s.size() << "): { ";
|
||||
for (unsigned vreg : s) {
|
||||
os << regIdToString(vreg, printer) << " ";
|
||||
}
|
||||
os << "}\n";
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@@ -23,6 +23,21 @@ public:
|
||||
bool runOnFunction(Function *F, AnalysisManager& AM) override;
|
||||
|
||||
void runOnMachineFunction(MachineFunction* mfunc);
|
||||
|
||||
/**
|
||||
* @brief 设置是否启用浮点乘加融合优化
|
||||
* @param enabled 是否启用
|
||||
*/
|
||||
static void setFusedMulAddEnabled(bool enabled) { fusedMulAddEnabled = enabled; }
|
||||
|
||||
/**
|
||||
* @brief 检查是否启用了浮点乘加融合优化
|
||||
* @return 是否启用
|
||||
*/
|
||||
static bool isFusedMulAddEnabled() { return fusedMulAddEnabled; }
|
||||
|
||||
private:
|
||||
static bool fusedMulAddEnabled; // 浮点乘加融合优化开关
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
@@ -19,7 +19,7 @@ public:
|
||||
// 辅助函数
|
||||
void setStream(std::ostream& os) { OS = &os; }
|
||||
// 辅助函数
|
||||
std::string regToString(PhysicalReg reg);
|
||||
std::string regToString(PhysicalReg reg) const;
|
||||
std::string formatInstr(const MachineInstr *instr);
|
||||
|
||||
private:
|
||||
|
||||
@@ -26,6 +26,7 @@ private:
|
||||
unsigned getTypeSizeInBytes(Type* type);
|
||||
|
||||
Module* module;
|
||||
bool irc_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
|
||||
@@ -11,6 +11,7 @@ namespace sysy {
|
||||
|
||||
extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
extern int optLevel;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
@@ -22,14 +23,12 @@ 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; }
|
||||
|
||||
private:
|
||||
// DAG节点定义,作为ISel的内部实现细节
|
||||
struct DAGNode;
|
||||
|
||||
98
src/include/backend/RISCv64/RISCv64Info.h
Normal file
98
src/include/backend/RISCv64/RISCv64Info.h
Normal file
@@ -0,0 +1,98 @@
|
||||
#ifndef RISCV64_INFO_H
|
||||
#define RISCV64_INFO_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 定义一个全局的、权威的指令信息表
|
||||
// 它包含了指令的定义(def)和使用(use)操作数索引
|
||||
// defs: {0} -> 第一个操作数是定义
|
||||
// uses: {1, 2} -> 第二、三个操作数是使用
|
||||
static const std::map<RVOpcodes, std::pair<std::vector<int>, std::vector<int>>> op_info = {
|
||||
// --- 整数计算 (R-Type) ---
|
||||
{RVOpcodes::ADD, {{0}, {1, 2}}},
|
||||
{RVOpcodes::SUB, {{0}, {1, 2}}},
|
||||
{RVOpcodes::MUL, {{0}, {1, 2}}},
|
||||
{RVOpcodes::MULH, {{0}, {1, 2}}},
|
||||
{RVOpcodes::DIV, {{0}, {1, 2}}},
|
||||
{RVOpcodes::DIVW, {{0}, {1, 2}}},
|
||||
{RVOpcodes::REM, {{0}, {1, 2}}},
|
||||
{RVOpcodes::REMW, {{0}, {1, 2}}},
|
||||
{RVOpcodes::ADDW, {{0}, {1, 2}}},
|
||||
{RVOpcodes::SUBW, {{0}, {1, 2}}},
|
||||
{RVOpcodes::MULW, {{0}, {1, 2}}},
|
||||
{RVOpcodes::SLT, {{0}, {1, 2}}},
|
||||
{RVOpcodes::SLTU, {{0}, {1, 2}}},
|
||||
{RVOpcodes::XOR, {{0}, {1, 2}}},
|
||||
{RVOpcodes::OR, {{0}, {1, 2}}},
|
||||
{RVOpcodes::AND, {{0}, {1, 2}}},
|
||||
{RVOpcodes::SLL, {{0}, {1, 2}}},
|
||||
{RVOpcodes::SRL, {{0}, {1, 2}}},
|
||||
{RVOpcodes::SRA, {{0}, {1, 2}}},
|
||||
{RVOpcodes::SLLW, {{0}, {1, 2}}},
|
||||
{RVOpcodes::SRLW, {{0}, {1, 2}}},
|
||||
{RVOpcodes::SRAW, {{0}, {1, 2}}},
|
||||
|
||||
// --- 整数计算 (I-Type) ---
|
||||
{RVOpcodes::ADDI, {{0}, {1}}},
|
||||
{RVOpcodes::ADDIW, {{0}, {1}}},
|
||||
{RVOpcodes::XORI, {{0}, {1}}},
|
||||
{RVOpcodes::ORI, {{0}, {1}}},
|
||||
{RVOpcodes::ANDI, {{0}, {1}}},
|
||||
{RVOpcodes::SLTI, {{0}, {1}}},
|
||||
{RVOpcodes::SLTIU, {{0}, {1}}},
|
||||
{RVOpcodes::SLLI, {{0}, {1}}},
|
||||
{RVOpcodes::SLLIW, {{0}, {1}}},
|
||||
{RVOpcodes::SRLI, {{0}, {1}}},
|
||||
{RVOpcodes::SRLIW, {{0}, {1}}},
|
||||
{RVOpcodes::SRAI, {{0}, {1}}},
|
||||
{RVOpcodes::SRAIW, {{0}, {1}}},
|
||||
|
||||
// --- 内存加载 ---
|
||||
{RVOpcodes::LW, {{0}, {}}}, {RVOpcodes::LH, {{0}, {}}}, {RVOpcodes::LB, {{0}, {}}},
|
||||
{RVOpcodes::LWU, {{0}, {}}}, {RVOpcodes::LHU, {{0}, {}}}, {RVOpcodes::LBU, {{0}, {}}},
|
||||
{RVOpcodes::LD, {{0}, {}}},
|
||||
{RVOpcodes::FLW, {{0}, {}}}, {RVOpcodes::FLD, {{0}, {}}},
|
||||
|
||||
// --- 内存存储 ---
|
||||
{RVOpcodes::SW, {{}, {0, 1}}}, {RVOpcodes::SH, {{}, {0, 1}}}, {RVOpcodes::SB, {{}, {0, 1}}},
|
||||
{RVOpcodes::SD, {{}, {0, 1}}},
|
||||
{RVOpcodes::FSW, {{}, {0, 1}}}, {RVOpcodes::FSD, {{}, {0, 1}}},
|
||||
|
||||
// --- 分支指令 ---
|
||||
{RVOpcodes::BEQ, {{}, {0, 1}}}, {RVOpcodes::BNE, {{}, {0, 1}}}, {RVOpcodes::BLT, {{}, {0, 1}}},
|
||||
{RVOpcodes::BGE, {{}, {0, 1}}}, {RVOpcodes::BLTU, {{}, {0, 1}}}, {RVOpcodes::BGEU, {{}, {0, 1}}},
|
||||
|
||||
// --- 跳转 ---
|
||||
{RVOpcodes::JAL, {{0}, {}}}, // JAL的rd是def,但通常用x0表示不关心返回值,这里简化
|
||||
{RVOpcodes::JALR, {{0}, {1}}},
|
||||
{RVOpcodes::RET, {{}, {}}}, // RET是伪指令,通常展开为JALR
|
||||
|
||||
// --- 伪指令 & 其他 ---
|
||||
{RVOpcodes::LI, {{0}, {}}}, {RVOpcodes::LA, {{0}, {}}},
|
||||
{RVOpcodes::MV, {{0}, {1}}},
|
||||
{RVOpcodes::NEG, {{0}, {1}}}, // sub rd, zero, rs1
|
||||
{RVOpcodes::NEGW, {{0}, {1}}}, // subw rd, zero, rs1
|
||||
{RVOpcodes::SEQZ, {{0}, {1}}},
|
||||
{RVOpcodes::SNEZ, {{0}, {1}}},
|
||||
|
||||
// --- 函数调用 ---
|
||||
// CALL的use/def在getInstrUseDef中有特殊处理逻辑,这里可以不列出
|
||||
|
||||
// --- 浮点指令 ---
|
||||
{RVOpcodes::FADD_S, {{0}, {1, 2}}}, {RVOpcodes::FSUB_S, {{0}, {1, 2}}},
|
||||
{RVOpcodes::FMUL_S, {{0}, {1, 2}}}, {RVOpcodes::FDIV_S, {{0}, {1, 2}}},
|
||||
{RVOpcodes::FMADD_S, {{0}, {1, 2, 3}}},
|
||||
{RVOpcodes::FEQ_S, {{0}, {1, 2}}}, {RVOpcodes::FLT_S, {{0}, {1, 2}}}, {RVOpcodes::FLE_S, {{0}, {1, 2}}},
|
||||
{RVOpcodes::FCVT_S_W, {{0}, {1}}}, {RVOpcodes::FCVT_W_S, {{0}, {1}}},
|
||||
{RVOpcodes::FCVT_W_S_RTZ, {{0}, {1}}},
|
||||
{RVOpcodes::FMV_S, {{0}, {1}}}, {RVOpcodes::FMV_W_X, {{0}, {1}}}, {RVOpcodes::FMV_X_W, {{0}, {1}}},
|
||||
{RVOpcodes::FNEG_S, {{0}, {1}}}
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // RISCV64_INFO_H
|
||||
@@ -41,6 +41,8 @@ enum class PhysicalReg {
|
||||
// 假设 vreg_counter 不会达到这么大的值
|
||||
PHYS_REG_START_ID = 1000000,
|
||||
PHYS_REG_END_ID = PHYS_REG_START_ID + 320, // 预留足够的空间
|
||||
|
||||
INVALID, ///< 无效寄存器标记
|
||||
};
|
||||
|
||||
// RISC-V 指令操作码枚举
|
||||
@@ -77,6 +79,7 @@ enum class RVOpcodes {
|
||||
FSUB_S, // fsub.s rd, rs1, rs2
|
||||
FMUL_S, // fmul.s rd, rs1, rs2
|
||||
FDIV_S, // fdiv.s rd, rs1, rs2
|
||||
FMADD_S, // fmadd.s rd, rs1, rs2, rs3
|
||||
|
||||
// 浮点比较 (单精度)
|
||||
FEQ_S, // feq.s rd, rs1, rs2 (结果写入整数寄存器rd)
|
||||
@@ -86,6 +89,7 @@ enum class RVOpcodes {
|
||||
// 浮点转换
|
||||
FCVT_S_W, // fcvt.s.w rd, rs1 (有符号整数 -> 单精度浮点)
|
||||
FCVT_W_S, // fcvt.w.s rd, rs1 (单精度浮点 -> 有符号整数)
|
||||
FCVT_W_S_RTZ, // fcvt.w.s rd, rs1, rtz (使用向零截断模式)
|
||||
|
||||
// 浮点传送/移动
|
||||
FMV_S, // fmv.s rd, rs1 (浮点寄存器之间)
|
||||
@@ -93,6 +97,9 @@ enum class RVOpcodes {
|
||||
FMV_X_W, // fmv.x.w rd, rs1 (浮点寄存器位模式 -> 整数寄存器)
|
||||
FNEG_S, // fneg.s rd, rs (浮点取负)
|
||||
|
||||
// 浮点控制状态寄存器 (CSR)
|
||||
FSRMI, // fsrmi rd, imm (设置舍入模式立即数)
|
||||
|
||||
// 伪指令
|
||||
FRAME_LOAD_W, // 从栈帧加载 32位 Word (对应 lw)
|
||||
FRAME_LOAD_D, // 从栈帧加载 64位 Doubleword (对应 ld)
|
||||
@@ -249,6 +256,19 @@ public:
|
||||
void addOperand(std::unique_ptr<MachineOperand> operand) {
|
||||
operands.push_back(std::move(operand));
|
||||
}
|
||||
/**
|
||||
* @brief (为紧急溢出模式添加)将指令中所有对特定虚拟寄存器的引用替换为指定的物理寄存器。
|
||||
* * @param old_vreg 需要被替换的虚拟寄存器号。
|
||||
* @param preg 用于替换的物理寄存器。
|
||||
*/
|
||||
void replaceVRegWithPReg(unsigned old_vreg, PhysicalReg preg);
|
||||
|
||||
/**
|
||||
* @brief (为常规溢出模式添加)根据提供的映射表,重映射指令中的虚拟寄存器。
|
||||
* * @param use_remap 一个从旧vreg到新vreg的映射,用于指令的use操作数。
|
||||
* @param def_remap 一个从旧vreg到新vreg的映射,用于指令的def操作数。
|
||||
*/
|
||||
void remapVRegs(const std::map<unsigned, unsigned>& use_remap, const std::map<unsigned, unsigned>& def_remap);
|
||||
private:
|
||||
RVOpcodes opcode;
|
||||
std::vector<std::unique_ptr<MachineOperand>> operands;
|
||||
@@ -313,6 +333,22 @@ private:
|
||||
std::vector<std::unique_ptr<MachineBasicBlock>> blocks;
|
||||
StackFrameInfo frame_info;
|
||||
};
|
||||
inline bool isMemoryOp(RVOpcodes opcode) {
|
||||
switch (opcode) {
|
||||
case RVOpcodes::LB: case RVOpcodes::LH: case RVOpcodes::LW: case RVOpcodes::LD:
|
||||
case RVOpcodes::LBU: case RVOpcodes::LHU: case RVOpcodes::LWU:
|
||||
case RVOpcodes::SB: case RVOpcodes::SH: case RVOpcodes::SW: case RVOpcodes::SD:
|
||||
case RVOpcodes::FLW:
|
||||
case RVOpcodes::FSW:
|
||||
case RVOpcodes::FLD:
|
||||
case RVOpcodes::FSD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void getInstrUseDef(const MachineInstr* instr, std::set<unsigned>& use, std::set<unsigned>& def);
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
|
||||
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"
|
||||
@@ -9,10 +10,8 @@
|
||||
#include "LegalizeImmediates.h"
|
||||
#include "PrologueEpilogueInsertion.h"
|
||||
#include "EliminateFrameIndices.h"
|
||||
#include "Pass.h"
|
||||
#include "DivStrengthReduction.h"
|
||||
|
||||
|
||||
namespace sysy {
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
@@ -12,6 +12,7 @@ extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
extern int DEBUGLENGTH; // 用于限制调试输出的长度
|
||||
extern int DEEPERDEBUG; // 用于更深层次的调试输出
|
||||
extern int optLevel;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
@@ -20,7 +21,7 @@ public:
|
||||
RISCv64RegAlloc(MachineFunction* mfunc);
|
||||
|
||||
// 模块主入口
|
||||
void run();
|
||||
bool run(std::shared_ptr<std::atomic<bool>> stop_flag);
|
||||
|
||||
private:
|
||||
// 类型定义,与Python版本对应
|
||||
|
||||
107
src/include/backend/RISCv64/RISCv64SimpleRegAlloc.h
Normal file
107
src/include/backend/RISCv64/RISCv64SimpleRegAlloc.h
Normal file
@@ -0,0 +1,107 @@
|
||||
#ifndef RISCV64_SIMPLE_REGALLOC_H
|
||||
#define RISCV64_SIMPLE_REGALLOC_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
// 外部调试级别控制变量的声明
|
||||
extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class RISCv64AsmPrinter; // 前向声明
|
||||
|
||||
/**
|
||||
* @class RISCv64SimpleRegAlloc
|
||||
* @brief 一个简单的一次性图着色寄存器分配器。
|
||||
* * 该分配器遵循一个线性的、非迭代的流程:
|
||||
* 1. 活跃性分析
|
||||
* 2. 构建冲突图
|
||||
* 3. 贪心图着色
|
||||
* 4. 重写函数代码,插入溢出指令
|
||||
* * 它与新版后端流水线兼容,但保留了旧版分配器的核心逻辑。
|
||||
* 溢出处理使用硬编码的物理寄存器。
|
||||
*/
|
||||
class RISCv64SimpleRegAlloc {
|
||||
public:
|
||||
RISCv64SimpleRegAlloc(MachineFunction* mfunc);
|
||||
|
||||
/**
|
||||
* @brief 运行寄存器分配的主函数。
|
||||
*/
|
||||
void run();
|
||||
|
||||
private:
|
||||
using LiveSet = std::set<unsigned>;
|
||||
using InterferenceGraph = std::map<unsigned, LiveSet>;
|
||||
|
||||
// --- 分配流程的各个阶段 ---
|
||||
void unifyArgumentVRegs();
|
||||
void handleCallingConvention();
|
||||
void analyzeLiveness();
|
||||
void buildInterferenceGraph();
|
||||
void colorGraph();
|
||||
void rewriteFunction();
|
||||
|
||||
// --- 辅助函数 ---
|
||||
|
||||
/**
|
||||
* @brief 获取指令的Use/Def集合,包含物理寄存器,用于活跃性分析。
|
||||
* @param instr 机器指令。
|
||||
* @param use 输出参数,存储使用的寄存器ID。
|
||||
* @param def 输出参数,存储定义的寄存器ID。
|
||||
*/
|
||||
void getInstrUseDef_Liveness(const MachineInstr* instr, LiveSet& use, LiveSet& def);
|
||||
|
||||
/**
|
||||
* @brief 根据vreg的类型信息返回其大小和类型种类。
|
||||
* @param vreg 虚拟寄存器号。
|
||||
* @return 一个包含类型信息和大小(字节)的pair。
|
||||
*/
|
||||
std::pair<Type::Kind, unsigned> getTypeAndSize(unsigned vreg);
|
||||
|
||||
/**
|
||||
* @brief 打印调试用的活跃集信息。
|
||||
*/
|
||||
void printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os, const RISCv64AsmPrinter& printer);
|
||||
|
||||
/**
|
||||
* @brief 将寄存器ID(虚拟或物理)转换为可读字符串。
|
||||
*/
|
||||
std::string regIdToString(unsigned id, const RISCv64AsmPrinter& printer) const;
|
||||
|
||||
// --- 成员变量 ---
|
||||
MachineFunction* MFunc;
|
||||
RISCv64ISel* ISel;
|
||||
|
||||
// 可分配的寄存器池
|
||||
std::vector<PhysicalReg> allocable_int_regs;
|
||||
std::vector<PhysicalReg> allocable_fp_regs;
|
||||
|
||||
// 硬编码的溢出专用物理寄存器
|
||||
const PhysicalReg INT_SPILL_REG = PhysicalReg::T2; // 用于 32-bit int
|
||||
const PhysicalReg PTR_SPILL_REG = PhysicalReg::T3; // 用于 64-bit pointer
|
||||
const PhysicalReg FP_SPILL_REG = PhysicalReg::F4; // 用于 32-bit float (ft4)
|
||||
|
||||
// 活跃性分析结果
|
||||
std::map<const MachineInstr*, LiveSet> live_in_map;
|
||||
std::map<const MachineInstr*, LiveSet> live_out_map;
|
||||
|
||||
// 冲突图
|
||||
InterferenceGraph interference_graph;
|
||||
|
||||
// 着色结果和溢出列表
|
||||
std::map<unsigned, PhysicalReg> color_map;
|
||||
std::set<unsigned> spilled_vregs;
|
||||
|
||||
// 映射:将物理寄存器ID映射到它们在冲突图中的特殊虚拟ID
|
||||
std::map<PhysicalReg, unsigned> preg_to_vreg_id_map;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // RISCV64_SIMPLE_REGALLOC_H
|
||||
@@ -727,6 +727,7 @@ class Instruction : public User {
|
||||
kFCmpGE = 0x1UL << 20,
|
||||
kAnd = 0x1UL << 21,
|
||||
kOr = 0x1UL << 22,
|
||||
// kXor = 0x1UL << 46,
|
||||
// Unary
|
||||
kNeg = 0x1UL << 23,
|
||||
kNot = 0x1UL << 24,
|
||||
@@ -751,8 +752,10 @@ class Instruction : public User {
|
||||
kPhi = 0x1UL << 39,
|
||||
kBitItoF = 0x1UL << 40,
|
||||
kBitFtoI = 0x1UL << 41,
|
||||
kSRA = 0x1UL << 42,
|
||||
kMulh = 0x1UL << 43
|
||||
kSrl = 0x1UL << 42, // 逻辑右移
|
||||
kSll = 0x1UL << 43, // 逻辑左移
|
||||
kSra = 0x1UL << 44, // 算术右移
|
||||
kMulh = 0x1UL << 45
|
||||
};
|
||||
|
||||
protected:
|
||||
@@ -855,8 +858,14 @@ public:
|
||||
return "BitItoF";
|
||||
case kBitFtoI:
|
||||
return "BitFtoI";
|
||||
case kSRA:
|
||||
case kSrl:
|
||||
return "lshr";
|
||||
case kSll:
|
||||
return "shl";
|
||||
case kSra:
|
||||
return "ashr";
|
||||
case kMulh:
|
||||
return "mulh";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
@@ -868,7 +877,7 @@ public:
|
||||
|
||||
bool isBinary() const {
|
||||
static constexpr uint64_t BinaryOpMask =
|
||||
(kAdd | kSub | kMul | kDiv | kRem | kAnd | kOr | kSRA | kMulh) |
|
||||
(kAdd | kSub | kMul | kDiv | kRem | kAnd | kOr | kSra | kSrl | kSll | kMulh) |
|
||||
(kICmpEQ | kICmpNE | kICmpLT | kICmpGT | kICmpLE | kICmpGE);
|
||||
return kind & BinaryOpMask;
|
||||
}
|
||||
@@ -962,7 +971,13 @@ class PhiInst : public Instruction {
|
||||
|
||||
Value* getValfromBlk(BasicBlock* block);
|
||||
BasicBlock* getBlkfromVal(Value* value);
|
||||
|
||||
auto getIncomingValues() const {
|
||||
std::vector<std::pair<BasicBlock*, Value*>> result;
|
||||
for (const auto& [block, value] : blk2val) {
|
||||
result.emplace_back(block, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
void addIncoming(Value *value, BasicBlock *block) {
|
||||
assert(value && block && "PhiInst: value and block cannot be null");
|
||||
addOperand(value);
|
||||
@@ -1420,8 +1435,19 @@ protected:
|
||||
auto is_same_ptr = [blockToRemove](const std::unique_ptr<BasicBlock> &ptr) { return ptr.get() == blockToRemove; };
|
||||
blocks.remove_if(is_same_ptr);
|
||||
}
|
||||
BasicBlock* addBasicBlock(const std::string &name, BasicBlock *before) {
|
||||
// 在指定的基本块之前添加一个新的基本块
|
||||
auto it = std::find_if(blocks.begin(), blocks.end(),
|
||||
[before](const std::unique_ptr<BasicBlock> &ptr) { return ptr.get() == before; });
|
||||
if (it != blocks.end()) {
|
||||
auto newblk = blocks.emplace(it, std::make_unique<BasicBlock>(this, name));
|
||||
return newblk->get(); // 返回新添加的基本块指针
|
||||
}
|
||||
assert(false && "BasicBlock to insert before not found!");
|
||||
return nullptr; // 如果没有找到指定的基本块,则返回nullptr
|
||||
} ///< 添加一个新的基本块到某个基本块之前
|
||||
BasicBlock* addBasicBlock(const std::string &name = "") {
|
||||
blocks.emplace_back(new BasicBlock(this, name));
|
||||
blocks.emplace_back(std::make_unique<BasicBlock>(this, name));
|
||||
return blocks.back().get();
|
||||
}
|
||||
BasicBlock* addBasicBlock(BasicBlock *block) {
|
||||
|
||||
@@ -217,8 +217,14 @@ 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 * createSllInst(Value *lhs, Value *rhs, const std::string &name = "") {
|
||||
return createBinaryInst(Instruction::kSll, Type::getIntType(), lhs, rhs, name);
|
||||
} ///< 创建逻辑左移指令
|
||||
BinaryInst * createSrlInst(Value *lhs, Value *rhs, const std::string &name = "") {
|
||||
return createBinaryInst(Instruction::kSrl, 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);
|
||||
|
||||
246
src/include/midend/Pass/Analysis/AliasAnalysis.h
Normal file
246
src/include/midend/Pass/Analysis/AliasAnalysis.h
Normal file
@@ -0,0 +1,246 @@
|
||||
#pragma once
|
||||
|
||||
#include "IR.h"
|
||||
#include "Pass.h"
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 前向声明
|
||||
class MemoryLocation;
|
||||
class AliasAnalysisResult;
|
||||
|
||||
/**
|
||||
* @brief 别名关系类型
|
||||
* 按风险等级递增排序
|
||||
*/
|
||||
enum class AliasType {
|
||||
NO_ALIAS = 0, // 确定无别名 (不同的局部数组)
|
||||
SELF_ALIAS = 1, // 自别名 (同一数组的不同索引)
|
||||
POSSIBLE_ALIAS = 2, // 可能有别名 (函数参数数组)
|
||||
UNKNOWN_ALIAS = 3 // 未知 (保守估计)
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 内存位置信息
|
||||
* 描述一个内存访问的基础信息
|
||||
*/
|
||||
struct MemoryLocation {
|
||||
Value* basePointer; // 基指针 (剥离GEP后的真实基址)
|
||||
Value* accessPointer; // 访问指针 (包含索引信息)
|
||||
|
||||
// 分类信息
|
||||
bool isLocalArray; // 是否为局部数组
|
||||
bool isFunctionParameter; // 是否为函数参数
|
||||
bool isGlobalArray; // 是否为全局数组
|
||||
|
||||
// 索引信息
|
||||
std::vector<Value*> indices; // GEP索引列表
|
||||
bool hasConstantIndices; // 是否为常量索引
|
||||
bool hasLoopVariableIndex; // 是否包含循环变量
|
||||
int constantOffset; // 常量偏移量 (仅当全部为常量时有效)
|
||||
|
||||
// 访问模式
|
||||
bool hasReads; // 是否有读操作
|
||||
bool hasWrites; // 是否有写操作
|
||||
std::vector<Instruction*> accessInsts; // 所有访问指令
|
||||
|
||||
MemoryLocation(Value* base, Value* access)
|
||||
: basePointer(base), accessPointer(access),
|
||||
isLocalArray(false), isFunctionParameter(false), isGlobalArray(false),
|
||||
hasConstantIndices(false), hasLoopVariableIndex(false), constantOffset(0),
|
||||
hasReads(false), hasWrites(false) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 别名分析结果
|
||||
* 存储一个函数的完整别名分析信息
|
||||
*/
|
||||
class AliasAnalysisResult : public AnalysisResultBase {
|
||||
public:
|
||||
AliasAnalysisResult(Function *F) : AssociatedFunction(F) {}
|
||||
~AliasAnalysisResult() override = default;
|
||||
|
||||
// ========== 基础查询接口 ==========
|
||||
|
||||
/**
|
||||
* 查询两个指针之间的别名关系
|
||||
*/
|
||||
AliasType queryAlias(Value* ptr1, Value* ptr2) const;
|
||||
|
||||
/**
|
||||
* 查询指针的内存位置信息
|
||||
*/
|
||||
const MemoryLocation* getMemoryLocation(Value* ptr) const;
|
||||
|
||||
/**
|
||||
* 获取所有内存位置
|
||||
*/
|
||||
const std::map<Value*, std::unique_ptr<MemoryLocation>>& getAllMemoryLocations() const {
|
||||
return LocationMap;
|
||||
}
|
||||
|
||||
// ========== 高级查询接口 ==========
|
||||
|
||||
/**
|
||||
* 检查指针是否为局部数组
|
||||
*/
|
||||
bool isLocalArray(Value* ptr) const;
|
||||
|
||||
/**
|
||||
* 检查指针是否为函数参数数组
|
||||
*/
|
||||
bool isFunctionParameter(Value* ptr) const;
|
||||
|
||||
/**
|
||||
* 检查指针是否为全局数组
|
||||
*/
|
||||
bool isGlobalArray(Value* ptr) const;
|
||||
|
||||
/**
|
||||
* 检查指针是否使用常量索引
|
||||
*/
|
||||
bool hasConstantAccess(Value* ptr) const;
|
||||
|
||||
// ========== 统计接口 ==========
|
||||
|
||||
/**
|
||||
* 获取各类别名类型的统计信息
|
||||
*/
|
||||
struct Statistics {
|
||||
int totalQueries;
|
||||
int noAlias;
|
||||
int selfAlias;
|
||||
int possibleAlias;
|
||||
int unknownAlias;
|
||||
int localArrays;
|
||||
int functionParameters;
|
||||
int globalArrays;
|
||||
int constantAccesses;
|
||||
};
|
||||
|
||||
Statistics getStatistics() const;
|
||||
|
||||
/**
|
||||
* 打印别名分析结果 (调试用)
|
||||
*/
|
||||
void print() const;
|
||||
void printStatics() const;
|
||||
// ========== 内部方法 ==========
|
||||
|
||||
void addMemoryLocation(std::unique_ptr<MemoryLocation> location);
|
||||
void addAliasRelation(Value* ptr1, Value* ptr2, AliasType type);
|
||||
|
||||
// ========== 公开数据成员 (供Pass使用) ==========
|
||||
std::map<Value*, std::unique_ptr<MemoryLocation>> LocationMap; // 内存位置映射
|
||||
std::map<std::pair<Value*, Value*>, AliasType> AliasMap; // 别名关系缓存
|
||||
|
||||
private:
|
||||
Function *AssociatedFunction; // 关联的函数
|
||||
|
||||
// 分类存储
|
||||
std::vector<Argument*> ArrayParameters; // 数组参数
|
||||
std::vector<AllocaInst*> LocalArrays; // 局部数组
|
||||
std::set<GlobalValue*> AccessedGlobals; // 访问的全局变量
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief SysY语言特化的别名分析Pass
|
||||
* 针对SysY语言特性优化的别名分析实现
|
||||
*/
|
||||
class SysYAliasAnalysisPass : public AnalysisPass {
|
||||
public:
|
||||
// 唯一的 Pass ID
|
||||
static void *ID;
|
||||
// 在这里开启激进分析策略
|
||||
SysYAliasAnalysisPass() : AnalysisPass("SysYAliasAnalysis", Pass::Granularity::Function),
|
||||
aggressiveParameterMode(false), parameterOptimizationEnabled(false) {}
|
||||
|
||||
// 实现 getPassID
|
||||
void *getPassID() const override { return &ID; }
|
||||
|
||||
// 核心运行方法
|
||||
bool runOnFunction(Function *F, AnalysisManager &AM) override;
|
||||
|
||||
// 获取分析结果
|
||||
std::unique_ptr<AnalysisResultBase> getResult() override { return std::move(CurrentResult); }
|
||||
|
||||
// ========== 配置接口 ==========
|
||||
|
||||
/**
|
||||
* 启用针对SysY评测的激进优化模式
|
||||
* 在这种模式下,假设不同参数不会传入相同数组
|
||||
*/
|
||||
void enableSysYTestingMode() {
|
||||
aggressiveParameterMode = true;
|
||||
parameterOptimizationEnabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用保守的默认模式(适合通用场景)
|
||||
*/
|
||||
void useConservativeMode() {
|
||||
aggressiveParameterMode = false;
|
||||
parameterOptimizationEnabled = false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<AliasAnalysisResult> CurrentResult; // 当前函数的分析结果
|
||||
|
||||
// ========== 主要分析流程 ==========
|
||||
|
||||
void collectMemoryAccesses(Function* F); // 收集内存访问
|
||||
void buildAliasRelations(Function* F); // 构建别名关系
|
||||
void optimizeForSysY(Function* F); // SysY特化优化
|
||||
|
||||
// ========== 内存位置分析 ==========
|
||||
|
||||
std::unique_ptr<MemoryLocation> createMemoryLocation(Value* ptr);
|
||||
Value* getBasePointer(Value* ptr); // 获取基指针
|
||||
void analyzeMemoryType(MemoryLocation* location); // 分析内存类型
|
||||
void analyzeIndexPattern(MemoryLocation* location); // 分析索引模式
|
||||
|
||||
// ========== 别名关系推断 ==========
|
||||
|
||||
AliasType analyzeAliasBetween(MemoryLocation* loc1, MemoryLocation* loc2);
|
||||
AliasType compareIndices(MemoryLocation* loc1, MemoryLocation* loc2);
|
||||
AliasType compareLocalArrays(MemoryLocation* loc1, MemoryLocation* loc2);
|
||||
AliasType compareParameters(MemoryLocation* loc1, MemoryLocation* loc2);
|
||||
AliasType compareWithGlobal(MemoryLocation* loc1, MemoryLocation* loc2);
|
||||
AliasType compareMixedTypes(MemoryLocation* loc1, MemoryLocation* loc2);
|
||||
|
||||
// ========== SysY特化优化 ==========
|
||||
|
||||
void applySysYConstraints(Function* F); // 应用SysY语言约束
|
||||
void optimizeParameterAnalysis(Function* F); // 优化参数分析
|
||||
void optimizeArrayAccessAnalysis(Function* F); // 优化数组访问分析
|
||||
|
||||
// ========== 配置和策略控制 ==========
|
||||
|
||||
bool useAggressiveParameterAnalysis() const { return aggressiveParameterMode; }
|
||||
bool enableParameterOptimization() const { return parameterOptimizationEnabled; }
|
||||
void setAggressiveParameterMode(bool enable) { aggressiveParameterMode = enable; }
|
||||
void setParameterOptimizationEnabled(bool enable) { parameterOptimizationEnabled = enable; }
|
||||
|
||||
// ========== 辅助优化方法 ==========
|
||||
|
||||
void optimizeConstantIndexAccesses(); // 优化常量索引访问
|
||||
void optimizeSequentialAccesses(); // 优化顺序访问
|
||||
|
||||
// ========== 辅助方法 ==========
|
||||
|
||||
bool isConstantValue(Value* val); // 是否为常量
|
||||
bool hasLoopVariableInIndices(const std::vector<Value*>& indices, Function* F);
|
||||
int calculateConstantOffset(const std::vector<Value*>& indices);
|
||||
void printStatistics() const; // 打印统计信息
|
||||
|
||||
private:
|
||||
// ========== 配置选项 ==========
|
||||
bool aggressiveParameterMode = false; // 激进的参数别名分析模式
|
||||
bool parameterOptimizationEnabled = false; // 启用参数优化
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
242
src/include/midend/Pass/Analysis/CallGraphAnalysis.h
Normal file
242
src/include/midend/Pass/Analysis/CallGraphAnalysis.h
Normal file
@@ -0,0 +1,242 @@
|
||||
#pragma once
|
||||
|
||||
#include "IR.h"
|
||||
#include "Pass.h"
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 前向声明
|
||||
class CallGraphAnalysisResult;
|
||||
|
||||
/**
|
||||
* @brief 调用图节点信息
|
||||
* 存储单个函数在调用图中的信息
|
||||
*/
|
||||
struct CallGraphNode {
|
||||
Function* function; // 关联的函数
|
||||
std::set<Function*> callers; // 调用此函数的函数集合
|
||||
std::set<Function*> callees; // 此函数调用的函数集合
|
||||
|
||||
// 递归信息
|
||||
bool isRecursive; // 是否参与递归调用
|
||||
bool isSelfRecursive; // 是否自递归
|
||||
int recursiveDepth; // 递归深度(-1表示无限递归)
|
||||
|
||||
// 调用统计
|
||||
size_t totalCallers; // 调用者总数
|
||||
size_t totalCallees; // 被调用函数总数
|
||||
size_t callSiteCount; // 调用点总数
|
||||
|
||||
CallGraphNode(Function* f) : function(f), isRecursive(false),
|
||||
isSelfRecursive(false), recursiveDepth(0), totalCallers(0),
|
||||
totalCallees(0), callSiteCount(0) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 调用图分析结果类
|
||||
* 包含整个模块的调用图信息和查询接口
|
||||
*/
|
||||
class CallGraphAnalysisResult : public AnalysisResultBase {
|
||||
public:
|
||||
CallGraphAnalysisResult(Module* M) : AssociatedModule(M) {}
|
||||
~CallGraphAnalysisResult() override = default;
|
||||
|
||||
// ========== 基础查询接口 ==========
|
||||
|
||||
/**
|
||||
* 获取函数的调用图节点
|
||||
*/
|
||||
const CallGraphNode* getNode(Function* F) const {
|
||||
auto it = nodes.find(F);
|
||||
return (it != nodes.end()) ? it->second.get() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取函数的调用图节点(非const版本)
|
||||
*/
|
||||
CallGraphNode* getMutableNode(Function* F) {
|
||||
auto it = nodes.find(F);
|
||||
return (it != nodes.end()) ? it->second.get() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有函数节点
|
||||
*/
|
||||
const std::map<Function*, std::unique_ptr<CallGraphNode>>& getAllNodes() const {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查函数是否存在于调用图中
|
||||
*/
|
||||
bool hasFunction(Function* F) const {
|
||||
return nodes.find(F) != nodes.end();
|
||||
}
|
||||
|
||||
// ========== 调用关系查询 ==========
|
||||
|
||||
/**
|
||||
* 检查是否存在从caller到callee的调用
|
||||
*/
|
||||
bool hasCallEdge(Function* caller, Function* callee) const {
|
||||
auto node = getNode(caller);
|
||||
return node && node->callees.count(callee) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取函数的所有调用者
|
||||
*/
|
||||
std::vector<Function*> getCallers(Function* F) const {
|
||||
auto node = getNode(F);
|
||||
if (!node) return {};
|
||||
return std::vector<Function*>(node->callers.begin(), node->callers.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取函数的所有被调用函数
|
||||
*/
|
||||
std::vector<Function*> getCallees(Function* F) const {
|
||||
auto node = getNode(F);
|
||||
if (!node) return {};
|
||||
return std::vector<Function*>(node->callees.begin(), node->callees.end());
|
||||
}
|
||||
|
||||
// ========== 递归分析查询 ==========
|
||||
|
||||
/**
|
||||
* 检查函数是否参与递归调用
|
||||
*/
|
||||
bool isRecursive(Function* F) const {
|
||||
auto node = getNode(F);
|
||||
return node && node->isRecursive;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查函数是否自递归
|
||||
*/
|
||||
bool isSelfRecursive(Function* F) const {
|
||||
auto node = getNode(F);
|
||||
return node && node->isSelfRecursive;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取递归深度
|
||||
*/
|
||||
int getRecursiveDepth(Function* F) const {
|
||||
auto node = getNode(F);
|
||||
return node ? node->recursiveDepth : 0;
|
||||
}
|
||||
|
||||
// ========== 拓扑排序和SCC ==========
|
||||
|
||||
/**
|
||||
* 获取函数的拓扑排序结果
|
||||
* 保证被调用函数在调用函数之前
|
||||
*/
|
||||
const std::vector<Function*>& getTopologicalOrder() const {
|
||||
return topologicalOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取强连通分量列表
|
||||
* 每个SCC表示一个递归函数群
|
||||
*/
|
||||
const std::vector<std::vector<Function*>>& getStronglyConnectedComponents() const {
|
||||
return sccs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取函数所在的SCC索引
|
||||
*/
|
||||
int getSCCIndex(Function* F) const {
|
||||
auto it = functionToSCC.find(F);
|
||||
return (it != functionToSCC.end()) ? it->second : -1;
|
||||
}
|
||||
|
||||
// ========== 统计信息 ==========
|
||||
|
||||
struct Statistics {
|
||||
size_t totalFunctions;
|
||||
size_t totalCallEdges;
|
||||
size_t recursiveFunctions;
|
||||
size_t selfRecursiveFunctions;
|
||||
size_t stronglyConnectedComponents;
|
||||
size_t maxSCCSize;
|
||||
double avgCallersPerFunction;
|
||||
double avgCalleesPerFunction;
|
||||
};
|
||||
|
||||
Statistics getStatistics() const;
|
||||
|
||||
/**
|
||||
* 打印调用图分析结果
|
||||
*/
|
||||
void print() const;
|
||||
|
||||
// ========== 内部构建接口 ==========
|
||||
|
||||
void addNode(Function* F);
|
||||
void addCallEdge(Function* caller, Function* callee);
|
||||
void computeTopologicalOrder();
|
||||
void computeStronglyConnectedComponents();
|
||||
void analyzeRecursion();
|
||||
|
||||
private:
|
||||
Module* AssociatedModule; // 关联的模块
|
||||
std::map<Function*, std::unique_ptr<CallGraphNode>> nodes; // 调用图节点
|
||||
std::vector<Function*> topologicalOrder; // 拓扑排序结果
|
||||
std::vector<std::vector<Function*>> sccs; // 强连通分量
|
||||
std::map<Function*, int> functionToSCC; // 函数到SCC的映射
|
||||
|
||||
// 内部辅助方法
|
||||
void dfsTopological(Function* F, std::unordered_set<Function*>& visited,
|
||||
std::vector<Function*>& result);
|
||||
void tarjanSCC();
|
||||
void tarjanDFS(Function* F, int& index, std::vector<int>& indices,
|
||||
std::vector<int>& lowlinks, std::vector<Function*>& stack,
|
||||
std::unordered_set<Function*>& onStack);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief SysY调用图分析Pass
|
||||
* Module级别的分析Pass,构建整个模块的函数调用图
|
||||
*/
|
||||
class CallGraphAnalysisPass : public AnalysisPass {
|
||||
public:
|
||||
// 唯一的 Pass ID
|
||||
static void* ID;
|
||||
|
||||
CallGraphAnalysisPass() : AnalysisPass("CallGraphAnalysis", Pass::Granularity::Module) {}
|
||||
|
||||
// 实现 getPassID
|
||||
void* getPassID() const override { return &ID; }
|
||||
|
||||
// 核心运行方法
|
||||
bool runOnModule(Module* M, AnalysisManager& AM) override;
|
||||
|
||||
// 获取分析结果
|
||||
std::unique_ptr<AnalysisResultBase> getResult() override { return std::move(CurrentResult); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<CallGraphAnalysisResult> CurrentResult; // 当前模块的分析结果
|
||||
|
||||
// ========== 主要分析流程 ==========
|
||||
|
||||
void buildCallGraph(Module* M); // 构建调用图
|
||||
void scanFunctionCalls(Function* F); // 扫描函数的调用
|
||||
void processCallInstruction(CallInst* call, Function* caller); // 处理调用指令
|
||||
|
||||
// ========== 辅助方法 ==========
|
||||
|
||||
bool isLibraryFunction(Function* F) const; // 判断是否为标准库函数
|
||||
bool isIntrinsicFunction(Function* F) const; // 判断是否为内置函数
|
||||
void printStatistics() const; // 打印统计信息
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
618
src/include/midend/Pass/Analysis/Loop.h
Normal file
618
src/include/midend/Pass/Analysis/Loop.h
Normal file
@@ -0,0 +1,618 @@
|
||||
#pragma once
|
||||
|
||||
#include "Dom.h"
|
||||
#include "IR.h"
|
||||
#include "Pass.h"
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 前向声明
|
||||
class LoopAnalysisResult;
|
||||
class AliasAnalysisResult;
|
||||
class SideEffectAnalysisResult;
|
||||
|
||||
/**
|
||||
* @brief 表示一个识别出的循环。
|
||||
*/
|
||||
class Loop {
|
||||
private:
|
||||
static int NextLoopID; // 静态变量用于分配唯一ID
|
||||
int LoopID;
|
||||
public:
|
||||
// 构造函数:指定循环头
|
||||
Loop(BasicBlock *header) : Header(header), LoopID(NextLoopID++) {}
|
||||
|
||||
// 获取循环头
|
||||
BasicBlock *getHeader() const { return Header; }
|
||||
|
||||
// 获取循环的名称 (基于ID)
|
||||
std::string getName() const { return "loop_" + std::to_string(LoopID); }
|
||||
// 获取循环体包含的所有基本块
|
||||
const std::set<BasicBlock *> &getBlocks() const { return LoopBlocks; }
|
||||
|
||||
// 获取循环的出口基本块(即从循环内部跳转到循环外部的基本块)
|
||||
const std::set<BasicBlock *> &getExitBlocks() const { return ExitBlocks; }
|
||||
|
||||
// 获取循环前置块(如果存在),可以为 nullptr
|
||||
BasicBlock *getPreHeader() const { return PreHeader; }
|
||||
|
||||
// 获取直接包含此循环的父循环(如果存在),可以为 nullptr
|
||||
Loop *getParentLoop() const { return ParentLoop; }
|
||||
|
||||
// 获取直接嵌套在此循环内的子循环
|
||||
const std::vector<Loop *> &getNestedLoops() const { return NestedLoops; }
|
||||
|
||||
// 获取循环的层级 (0 表示最外层循环,1 表示嵌套一层,以此类推)
|
||||
int getLoopLevel() const { return Level; }
|
||||
|
||||
// 检查一个基本块是否属于当前循环
|
||||
bool contains(BasicBlock *BB) const { return LoopBlocks.count(BB); }
|
||||
|
||||
// 判断当前循环是否是最内层循环 (没有嵌套子循环)
|
||||
bool isInnermost() const { return NestedLoops.empty(); }
|
||||
|
||||
// 获取循环的深度(从最外层开始计算)
|
||||
int getLoopDepth() const { return Level + 1; }
|
||||
|
||||
// 获取循环体的大小(基本块数量)
|
||||
size_t getLoopSize() const { return LoopBlocks.size(); }
|
||||
|
||||
// 检查循环是否有唯一的外部前驱(即是否有前置块)
|
||||
bool hasUniquePreHeader() const { return PreHeader != nullptr; }
|
||||
|
||||
// 检查循环是否是最外层循环(没有父循环)
|
||||
bool isOutermost() const { return getParentLoop() == nullptr; }
|
||||
|
||||
// 获取循环的所有出口(从循环内到循环外的基本块)
|
||||
std::vector<BasicBlock*> getExitingBlocks() const {
|
||||
std::vector<BasicBlock*> exitingBlocks;
|
||||
for (BasicBlock* bb : LoopBlocks) {
|
||||
for (BasicBlock* succ : bb->getSuccessors()) {
|
||||
if (!contains(succ)) {
|
||||
exitingBlocks.push_back(bb);
|
||||
break; // 每个基本块只添加一次
|
||||
}
|
||||
}
|
||||
}
|
||||
return exitingBlocks;
|
||||
}
|
||||
|
||||
// 判断循环是否是简单循环(只有一个回边)
|
||||
bool isSimpleLoop() const {
|
||||
int backEdgeCount = 0;
|
||||
for (BasicBlock* pred : Header->getPredecessors()) {
|
||||
if (contains(pred)) {
|
||||
backEdgeCount++;
|
||||
}
|
||||
}
|
||||
return backEdgeCount == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有出口目标块 (循环外接收循环出口边的块)
|
||||
* 使用场景: 循环后置处理、phi节点分析
|
||||
*/
|
||||
std::vector<BasicBlock*> getExitTargetBlocks() const {
|
||||
std::set<BasicBlock*> exitTargetSet;
|
||||
for (BasicBlock* bb : LoopBlocks) {
|
||||
for (BasicBlock* succ : bb->getSuccessors()) {
|
||||
if (!contains(succ)) {
|
||||
exitTargetSet.insert(succ);
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::vector<BasicBlock*>(exitTargetSet.begin(), exitTargetSet.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算循环的"深度"相对于指定的祖先循环
|
||||
* 使用场景: 相对深度计算、嵌套分析
|
||||
*/
|
||||
int getRelativeDepth(Loop* ancestor) const {
|
||||
if (this == ancestor) return 0;
|
||||
|
||||
int depth = 0;
|
||||
Loop* current = this->ParentLoop;
|
||||
while (current && current != ancestor) {
|
||||
depth++;
|
||||
current = current->ParentLoop;
|
||||
}
|
||||
|
||||
return current == ancestor ? depth : -1; // -1表示不是祖先关系
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查循环是否包含函数调用
|
||||
* 使用场景: 内联决策、副作用分析
|
||||
*/
|
||||
bool containsFunctionCalls() const {
|
||||
for (BasicBlock* bb : LoopBlocks) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (dynamic_cast<CallInst*>(inst.get())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查循环是否可能有副作用(基于副作用分析结果)
|
||||
* 使用场景: 循环优化决策、并行化分析
|
||||
*/
|
||||
bool mayHaveSideEffects(SideEffectAnalysisResult* sideEffectAnalysis) const;
|
||||
|
||||
/**
|
||||
* 检查循环是否访问全局内存(基于别名分析结果)
|
||||
* 使用场景: 并行化分析、缓存优化
|
||||
*/
|
||||
bool accessesGlobalMemory(AliasAnalysisResult* aliasAnalysis) const;
|
||||
|
||||
/**
|
||||
* 检查循环是否有可能的内存别名冲突
|
||||
* 使用场景: 向量化分析、并行化决策
|
||||
*/
|
||||
bool hasMemoryAliasConflicts(AliasAnalysisResult* aliasAnalysis) const;
|
||||
|
||||
/**
|
||||
* 估算循环的"热度" (基于嵌套深度和大小)
|
||||
* 使用场景: 优化优先级、资源分配
|
||||
*/
|
||||
double getLoopHotness() const {
|
||||
// 简单的热度估算: 深度权重 + 大小惩罚
|
||||
double hotness = std::pow(2.0, Level); // 深度越深越热
|
||||
hotness /= std::sqrt(LoopBlocks.size()); // 大小越大相对热度降低
|
||||
return hotness;
|
||||
}
|
||||
|
||||
// --- 供 LoopAnalysisPass 内部调用的方法,用于构建 Loop 对象 ---
|
||||
void addBlock(BasicBlock *BB) { LoopBlocks.insert(BB); }
|
||||
void addExitBlock(BasicBlock *BB) { ExitBlocks.insert(BB); }
|
||||
void setPreHeader(BasicBlock *BB) { PreHeader = BB; }
|
||||
void setParentLoop(Loop *loop) { ParentLoop = loop; }
|
||||
void addNestedLoop(Loop *loop) { NestedLoops.push_back(loop); }
|
||||
void setLoopLevel(int level) { Level = level; }
|
||||
void clearNestedLoops() { NestedLoops.clear(); }
|
||||
private:
|
||||
BasicBlock *Header; // 循环头基本块
|
||||
std::set<BasicBlock *> LoopBlocks; // 循环体包含的基本块集合
|
||||
std::set<BasicBlock *> ExitBlocks; // 循环出口基本块集合
|
||||
BasicBlock *PreHeader = nullptr; // 循环前置块 (Optional)
|
||||
Loop *ParentLoop = nullptr; // 父循环 (用于嵌套)
|
||||
std::vector<Loop *> NestedLoops; // 嵌套的子循环
|
||||
int Level = -1; // 循环的层级,-1表示未计算
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 循环分析结果类。
|
||||
* 包含一个函数中所有识别出的循环,并提供高效的查询缓存机制。
|
||||
*/
|
||||
class LoopAnalysisResult : public AnalysisResultBase {
|
||||
public:
|
||||
LoopAnalysisResult(Function *F) : AssociatedFunction(F) {}
|
||||
~LoopAnalysisResult() override = default;
|
||||
|
||||
// ========== 缓存统计结构 ==========
|
||||
struct CacheStats {
|
||||
size_t innermostLoopsCached;
|
||||
size_t outermostLoopsCached;
|
||||
size_t loopsByDepthCached;
|
||||
size_t containingLoopsCached;
|
||||
size_t allNestedLoopsCached;
|
||||
size_t totalCachedQueries;
|
||||
};
|
||||
|
||||
private:
|
||||
// ========== 高频查询缓存 ==========
|
||||
mutable std::optional<std::vector<Loop*>> cachedInnermostLoops;
|
||||
mutable std::optional<std::vector<Loop*>> cachedOutermostLoops;
|
||||
mutable std::optional<int> cachedMaxDepth;
|
||||
mutable std::optional<size_t> cachedLoopCount;
|
||||
mutable std::map<int, std::vector<Loop*>> cachedLoopsByDepth;
|
||||
|
||||
// ========== 中频查询缓存 ==========
|
||||
mutable std::map<BasicBlock*, Loop*> cachedInnermostContainingLoop;
|
||||
mutable std::map<Loop*, std::set<Loop*>> cachedAllNestedLoops; // 递归嵌套
|
||||
mutable std::map<BasicBlock*, std::vector<Loop*>> cachedAllContainingLoops;
|
||||
|
||||
// ========== 缓存状态管理 ==========
|
||||
mutable bool cacheValid = true;
|
||||
|
||||
// 内部辅助方法
|
||||
void invalidateCache() const {
|
||||
cachedInnermostLoops.reset();
|
||||
cachedOutermostLoops.reset();
|
||||
cachedMaxDepth.reset();
|
||||
cachedLoopCount.reset();
|
||||
cachedLoopsByDepth.clear();
|
||||
cachedInnermostContainingLoop.clear();
|
||||
cachedAllNestedLoops.clear();
|
||||
cachedAllContainingLoops.clear();
|
||||
cacheValid = false;
|
||||
}
|
||||
|
||||
void ensureCacheValid() const {
|
||||
if (!cacheValid) {
|
||||
// 重新计算基础缓存
|
||||
computeBasicCache();
|
||||
cacheValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
void computeBasicCache() const {
|
||||
// 计算最内层循环
|
||||
if (!cachedInnermostLoops) {
|
||||
cachedInnermostLoops = std::vector<Loop*>();
|
||||
for (const auto& loop : AllLoops) {
|
||||
if (loop->isInnermost()) {
|
||||
cachedInnermostLoops->push_back(loop.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 计算最外层循环
|
||||
if (!cachedOutermostLoops) {
|
||||
cachedOutermostLoops = std::vector<Loop*>();
|
||||
for (const auto& loop : AllLoops) {
|
||||
if (loop->isOutermost()) {
|
||||
cachedOutermostLoops->push_back(loop.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 计算最大深度
|
||||
if (!cachedMaxDepth) {
|
||||
int maxDepth = 0;
|
||||
for (const auto& loop : AllLoops) {
|
||||
maxDepth = std::max(maxDepth, loop->getLoopDepth());
|
||||
}
|
||||
cachedMaxDepth = maxDepth;
|
||||
}
|
||||
|
||||
// 计算循环总数
|
||||
if (!cachedLoopCount) {
|
||||
cachedLoopCount = AllLoops.size();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// ========== 基础接口 ==========
|
||||
|
||||
// 添加一个识别出的循环到结果中
|
||||
void addLoop(std::unique_ptr<Loop> loop) {
|
||||
invalidateCache(); // 添加新循环时失效缓存
|
||||
AllLoops.push_back(std::move(loop));
|
||||
LoopMap[AllLoops.back()->getHeader()] = AllLoops.back().get();
|
||||
}
|
||||
|
||||
// 获取所有识别出的循环(unique_ptr 管理内存)
|
||||
const std::vector<std::unique_ptr<Loop>> &getAllLoops() const { return AllLoops; }
|
||||
|
||||
// ========== 高频查询接口 ==========
|
||||
|
||||
/**
|
||||
* 获取所有最内层循环 - 循环优化的主要目标
|
||||
* 使用场景: 循环展开、向量化、循环不变量外提
|
||||
*/
|
||||
const std::vector<Loop*>& getInnermostLoops() const {
|
||||
ensureCacheValid();
|
||||
if (!cachedInnermostLoops) {
|
||||
cachedInnermostLoops = std::vector<Loop*>();
|
||||
for (const auto& loop : AllLoops) {
|
||||
if (loop->isInnermost()) {
|
||||
cachedInnermostLoops->push_back(loop.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
return *cachedInnermostLoops;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有最外层循环
|
||||
* 使用场景: 循环树遍历、整体优化策略
|
||||
*/
|
||||
const std::vector<Loop*>& getOutermostLoops() const {
|
||||
ensureCacheValid();
|
||||
if (!cachedOutermostLoops) {
|
||||
cachedOutermostLoops = std::vector<Loop*>();
|
||||
for (const auto& loop : AllLoops) {
|
||||
if (loop->isOutermost()) {
|
||||
cachedOutermostLoops->push_back(loop.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
return *cachedOutermostLoops;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定深度的所有循环
|
||||
* 使用场景: 分层优化、循环展开决策、并行化分析
|
||||
*/
|
||||
const std::vector<Loop*>& getLoopsAtDepth(int depth) const {
|
||||
ensureCacheValid();
|
||||
if (cachedLoopsByDepth.find(depth) == cachedLoopsByDepth.end()) {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& loop : AllLoops) {
|
||||
if (loop->getLoopDepth() == depth) {
|
||||
result.push_back(loop.get());
|
||||
}
|
||||
}
|
||||
cachedLoopsByDepth[depth] = std::move(result);
|
||||
}
|
||||
return cachedLoopsByDepth[depth];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最大循环嵌套深度
|
||||
* 使用场景: 优化预算分配、编译时间控制
|
||||
*/
|
||||
int getMaxLoopDepth() const {
|
||||
ensureCacheValid();
|
||||
if (!cachedMaxDepth) {
|
||||
int maxDepth = 0;
|
||||
for (const auto& loop : AllLoops) {
|
||||
maxDepth = std::max(maxDepth, loop->getLoopDepth());
|
||||
}
|
||||
cachedMaxDepth = maxDepth;
|
||||
}
|
||||
return *cachedMaxDepth;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取循环总数
|
||||
* 使用场景: 统计信息、优化决策
|
||||
*/
|
||||
size_t getLoopCount() const {
|
||||
ensureCacheValid();
|
||||
if (!cachedLoopCount) {
|
||||
cachedLoopCount = AllLoops.size();
|
||||
}
|
||||
return *cachedLoopCount;
|
||||
}
|
||||
|
||||
// 获取指定深度的循环数量
|
||||
size_t getLoopCountAtDepth(int depth) const {
|
||||
return getLoopsAtDepth(depth).size();
|
||||
}
|
||||
|
||||
// 检查函数是否包含循环
|
||||
bool hasLoops() const { return !AllLoops.empty(); }
|
||||
|
||||
// ========== 中频查询接口 ==========
|
||||
|
||||
/**
|
||||
* 获取包含指定基本块的最内层循环
|
||||
* 使用场景: 活跃性分析、寄存器分配、指令调度
|
||||
*/
|
||||
Loop* getInnermostContainingLoop(BasicBlock* BB) const {
|
||||
ensureCacheValid();
|
||||
if (cachedInnermostContainingLoop.find(BB) == cachedInnermostContainingLoop.end()) {
|
||||
Loop* result = nullptr;
|
||||
int maxDepth = -1;
|
||||
for (const auto& loop : AllLoops) {
|
||||
if (loop->contains(BB) && loop->getLoopDepth() > maxDepth) {
|
||||
result = loop.get();
|
||||
maxDepth = loop->getLoopDepth();
|
||||
}
|
||||
}
|
||||
cachedInnermostContainingLoop[BB] = result;
|
||||
}
|
||||
return cachedInnermostContainingLoop[BB];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取包含指定基本块的所有循环 (从外到内排序)
|
||||
* 使用场景: 循环间优化、依赖分析
|
||||
*/
|
||||
const std::vector<Loop*>& getAllContainingLoops(BasicBlock* BB) const {
|
||||
ensureCacheValid();
|
||||
if (cachedAllContainingLoops.find(BB) == cachedAllContainingLoops.end()) {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& loop : AllLoops) {
|
||||
if (loop->contains(BB)) {
|
||||
result.push_back(loop.get());
|
||||
}
|
||||
}
|
||||
// 按深度排序 (外层到内层)
|
||||
std::sort(result.begin(), result.end(),
|
||||
[](Loop* a, Loop* b) { return a->getLoopDepth() < b->getLoopDepth(); });
|
||||
cachedAllContainingLoops[BB] = std::move(result);
|
||||
}
|
||||
return cachedAllContainingLoops[BB];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定循环的所有嵌套子循环 (递归)
|
||||
* 使用场景: 循环树分析、嵌套优化
|
||||
*/
|
||||
const std::set<Loop*>& getAllNestedLoops(Loop* loop) const {
|
||||
ensureCacheValid();
|
||||
if (cachedAllNestedLoops.find(loop) == cachedAllNestedLoops.end()) {
|
||||
std::set<Loop*> result;
|
||||
std::function<void(Loop*)> collectNested = [&](Loop* current) {
|
||||
for (Loop* nested : current->getNestedLoops()) {
|
||||
result.insert(nested);
|
||||
collectNested(nested); // 递归收集
|
||||
}
|
||||
};
|
||||
collectNested(loop);
|
||||
cachedAllNestedLoops[loop] = std::move(result);
|
||||
}
|
||||
return cachedAllNestedLoops[loop];
|
||||
}
|
||||
|
||||
// ========== 利用别名和副作用分析的查询接口 ==========
|
||||
|
||||
/**
|
||||
* 获取所有纯循环(无副作用的循环)
|
||||
* 并行化、循环优化
|
||||
*/
|
||||
std::vector<Loop*> getPureLoops(SideEffectAnalysisResult* sideEffectAnalysis) const {
|
||||
std::vector<Loop*> result;
|
||||
if (!sideEffectAnalysis) return result;
|
||||
|
||||
for (const auto& loop : AllLoops) {
|
||||
if (!loop->mayHaveSideEffects(sideEffectAnalysis)) {
|
||||
result.push_back(loop.get());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有只访问局部内存的循环
|
||||
* 缓存优化、局部性分析
|
||||
*/
|
||||
std::vector<Loop*> getLocalMemoryLoops(AliasAnalysisResult* aliasAnalysis) const {
|
||||
std::vector<Loop*> result;
|
||||
if (!aliasAnalysis) return result;
|
||||
|
||||
for (const auto& loop : AllLoops) {
|
||||
if (!loop->accessesGlobalMemory(aliasAnalysis)) {
|
||||
result.push_back(loop.get());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有无内存别名冲突的循环
|
||||
* 向量化、并行化
|
||||
*/
|
||||
std::vector<Loop*> getNoAliasConflictLoops(AliasAnalysisResult* aliasAnalysis) const {
|
||||
std::vector<Loop*> result;
|
||||
if (!aliasAnalysis) return result;
|
||||
|
||||
for (const auto& loop : AllLoops) {
|
||||
if (!loop->hasMemoryAliasConflicts(aliasAnalysis)) {
|
||||
result.push_back(loop.get());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ========== 低频查询接口(不缓存) ==========
|
||||
|
||||
/**
|
||||
* 检查两个循环是否有嵌套关系
|
||||
* 循环间依赖分析
|
||||
*/
|
||||
bool isNestedLoop(Loop* inner, Loop* outer) const {
|
||||
if (inner == outer) return false;
|
||||
|
||||
Loop* current = inner->getParentLoop();
|
||||
while (current) {
|
||||
if (current == outer) return true;
|
||||
current = current->getParentLoop();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取两个循环的最近公共祖先循环
|
||||
* 循环融合分析、优化范围确定
|
||||
*/
|
||||
Loop* getLowestCommonAncestor(Loop* loop1, Loop* loop2) const {
|
||||
if (!loop1 || !loop2) return nullptr;
|
||||
if (loop1 == loop2) return loop1;
|
||||
|
||||
// 收集loop1的所有祖先
|
||||
std::set<Loop*> ancestors1;
|
||||
Loop* current = loop1;
|
||||
while (current) {
|
||||
ancestors1.insert(current);
|
||||
current = current->getParentLoop();
|
||||
}
|
||||
|
||||
// 查找loop2祖先链中第一个在ancestors1中的循环
|
||||
current = loop2;
|
||||
while (current) {
|
||||
if (ancestors1.count(current)) {
|
||||
return current;
|
||||
}
|
||||
current = current->getParentLoop();
|
||||
}
|
||||
|
||||
return nullptr; // 没有公共祖先
|
||||
}
|
||||
|
||||
// 通过循环头获取 Loop 对象
|
||||
Loop *getLoopForHeader(BasicBlock *header) const {
|
||||
auto it = LoopMap.find(header);
|
||||
return (it != LoopMap.end()) ? it->second : nullptr;
|
||||
}
|
||||
|
||||
// 通过某个基本块获取包含它的最内层循环 (向后兼容接口)
|
||||
Loop *getLoopContainingBlock(BasicBlock *BB) const {
|
||||
return getInnermostContainingLoop(BB);
|
||||
}
|
||||
|
||||
// ========== 缓存管理接口 ==========
|
||||
|
||||
/**
|
||||
* 手动失效缓存 (可删除)
|
||||
*/
|
||||
void invalidateQueryCache() const {
|
||||
invalidateCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存统计信息
|
||||
*/
|
||||
CacheStats getCacheStats() const {
|
||||
CacheStats stats = {};
|
||||
stats.innermostLoopsCached = cachedInnermostLoops.has_value() ? 1 : 0;
|
||||
stats.outermostLoopsCached = cachedOutermostLoops.has_value() ? 1 : 0;
|
||||
stats.loopsByDepthCached = cachedLoopsByDepth.size();
|
||||
stats.containingLoopsCached = cachedInnermostContainingLoop.size();
|
||||
stats.allNestedLoopsCached = cachedAllNestedLoops.size();
|
||||
stats.totalCachedQueries = stats.innermostLoopsCached + stats.outermostLoopsCached +
|
||||
stats.loopsByDepthCached + stats.containingLoopsCached +
|
||||
stats.allNestedLoopsCached;
|
||||
return stats;
|
||||
}
|
||||
|
||||
// 打印分析结果
|
||||
void print() const;
|
||||
void printBBSet(const std::string &prefix, const std::set<BasicBlock *> &s) const;
|
||||
void printLoopVector(const std::string &prefix, const std::vector<Loop *> &loops) const;
|
||||
|
||||
private:
|
||||
Function *AssociatedFunction; // 结果关联的函数
|
||||
std::vector<std::unique_ptr<Loop>> AllLoops; // 所有识别出的循环
|
||||
std::map<BasicBlock *, Loop *> LoopMap; // 循环头到 Loop* 的映射,方便查找
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 循环分析遍。
|
||||
* 识别函数中的所有循环,并生成 LoopAnalysisResult。
|
||||
*/
|
||||
class LoopAnalysisPass : public AnalysisPass {
|
||||
public:
|
||||
// 唯一的 Pass ID,需要在 .cpp 文件中定义
|
||||
static void *ID;
|
||||
|
||||
LoopAnalysisPass() : AnalysisPass("LoopAnalysis", Pass::Granularity::Function) {}
|
||||
|
||||
// 实现 getPassID
|
||||
void *getPassID() const override { return &ID; }
|
||||
|
||||
// 核心运行方法:在每个函数上执行循环分析
|
||||
bool runOnFunction(Function *F, AnalysisManager &AM) override;
|
||||
|
||||
// 获取分析结果
|
||||
std::unique_ptr<AnalysisResultBase> getResult() override { return std::move(CurrentResult); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<LoopAnalysisResult> CurrentResult; // 当前函数的分析结果
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
360
src/include/midend/Pass/Analysis/LoopCharacteristics.h
Normal file
360
src/include/midend/Pass/Analysis/LoopCharacteristics.h
Normal file
@@ -0,0 +1,360 @@
|
||||
#pragma once
|
||||
|
||||
#include "Dom.h" // 支配树分析依赖
|
||||
#include "Loop.h" // 循环分析依赖
|
||||
#include "Liveness.h" // 活跃性分析依赖
|
||||
#include "AliasAnalysis.h" // 别名分析依赖
|
||||
#include "SideEffectAnalysis.h" // 副作用分析依赖
|
||||
#include "CallGraphAnalysis.h" // 调用图分析依赖
|
||||
#include "IR.h" // IR定义
|
||||
#include "Pass.h" // Pass框架
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 前向声明
|
||||
class LoopCharacteristicsResult;
|
||||
|
||||
enum IVKind {
|
||||
kBasic, // 基本归纳变量
|
||||
kLinear, // 线性归纳变量
|
||||
kCmplx // 复杂派生归纳变量
|
||||
} ; // 归纳变量类型
|
||||
|
||||
struct InductionVarInfo {
|
||||
Value* div; // 派生归纳变量的指令
|
||||
Value* base = nullptr; // 其根phi或BIV或DIV
|
||||
std::pair<Value*, Value*> Multibase = {nullptr, nullptr}; // 多个BIV
|
||||
Instruction::Kind Instkind; // 操作类型
|
||||
int factor = 1; // 系数(如i*2+3的2)
|
||||
int offset = 0; // 常量偏移
|
||||
bool valid; // 是否线性可归约
|
||||
IVKind ivkind; // 归纳变量类型
|
||||
|
||||
|
||||
static std::unique_ptr<InductionVarInfo> createBasicBIV(Value* v, Instruction::Kind kind, Value* base = nullptr, int factor = 1, int offset = 0) {
|
||||
return std::make_unique<InductionVarInfo>(
|
||||
InductionVarInfo{v, base, {nullptr, nullptr}, kind, factor, offset, true, IVKind::kBasic}
|
||||
);
|
||||
}
|
||||
|
||||
static std::unique_ptr<InductionVarInfo> createSingleDIV(Value* v, Instruction::Kind kind, Value* base = nullptr, int factor = 1, int offset = 0) {
|
||||
return std::make_unique<InductionVarInfo>(
|
||||
InductionVarInfo{v, base, {nullptr, nullptr}, kind, factor, offset, true, IVKind::kLinear}
|
||||
);
|
||||
}
|
||||
|
||||
static std::unique_ptr<InductionVarInfo> createDoubleDIV(Value* v, Instruction::Kind kind, Value* base1 = nullptr, Value* base2 = nullptr, int factor = 1, int offset = 0) {
|
||||
return std::make_unique<InductionVarInfo>(
|
||||
InductionVarInfo{v, nullptr, {base1, base2}, kind, factor, offset, false, IVKind::kCmplx}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 循环特征信息结构 - 基础循环分析阶段
|
||||
* 存储循环的基本特征信息,为后续精确分析提供基础
|
||||
*/
|
||||
struct LoopCharacteristics {
|
||||
Loop* loop; // 关联的循环对象
|
||||
|
||||
// ========== 基础循环形式分析 ==========
|
||||
bool isCountingLoop; // 是否为计数循环 (for i=0; i<n; i++)
|
||||
bool isSimpleForLoop; // 是否为简单for循环
|
||||
bool hasComplexControlFlow; // 是否有复杂控制流 (break, continue)
|
||||
bool isInnermost; // 是否为最内层循环
|
||||
|
||||
// ========== 归纳变量分析 ==========
|
||||
|
||||
// ========== 基础循环不变量分析 ==========
|
||||
std::unordered_set<Value*> loopInvariants; // 循环不变量
|
||||
std::unordered_set<Instruction*> invariantInsts; // 可提升的不变指令
|
||||
|
||||
std::vector<std::unique_ptr<InductionVarInfo>> InductionVars; // 归纳变量
|
||||
|
||||
// ========== 基础边界分析 ==========
|
||||
std::optional<int> staticTripCount; // 静态循环次数(如果可确定)
|
||||
bool hasKnownBounds; // 是否有已知边界
|
||||
|
||||
// ========== 基础纯度和副作用分析 ==========
|
||||
bool isPure; // 是否为纯循环(无副作用)
|
||||
bool accessesOnlyLocalMemory; // 是否只访问局部内存
|
||||
bool hasNoMemoryAliasConflicts; // 是否无内存别名冲突
|
||||
|
||||
// ========== 基础内存访问模式分析 ==========
|
||||
struct MemoryAccessPattern {
|
||||
std::vector<Instruction*> loadInsts; // load指令列表
|
||||
std::vector<Instruction*> storeInsts; // store指令列表
|
||||
bool isArrayParameter; // 是否为数组参数访问
|
||||
bool isGlobalArray; // 是否为全局数组访问
|
||||
bool hasConstantIndices; // 是否使用常量索引
|
||||
};
|
||||
std::map<Value*, MemoryAccessPattern> memoryPatterns; // 内存访问模式
|
||||
|
||||
// ========== 基础性能特征 ==========
|
||||
size_t instructionCount; // 循环体指令数
|
||||
size_t memoryOperationCount; // 内存操作数
|
||||
size_t arithmeticOperationCount; // 算术操作数
|
||||
double computeToMemoryRatio; // 计算与内存操作比率
|
||||
|
||||
// ========== 基础优化提示 ==========
|
||||
bool benefitsFromUnrolling; // 是否适合循环展开
|
||||
int suggestedUnrollFactor; // 建议的展开因子
|
||||
|
||||
// 构造函数 - 简化的基础分析初始化
|
||||
LoopCharacteristics(Loop* l) : loop(l),
|
||||
isCountingLoop(false), isSimpleForLoop(false), hasComplexControlFlow(false),
|
||||
isInnermost(false), hasKnownBounds(false), isPure(false),
|
||||
accessesOnlyLocalMemory(false), hasNoMemoryAliasConflicts(false),
|
||||
benefitsFromUnrolling(false), suggestedUnrollFactor(1),
|
||||
instructionCount(0), memoryOperationCount(0),
|
||||
arithmeticOperationCount(0), computeToMemoryRatio(0.0) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 循环特征分析结果类
|
||||
* 包含函数中所有循环的特征信息,并提供查询接口
|
||||
*/
|
||||
class LoopCharacteristicsResult : public AnalysisResultBase {
|
||||
public:
|
||||
LoopCharacteristicsResult(Function *F) : AssociatedFunction(F) {}
|
||||
~LoopCharacteristicsResult() override = default;
|
||||
|
||||
// ========== 基础接口 ==========
|
||||
|
||||
/**
|
||||
* 添加循环特征信息
|
||||
*/
|
||||
void addLoopCharacteristics(std::unique_ptr<LoopCharacteristics> characteristics) {
|
||||
auto* loop = characteristics->loop;
|
||||
CharacteristicsMap[loop] = std::move(characteristics);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定循环的特征信息
|
||||
*/
|
||||
const LoopCharacteristics* getCharacteristics(Loop* loop) const {
|
||||
auto it = CharacteristicsMap.find(loop);
|
||||
return (it != CharacteristicsMap.end()) ? it->second.get() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有循环特征信息
|
||||
*/
|
||||
const std::map<Loop*, std::unique_ptr<LoopCharacteristics>>& getAllCharacteristics() const {
|
||||
return CharacteristicsMap;
|
||||
}
|
||||
|
||||
// ========== 核心查询接口 ==========
|
||||
|
||||
/**
|
||||
* 获取所有计数循环
|
||||
*/
|
||||
std::vector<Loop*> getCountingLoops() const {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& [loop, chars] : CharacteristicsMap) {
|
||||
if (chars->isCountingLoop) {
|
||||
result.push_back(loop);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有纯循环(无副作用)
|
||||
*/
|
||||
std::vector<Loop*> getPureLoops() const {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& [loop, chars] : CharacteristicsMap) {
|
||||
if (chars->isPure) {
|
||||
result.push_back(loop);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有只访问局部内存的循环
|
||||
*/
|
||||
std::vector<Loop*> getLocalMemoryOnlyLoops() const {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& [loop, chars] : CharacteristicsMap) {
|
||||
if (chars->accessesOnlyLocalMemory) {
|
||||
result.push_back(loop);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有无内存别名冲突的循环
|
||||
*/
|
||||
std::vector<Loop*> getNoAliasConflictLoops() const {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& [loop, chars] : CharacteristicsMap) {
|
||||
if (chars->hasNoMemoryAliasConflicts) {
|
||||
result.push_back(loop);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有适合展开的循环
|
||||
*/
|
||||
std::vector<Loop*> getUnrollingCandidates() const {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& [loop, chars] : CharacteristicsMap) {
|
||||
if (chars->benefitsFromUnrolling) {
|
||||
result.push_back(loop);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据热度排序循环 (用于优化优先级)
|
||||
*/
|
||||
std::vector<Loop*> getLoopsByHotness() const {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& [loop, chars] : CharacteristicsMap) {
|
||||
result.push_back(loop);
|
||||
}
|
||||
|
||||
// 按循环热度排序 (嵌套深度 + 循环次数 + 指令数)
|
||||
std::sort(result.begin(), result.end(), [](Loop* a, Loop* b) {
|
||||
double hotnessA = a->getLoopHotness();
|
||||
double hotnessB = b->getLoopHotness();
|
||||
return hotnessA > hotnessB; // 降序排列
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ========== 基础统计接口 ==========
|
||||
|
||||
/**
|
||||
* 获取基础优化统计信息
|
||||
*/
|
||||
struct BasicOptimizationStats {
|
||||
size_t totalLoops;
|
||||
size_t countingLoops;
|
||||
size_t unrollingCandidates;
|
||||
size_t pureLoops;
|
||||
size_t localMemoryOnlyLoops;
|
||||
size_t noAliasConflictLoops;
|
||||
double avgInstructionCount;
|
||||
double avgComputeMemoryRatio;
|
||||
};
|
||||
|
||||
BasicOptimizationStats getOptimizationStats() const {
|
||||
BasicOptimizationStats stats = {};
|
||||
stats.totalLoops = CharacteristicsMap.size();
|
||||
|
||||
size_t totalInstructions = 0;
|
||||
double totalComputeMemoryRatio = 0.0;
|
||||
|
||||
for (const auto& [loop, chars] : CharacteristicsMap) {
|
||||
if (chars->isCountingLoop) stats.countingLoops++;
|
||||
if (chars->benefitsFromUnrolling) stats.unrollingCandidates++;
|
||||
if (chars->isPure) stats.pureLoops++;
|
||||
if (chars->accessesOnlyLocalMemory) stats.localMemoryOnlyLoops++;
|
||||
if (chars->hasNoMemoryAliasConflicts) stats.noAliasConflictLoops++;
|
||||
|
||||
totalInstructions += chars->instructionCount;
|
||||
totalComputeMemoryRatio += chars->computeToMemoryRatio;
|
||||
}
|
||||
|
||||
if (stats.totalLoops > 0) {
|
||||
stats.avgInstructionCount = static_cast<double>(totalInstructions) / stats.totalLoops;
|
||||
stats.avgComputeMemoryRatio = totalComputeMemoryRatio / stats.totalLoops;
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
// 打印分析结果
|
||||
void print() const;
|
||||
|
||||
private:
|
||||
Function *AssociatedFunction; // 关联的函数
|
||||
std::map<Loop*, std::unique_ptr<LoopCharacteristics>> CharacteristicsMap; // 循环特征映射
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 基础循环特征分析遍
|
||||
* 在循环规范化前执行,进行基础的循环特征分析,为后续精确分析提供基础
|
||||
*/
|
||||
class LoopCharacteristicsPass : public AnalysisPass {
|
||||
public:
|
||||
// 唯一的 Pass ID
|
||||
static void *ID;
|
||||
|
||||
LoopCharacteristicsPass() : AnalysisPass("LoopCharacteristics", Pass::Granularity::Function) {}
|
||||
|
||||
// 实现 getPassID
|
||||
void *getPassID() const override { return &ID; }
|
||||
|
||||
// 核心运行方法
|
||||
bool runOnFunction(Function *F, AnalysisManager &AM) override;
|
||||
|
||||
// 获取分析结果
|
||||
std::unique_ptr<AnalysisResultBase> getResult() override { return std::move(CurrentResult); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<LoopCharacteristicsResult> CurrentResult;
|
||||
|
||||
// ========== 缓存的分析结果 ==========
|
||||
LoopAnalysisResult* loopAnalysis; // 循环结构分析结果
|
||||
AliasAnalysisResult* aliasAnalysis; // 别名分析结果
|
||||
SideEffectAnalysisResult* sideEffectAnalysis; // 副作用分析结果
|
||||
|
||||
// ========== 核心分析方法 ==========
|
||||
void analyzeLoop(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 基础循环形式分析
|
||||
void analyzeLoopForm(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 基础性能指标计算
|
||||
void computePerformanceMetrics(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 基础纯度和副作用分析
|
||||
void analyzePurityAndSideEffects(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 基础归纳变量识别
|
||||
void identifyBasicInductionVariables(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 循环不变量识别
|
||||
void identifyBasicLoopInvariants(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 基础边界分析
|
||||
void analyzeBasicLoopBounds(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 基础内存访问模式分析
|
||||
void analyzeBasicMemoryAccessPatterns(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 基础优化评估
|
||||
void evaluateBasicOptimizationOpportunities(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// ========== 辅助方法 ==========
|
||||
bool isClassicLoopInvariant(Value* val, Loop* loop, const std::unordered_set<Value*>& invariants);
|
||||
void findDerivedInductionVars(Value* root,
|
||||
Value* base, // 只传单一BIV base
|
||||
Loop* loop,
|
||||
std::vector<std::unique_ptr<InductionVarInfo>>& ivs,
|
||||
std::set<Value*>& visited
|
||||
);
|
||||
bool isBasicInductionVariable(Value* val, Loop* loop);
|
||||
// ========== 循环不变量分析辅助方法 ==========
|
||||
bool isInvariantOperands(Instruction* inst, Loop* loop, const std::unordered_set<Value*>& invariants);
|
||||
bool isMemoryLocationModifiedInLoop(Value* ptr, Loop* loop);
|
||||
bool isMemoryLocationLoadedInLoop(Value* ptr, Loop* loop, Instruction* excludeInst = nullptr);
|
||||
bool isPureFunction(Function* calledFunc);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
250
src/include/midend/Pass/Analysis/LoopVectorization.h
Normal file
250
src/include/midend/Pass/Analysis/LoopVectorization.h
Normal file
@@ -0,0 +1,250 @@
|
||||
#pragma once
|
||||
|
||||
#include "Pass.h"
|
||||
#include "Loop.h"
|
||||
#include "LoopCharacteristics.h"
|
||||
#include "AliasAnalysis.h"
|
||||
#include "SideEffectAnalysis.h"
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
/**
|
||||
* @brief 依赖类型枚举 - 只考虑真正影响并行性的依赖
|
||||
*
|
||||
* 依赖类型分析说明:
|
||||
* - TRUE_DEPENDENCE (RAW): 真依赖,必须保持原始执行顺序,是最关键的依赖
|
||||
* - ANTI_DEPENDENCE (WAR): 反依赖,影响指令重排序,可通过寄存器重命名等技术缓解
|
||||
* - OUTPUT_DEPENDENCE (WAW): 输出依赖,相对较少但需要考虑,可通过变量私有化解决
|
||||
*
|
||||
*/
|
||||
enum class DependenceType {
|
||||
TRUE_DEPENDENCE, // 真依赖 (RAW) - 读后写流依赖,最重要的依赖类型
|
||||
ANTI_DEPENDENCE, // 反依赖 (WAR) - 写后读反向依赖,影响指令重排序
|
||||
OUTPUT_DEPENDENCE // 输出依赖 (WAW) - 写后写,相对较少但需要考虑
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 依赖向量 - 表示两个内存访问之间的迭代距离
|
||||
* 例如:a[i] 和 a[i+1] 之间的依赖向量是 [1]
|
||||
* a[i][j] 和 a[i+1][j-2] 之间的依赖向量是 [1,-2]
|
||||
*/
|
||||
struct DependenceVector {
|
||||
std::vector<int> distances; // 每个循环层次的依赖距离
|
||||
bool isConstant; // 是否为常量距离
|
||||
bool isKnown; // 是否已知距离
|
||||
|
||||
DependenceVector(size_t loopDepth) : distances(loopDepth, 0), isConstant(false), isKnown(false) {}
|
||||
|
||||
// 检查是否为循环无关依赖
|
||||
bool isLoopIndependent() const {
|
||||
for (int dist : distances) {
|
||||
if (dist != 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 获取词典序方向向量
|
||||
std::vector<int> getDirectionVector() const;
|
||||
|
||||
// 检查是否可以通过向量化处理
|
||||
bool isVectorizationSafe() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 精确依赖关系 - 包含依赖向量的详细依赖信息
|
||||
*/
|
||||
struct PreciseDependence {
|
||||
Instruction* source;
|
||||
Instruction* sink;
|
||||
DependenceType type;
|
||||
DependenceVector dependenceVector;
|
||||
Value* memoryLocation;
|
||||
|
||||
// 并行化相关
|
||||
bool allowsParallelization; // 是否允许并行化
|
||||
bool requiresSynchronization; // 是否需要同步
|
||||
bool isReductionDependence; // 是否为归约依赖
|
||||
|
||||
PreciseDependence(size_t loopDepth) : dependenceVector(loopDepth),
|
||||
allowsParallelization(true), requiresSynchronization(false), isReductionDependence(false) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 向量化分析信息 - 暂时搁置,保留接口
|
||||
*/
|
||||
struct VectorizationAnalysis {
|
||||
bool isVectorizable; // 固定为false,暂不支持
|
||||
int suggestedVectorWidth; // 固定为1
|
||||
std::vector<std::string> preventingFactors; // 阻止向量化的因素
|
||||
|
||||
VectorizationAnalysis() : isVectorizable(false), suggestedVectorWidth(1) {
|
||||
preventingFactors.push_back("Vectorization temporarily disabled");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 并行化分析信息
|
||||
*/
|
||||
struct ParallelizationAnalysis {
|
||||
bool isParallelizable; // 是否可并行化
|
||||
int suggestedThreadCount; // 建议的线程数
|
||||
std::vector<std::string> preventingFactors; // 阻止并行化的因素
|
||||
|
||||
// 并行化模式
|
||||
enum ParallelizationType {
|
||||
NONE, // 不可并行化
|
||||
EMBARRASSINGLY_PARALLEL, // 完全并行
|
||||
REDUCTION_PARALLEL, // 归约并行
|
||||
PIPELINE_PARALLEL, // 流水线并行
|
||||
CONDITIONAL_PARALLEL // 条件并行
|
||||
} parallelType;
|
||||
|
||||
// 负载均衡
|
||||
bool hasLoadBalance; // 是否有良好的负载均衡
|
||||
bool isDynamicLoadBalanced; // 是否需要动态负载均衡
|
||||
double workComplexity; // 工作复杂度估计
|
||||
|
||||
// 同步需求
|
||||
bool requiresReduction; // 是否需要归约操作
|
||||
bool requiresBarrier; // 是否需要屏障同步
|
||||
std::set<Value*> sharedVariables; // 共享变量
|
||||
std::set<Value*> reductionVariables; // 归约变量
|
||||
std::set<Value*> privatizableVariables; // 可私有化变量
|
||||
|
||||
// 内存访问模式
|
||||
bool hasMemoryConflicts; // 是否有内存冲突
|
||||
bool hasReadOnlyAccess; // 是否只有只读访问
|
||||
bool hasIndependentAccess; // 是否有独立的内存访问
|
||||
|
||||
// 并行化收益评估
|
||||
double parallelizationBenefit; // 并行化收益估计 (0-1)
|
||||
size_t communicationCost; // 通信开销估计
|
||||
size_t synchronizationCost; // 同步开销估计
|
||||
|
||||
ParallelizationAnalysis() : isParallelizable(false), suggestedThreadCount(1), parallelType(NONE),
|
||||
hasLoadBalance(true), isDynamicLoadBalanced(false), workComplexity(0.0), requiresReduction(false),
|
||||
requiresBarrier(false), hasMemoryConflicts(false), hasReadOnlyAccess(false), hasIndependentAccess(false),
|
||||
parallelizationBenefit(0.0), communicationCost(0), synchronizationCost(0) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 循环向量化/并行化分析结果
|
||||
*/
|
||||
class LoopVectorizationResult : public AnalysisResultBase {
|
||||
private:
|
||||
Function* AssociatedFunction;
|
||||
std::map<Loop*, VectorizationAnalysis> VectorizationMap;
|
||||
std::map<Loop*, ParallelizationAnalysis> ParallelizationMap;
|
||||
std::map<Loop*, std::vector<PreciseDependence>> DependenceMap;
|
||||
|
||||
public:
|
||||
LoopVectorizationResult(Function* F) : AssociatedFunction(F) {}
|
||||
~LoopVectorizationResult() override = default;
|
||||
|
||||
// 基础接口
|
||||
void addVectorizationAnalysis(Loop* loop, VectorizationAnalysis analysis) {
|
||||
VectorizationMap[loop] = std::move(analysis);
|
||||
}
|
||||
|
||||
void addParallelizationAnalysis(Loop* loop, ParallelizationAnalysis analysis) {
|
||||
ParallelizationMap[loop] = std::move(analysis);
|
||||
}
|
||||
|
||||
void addDependenceAnalysis(Loop* loop, std::vector<PreciseDependence> dependences) {
|
||||
DependenceMap[loop] = std::move(dependences);
|
||||
}
|
||||
|
||||
// 查询接口
|
||||
const VectorizationAnalysis* getVectorizationAnalysis(Loop* loop) const {
|
||||
auto it = VectorizationMap.find(loop);
|
||||
return it != VectorizationMap.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
const ParallelizationAnalysis* getParallelizationAnalysis(Loop* loop) const {
|
||||
auto it = ParallelizationMap.find(loop);
|
||||
return it != ParallelizationMap.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
const std::vector<PreciseDependence>* getPreciseDependences(Loop* loop) const {
|
||||
auto it = DependenceMap.find(loop);
|
||||
return it != DependenceMap.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
// 统计接口
|
||||
size_t getVectorizableLoopCount() const;
|
||||
size_t getParallelizableLoopCount() const;
|
||||
|
||||
// 优化建议
|
||||
std::vector<Loop*> getVectorizationCandidates() const;
|
||||
std::vector<Loop*> getParallelizationCandidates() const;
|
||||
|
||||
// 打印分析结果
|
||||
void print() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 循环向量化/并行化分析遍
|
||||
* 在循环规范化后执行,进行精确的依赖向量分析和向量化/并行化可行性评估
|
||||
* 专注于并行化分析,向量化功能暂时搁置
|
||||
*/
|
||||
class LoopVectorizationPass : public AnalysisPass {
|
||||
public:
|
||||
// 唯一的 Pass ID
|
||||
static void *ID;
|
||||
|
||||
LoopVectorizationPass() : AnalysisPass("LoopVectorization", Pass::Granularity::Function) {}
|
||||
|
||||
// 实现 getPassID
|
||||
void *getPassID() const override { return &ID; }
|
||||
|
||||
// 核心运行方法
|
||||
bool runOnFunction(Function *F, AnalysisManager &AM) override;
|
||||
|
||||
// 获取分析结果
|
||||
std::unique_ptr<AnalysisResultBase> getResult() override { return std::move(CurrentResult); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<LoopVectorizationResult> CurrentResult;
|
||||
|
||||
// ========== 主要分析方法 ==========
|
||||
void analyzeLoop(Loop* loop, LoopCharacteristics* characteristics,
|
||||
AliasAnalysisResult* aliasAnalysis, SideEffectAnalysisResult* sideEffectAnalysis);
|
||||
|
||||
// ========== 依赖向量分析 ==========
|
||||
std::vector<PreciseDependence> computeDependenceVectors(Loop* loop, AliasAnalysisResult* aliasAnalysis);
|
||||
DependenceVector computeAccessDependence(Instruction* inst1, Instruction* inst2, Loop* loop);
|
||||
bool areAccessesAffinelyRelated(Value* ptr1, Value* ptr2, Loop* loop);
|
||||
|
||||
// ========== 向量化分析 (暂时搁置) ==========
|
||||
VectorizationAnalysis analyzeVectorizability(Loop* loop, const std::vector<PreciseDependence>& dependences,
|
||||
LoopCharacteristics* characteristics);
|
||||
|
||||
// ========== 并行化分析 ==========
|
||||
ParallelizationAnalysis analyzeParallelizability(Loop* loop, const std::vector<PreciseDependence>& dependences,
|
||||
LoopCharacteristics* characteristics);
|
||||
bool checkParallelizationLegality(Loop* loop, const std::vector<PreciseDependence>& dependences);
|
||||
int estimateOptimalThreadCount(Loop* loop, LoopCharacteristics* characteristics);
|
||||
ParallelizationAnalysis::ParallelizationType determineParallelizationType(Loop* loop,
|
||||
const std::vector<PreciseDependence>& dependences);
|
||||
|
||||
// ========== 并行化专用分析方法 ==========
|
||||
void analyzeReductionPatterns(Loop* loop, ParallelizationAnalysis* analysis);
|
||||
void analyzeMemoryAccessPatterns(Loop* loop, ParallelizationAnalysis* analysis, AliasAnalysisResult* aliasAnalysis);
|
||||
void estimateParallelizationBenefit(Loop* loop, ParallelizationAnalysis* analysis, LoopCharacteristics* characteristics);
|
||||
void identifyPrivatizableVariables(Loop* loop, ParallelizationAnalysis* analysis);
|
||||
void analyzeSynchronizationNeeds(Loop* loop, ParallelizationAnalysis* analysis, const std::vector<PreciseDependence>& dependences);
|
||||
|
||||
// ========== 辅助方法 ==========
|
||||
std::vector<int> extractInductionCoefficients(Value* ptr, Loop* loop);
|
||||
bool isConstantStride(Value* ptr, Loop* loop, int& stride);
|
||||
bool isIndependentMemoryAccess(Value* ptr1, Value* ptr2, Loop* loop);
|
||||
double estimateWorkComplexity(Loop* loop);
|
||||
bool hasReductionPattern(Value* var, Loop* loop);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
137
src/include/midend/Pass/Analysis/SideEffectAnalysis.h
Normal file
137
src/include/midend/Pass/Analysis/SideEffectAnalysis.h
Normal file
@@ -0,0 +1,137 @@
|
||||
#pragma once
|
||||
|
||||
#include "Pass.h"
|
||||
#include "IR.h"
|
||||
#include "AliasAnalysis.h"
|
||||
#include "CallGraphAnalysis.h"
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 副作用类型枚举
|
||||
enum class SideEffectType {
|
||||
NO_SIDE_EFFECT, // 无副作用
|
||||
MEMORY_WRITE, // 内存写入(store、memset)
|
||||
FUNCTION_CALL, // 函数调用(可能有任意副作用)
|
||||
IO_OPERATION, // I/O操作(printf、scanf等)
|
||||
UNKNOWN // 未知副作用
|
||||
};
|
||||
|
||||
// 副作用信息结构
|
||||
struct SideEffectInfo {
|
||||
SideEffectType type = SideEffectType::NO_SIDE_EFFECT;
|
||||
bool mayModifyGlobal = false; // 可能修改全局变量
|
||||
bool mayModifyMemory = false; // 可能修改内存
|
||||
bool mayCallFunction = false; // 可能调用函数
|
||||
bool isPure = true; // 是否为纯函数(无副作用且结果只依赖参数)
|
||||
|
||||
// 合并两个副作用信息
|
||||
SideEffectInfo merge(const SideEffectInfo& other) const {
|
||||
SideEffectInfo result;
|
||||
result.type = (type == SideEffectType::NO_SIDE_EFFECT) ? other.type : type;
|
||||
result.mayModifyGlobal = mayModifyGlobal || other.mayModifyGlobal;
|
||||
result.mayModifyMemory = mayModifyMemory || other.mayModifyMemory;
|
||||
result.mayCallFunction = mayCallFunction || other.mayCallFunction;
|
||||
result.isPure = isPure && other.isPure;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// 副作用分析结果类
|
||||
class SideEffectAnalysisResult : public AnalysisResultBase {
|
||||
private:
|
||||
// 指令级别的副作用信息
|
||||
std::unordered_map<Instruction*, SideEffectInfo> instructionSideEffects;
|
||||
|
||||
// 函数级别的副作用信息
|
||||
std::unordered_map<Function*, SideEffectInfo> functionSideEffects;
|
||||
|
||||
// 已知的SysY标准库函数副作用信息
|
||||
std::unordered_map<std::string, SideEffectInfo> knownFunctions;
|
||||
|
||||
public:
|
||||
SideEffectAnalysisResult();
|
||||
virtual ~SideEffectAnalysisResult() noexcept override = default;
|
||||
|
||||
// 获取指令的副作用信息
|
||||
const SideEffectInfo& getInstructionSideEffect(Instruction* inst) const;
|
||||
|
||||
// 获取函数的副作用信息
|
||||
const SideEffectInfo& getFunctionSideEffect(Function* func) const;
|
||||
|
||||
// 设置指令的副作用信息
|
||||
void setInstructionSideEffect(Instruction* inst, const SideEffectInfo& info);
|
||||
|
||||
// 设置函数的副作用信息
|
||||
void setFunctionSideEffect(Function* func, const SideEffectInfo& info);
|
||||
|
||||
// 检查指令是否有副作用
|
||||
bool hasSideEffect(Instruction* inst) const;
|
||||
|
||||
// 检查指令是否可能修改内存
|
||||
bool mayModifyMemory(Instruction* inst) const;
|
||||
|
||||
// 检查指令是否可能修改全局状态
|
||||
bool mayModifyGlobal(Instruction* inst) const;
|
||||
|
||||
// 检查函数是否为纯函数
|
||||
bool isPureFunction(Function* func) const;
|
||||
|
||||
// 获取已知函数的副作用信息
|
||||
const SideEffectInfo* getKnownFunctionSideEffect(const std::string& funcName) const;
|
||||
|
||||
// 初始化已知函数的副作用信息
|
||||
void initializeKnownFunctions();
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
// 副作用分析遍类 - Module级别分析
|
||||
class SysYSideEffectAnalysisPass : public AnalysisPass {
|
||||
public:
|
||||
// 静态成员,作为该遍的唯一ID
|
||||
static void* ID;
|
||||
|
||||
SysYSideEffectAnalysisPass() : AnalysisPass("SysYSideEffectAnalysis", Granularity::Module) {}
|
||||
|
||||
// 在模块上运行分析
|
||||
bool runOnModule(Module* M, AnalysisManager& AM) override;
|
||||
|
||||
// 获取分析结果
|
||||
std::unique_ptr<AnalysisResultBase> getResult() override;
|
||||
|
||||
// Pass 基类中的纯虚函数,必须实现
|
||||
void* getPassID() const override { return &ID; }
|
||||
|
||||
private:
|
||||
// 分析结果
|
||||
std::unique_ptr<SideEffectAnalysisResult> result;
|
||||
|
||||
// 调用图分析结果
|
||||
CallGraphAnalysisResult* callGraphAnalysis = nullptr;
|
||||
|
||||
// 分析单个函数的副作用(Module级别的内部方法)
|
||||
SideEffectInfo analyzeFunction(Function* func, AnalysisManager& AM);
|
||||
|
||||
// 分析单个指令的副作用
|
||||
SideEffectInfo analyzeInstruction(Instruction* inst, Function* currentFunc, AnalysisManager& AM);
|
||||
|
||||
// 分析函数调用指令的副作用(利用调用图)
|
||||
SideEffectInfo analyzeCallInstruction(CallInst* call, Function* currentFunc, AnalysisManager& AM);
|
||||
|
||||
// 分析存储指令的副作用
|
||||
SideEffectInfo analyzeStoreInstruction(StoreInst* store, Function* currentFunc, AnalysisManager& AM);
|
||||
|
||||
// 分析内存设置指令的副作用
|
||||
SideEffectInfo analyzeMemsetInstruction(MemsetInst* memset, Function* currentFunc, AnalysisManager& AM);
|
||||
|
||||
// 使用不动点算法分析递归函数群
|
||||
void analyzeStronglyConnectedComponent(const std::vector<Function*>& scc, AnalysisManager& AM);
|
||||
|
||||
// 检查函数间副作用传播的收敛性
|
||||
bool hasConverged(const std::unordered_map<Function*, SideEffectInfo>& oldEffects,
|
||||
const std::unordered_map<Function*, SideEffectInfo>& newEffects) const;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "IR.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include "Dom.h"
|
||||
#include "AliasAnalysis.h"
|
||||
#include "SideEffectAnalysis.h"
|
||||
#include <unordered_set>
|
||||
#include <queue>
|
||||
|
||||
@@ -25,8 +27,12 @@ public:
|
||||
private:
|
||||
// 存储活跃指令的集合
|
||||
std::unordered_set<Instruction*> alive_insts;
|
||||
// 别名分析结果
|
||||
AliasAnalysisResult* aliasAnalysis = nullptr;
|
||||
// 副作用分析结果
|
||||
SideEffectAnalysisResult* sideEffectAnalysis = nullptr;
|
||||
|
||||
// 判断指令是否是“天然活跃”的(即总是保留的)
|
||||
// 判断指令是否是"天然活跃"的(即总是保留的)
|
||||
// inst: 要检查的指令
|
||||
// 返回值: 如果指令是天然活跃的,则为true,否则为false
|
||||
bool isAlive(Instruction* inst);
|
||||
@@ -34,6 +40,9 @@ private:
|
||||
// 递归地将活跃指令及其依赖加入到 alive_insts 集合中
|
||||
// inst: 要标记为活跃的指令
|
||||
void addAlive(Instruction* inst);
|
||||
|
||||
// 检查Store指令是否可能有副作用(通过别名分析)
|
||||
bool mayHaveSideEffect(StoreInst* store);
|
||||
};
|
||||
|
||||
// DCE 优化遍类,继承自 OptimizationPass
|
||||
|
||||
87
src/include/midend/Pass/Optimize/GVN.h
Normal file
87
src/include/midend/Pass/Optimize/GVN.h
Normal file
@@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
|
||||
#include "Pass.h"
|
||||
#include "IR.h"
|
||||
#include "Dom.h"
|
||||
#include "SideEffectAnalysis.h"
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// GVN优化遍的核心逻辑封装类
|
||||
class GVNContext {
|
||||
public:
|
||||
// 运行GVN优化的主要方法
|
||||
void run(Function* func, AnalysisManager* AM, bool& changed);
|
||||
|
||||
private:
|
||||
// 新的值编号系统
|
||||
std::unordered_map<Value*, unsigned> valueToNumber; // Value -> 值编号
|
||||
std::unordered_map<unsigned, Value*> numberToValue; // 值编号 -> 代表值
|
||||
std::unordered_map<std::string, unsigned> expressionToNumber; // 表达式 -> 值编号
|
||||
unsigned nextValueNumber = 1;
|
||||
|
||||
// 已访问的基本块集合
|
||||
std::unordered_set<BasicBlock*> visited;
|
||||
|
||||
// 逆后序遍历的基本块列表
|
||||
std::vector<BasicBlock*> rpoBlocks;
|
||||
|
||||
// 需要删除的指令集合
|
||||
std::unordered_set<Instruction*> needRemove;
|
||||
|
||||
// 分析结果
|
||||
DominatorTree* domTree = nullptr;
|
||||
SideEffectAnalysisResult* sideEffectAnalysis = nullptr;
|
||||
|
||||
// 计算逆后序遍历
|
||||
void computeRPO(Function* func);
|
||||
void dfs(BasicBlock* bb);
|
||||
|
||||
// 新的值编号方法
|
||||
unsigned getValueNumber(Value* value);
|
||||
unsigned assignValueNumber(Value* value);
|
||||
|
||||
// 基本块处理
|
||||
void processBasicBlock(BasicBlock* bb, bool& changed);
|
||||
|
||||
// 指令处理
|
||||
bool processInstruction(Instruction* inst);
|
||||
|
||||
// 表达式构建和查找
|
||||
std::string buildExpressionKey(Instruction* inst);
|
||||
Value* findExistingValue(const std::string& exprKey, Instruction* inst);
|
||||
|
||||
// 支配关系和安全性检查
|
||||
bool dominates(Instruction* a, Instruction* b);
|
||||
bool isMemorySafe(LoadInst* earlierLoad, LoadInst* laterLoad);
|
||||
|
||||
// 清理方法
|
||||
void eliminateRedundantInstructions(bool& changed);
|
||||
void invalidateMemoryValues(StoreInst* store);
|
||||
};
|
||||
|
||||
// GVN优化遍类
|
||||
class GVN : public OptimizationPass {
|
||||
public:
|
||||
// 静态成员,作为该遍的唯一ID
|
||||
static void* ID;
|
||||
|
||||
GVN() : OptimizationPass("GVN", Granularity::Function) {}
|
||||
|
||||
// 在函数上运行优化
|
||||
bool runOnFunction(Function* func, AnalysisManager& AM) override;
|
||||
|
||||
// 返回该遍的唯一ID
|
||||
void* getPassID() const override { return ID; }
|
||||
|
||||
// 声明分析依赖
|
||||
void getAnalysisUsage(std::set<void*>& analysisDependencies,
|
||||
std::set<void*>& analysisInvalidations) const override;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
107
src/include/midend/Pass/Optimize/GlobalStrengthReduction.h
Normal file
107
src/include/midend/Pass/Optimize/GlobalStrengthReduction.h
Normal file
@@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
|
||||
#include "Pass.h"
|
||||
#include "IR.h"
|
||||
#include "SideEffectAnalysis.h"
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 魔数乘法结构,用于除法优化
|
||||
struct MagicNumber {
|
||||
uint32_t multiplier;
|
||||
int shift;
|
||||
bool needAdd;
|
||||
|
||||
MagicNumber(uint32_t m, int s, bool add = false)
|
||||
: multiplier(m), shift(s), needAdd(add) {}
|
||||
};
|
||||
|
||||
// 全局强度削弱优化遍的核心逻辑封装类
|
||||
class GlobalStrengthReductionContext {
|
||||
public:
|
||||
// 构造函数,接受IRBuilder参数
|
||||
explicit GlobalStrengthReductionContext(IRBuilder* builder) : builder(builder) {}
|
||||
|
||||
// 运行优化的主要方法
|
||||
void run(Function* func, AnalysisManager* AM, bool& changed);
|
||||
|
||||
private:
|
||||
IRBuilder* builder; // IR构建器
|
||||
|
||||
// 分析结果
|
||||
SideEffectAnalysisResult* sideEffectAnalysis = nullptr;
|
||||
|
||||
// 优化计数
|
||||
int algebraicOptCount = 0;
|
||||
int strengthReductionCount = 0;
|
||||
int divisionOptCount = 0;
|
||||
|
||||
// 主要优化方法
|
||||
bool processBasicBlock(BasicBlock* bb);
|
||||
bool processInstruction(Instruction* inst);
|
||||
|
||||
// 代数优化方法
|
||||
bool tryAlgebraicOptimization(Instruction* inst);
|
||||
bool optimizeAddition(BinaryInst* inst);
|
||||
bool optimizeSubtraction(BinaryInst* inst);
|
||||
bool optimizeMultiplication(BinaryInst* inst);
|
||||
bool optimizeDivision(BinaryInst* inst);
|
||||
bool optimizeComparison(BinaryInst* inst);
|
||||
bool optimizeLogical(BinaryInst* inst);
|
||||
|
||||
// 强度削弱方法
|
||||
bool tryStrengthReduction(Instruction* inst);
|
||||
bool reduceMultiplication(BinaryInst* inst);
|
||||
bool reduceDivision(BinaryInst* inst);
|
||||
bool reducePower(CallInst* inst);
|
||||
|
||||
// 复杂乘法强度削弱方法
|
||||
bool tryComplexMultiplication(BinaryInst* inst, Value* variable, int constant);
|
||||
bool findOptimalShiftDecomposition(int constant, std::vector<int>& shifts);
|
||||
Value* createShiftDecomposition(BinaryInst* inst, Value* variable, const std::vector<int>& shifts);
|
||||
|
||||
// 魔数乘法相关方法
|
||||
MagicNumber computeMagicNumber(uint32_t divisor);
|
||||
std::pair<int, int> computeMulhMagicNumbers(int divisor);
|
||||
Value* createMagicDivision(BinaryInst* divInst, uint32_t divisor, const MagicNumber& magic);
|
||||
Value* createMagicDivisionLibdivide(BinaryInst* divInst, int divisor);
|
||||
bool isPowerOfTwo(uint32_t n);
|
||||
int log2OfPowerOfTwo(uint32_t n);
|
||||
|
||||
// 辅助方法
|
||||
bool isConstantInt(Value* val, int& constVal);
|
||||
bool isConstantInt(Value* val, uint32_t& constVal);
|
||||
ConstantInteger* getConstantInt(int val);
|
||||
bool hasOnlyLocalUses(Instruction* inst);
|
||||
void replaceWithOptimized(Instruction* original, Value* replacement);
|
||||
};
|
||||
|
||||
// 全局强度削弱优化遍类
|
||||
class GlobalStrengthReduction : public OptimizationPass {
|
||||
private:
|
||||
IRBuilder* builder; // IR构建器,用于创建新指令
|
||||
|
||||
public:
|
||||
// 静态成员,作为该遍的唯一ID
|
||||
static void* ID;
|
||||
|
||||
// 构造函数,接受IRBuilder参数
|
||||
explicit GlobalStrengthReduction(IRBuilder* builder)
|
||||
: OptimizationPass("GlobalStrengthReduction", Granularity::Function), builder(builder) {}
|
||||
|
||||
// 在函数上运行优化
|
||||
bool runOnFunction(Function* func, AnalysisManager& AM) override;
|
||||
|
||||
// 返回该遍的唯一ID
|
||||
void* getPassID() const override { return ID; }
|
||||
|
||||
// 声明分析依赖
|
||||
void getAnalysisUsage(std::set<void*>& analysisDependencies,
|
||||
std::set<void*>& analysisInvalidations) const override;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
252
src/include/midend/Pass/Optimize/InductionVariableElimination.h
Normal file
252
src/include/midend/Pass/Optimize/InductionVariableElimination.h
Normal file
@@ -0,0 +1,252 @@
|
||||
#pragma once
|
||||
|
||||
#include "Pass.h"
|
||||
#include "IR.h"
|
||||
#include "LoopCharacteristics.h"
|
||||
#include "Loop.h"
|
||||
#include "Dom.h"
|
||||
#include "SideEffectAnalysis.h"
|
||||
#include "AliasAnalysis.h"
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <memory>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 前向声明
|
||||
class LoopCharacteristicsResult;
|
||||
class LoopAnalysisResult;
|
||||
|
||||
/**
|
||||
* @brief 死归纳变量信息
|
||||
* 记录一个可以被消除的归纳变量
|
||||
*/
|
||||
struct DeadInductionVariable {
|
||||
PhiInst* phiInst; // phi 指令
|
||||
std::vector<Instruction*> relatedInsts; // 相关的递增/递减指令
|
||||
Loop* containingLoop; // 所在循环
|
||||
bool canEliminate; // 是否可以安全消除
|
||||
|
||||
DeadInductionVariable(PhiInst* phi, Loop* loop)
|
||||
: phiInst(phi), containingLoop(loop), canEliminate(false) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 归纳变量消除上下文类
|
||||
* 封装归纳变量消除优化的核心逻辑和状态
|
||||
*/
|
||||
class InductionVariableEliminationContext {
|
||||
public:
|
||||
InductionVariableEliminationContext() {}
|
||||
|
||||
/**
|
||||
* 运行归纳变量消除优化
|
||||
* @param F 目标函数
|
||||
* @param AM 分析管理器
|
||||
* @return 是否修改了IR
|
||||
*/
|
||||
bool run(Function* F, AnalysisManager& AM);
|
||||
|
||||
private:
|
||||
// 分析结果缓存
|
||||
LoopAnalysisResult* loopAnalysis = nullptr;
|
||||
LoopCharacteristicsResult* loopCharacteristics = nullptr;
|
||||
DominatorTree* dominatorTree = nullptr;
|
||||
SideEffectAnalysisResult* sideEffectAnalysis = nullptr;
|
||||
AliasAnalysisResult* aliasAnalysis = nullptr;
|
||||
|
||||
// 死归纳变量存储
|
||||
std::vector<std::unique_ptr<DeadInductionVariable>> deadIVs;
|
||||
std::unordered_map<Loop*, std::vector<DeadInductionVariable*>> loopToDeadIVs;
|
||||
|
||||
// ========== 核心分析和优化阶段 ==========
|
||||
|
||||
/**
|
||||
* 阶段1:识别死归纳变量
|
||||
* 找出没有被有效使用的归纳变量
|
||||
*/
|
||||
void identifyDeadInductionVariables(Function* F);
|
||||
|
||||
/**
|
||||
* 阶段2:分析消除的安全性
|
||||
* 确保消除操作不会破坏程序语义
|
||||
*/
|
||||
void analyzeSafetyForElimination();
|
||||
|
||||
/**
|
||||
* 阶段3:执行归纳变量消除
|
||||
* 删除死归纳变量及其相关指令
|
||||
*/
|
||||
bool performInductionVariableElimination();
|
||||
|
||||
// ========== 辅助方法 ==========
|
||||
|
||||
/**
|
||||
* 检查归纳变量是否为死归纳变量
|
||||
* @param iv 归纳变量信息
|
||||
* @param loop 所在循环
|
||||
* @return 如果是死归纳变量返回相关信息,否则返回nullptr
|
||||
*/
|
||||
std::unique_ptr<DeadInductionVariable>
|
||||
isDeadInductionVariable(const InductionVarInfo* iv, Loop* loop);
|
||||
|
||||
/**
|
||||
* 递归分析phi指令及其使用链是否都是死代码
|
||||
* @param phiInst phi指令
|
||||
* @param loop 所在循环
|
||||
* @return phi指令是否可以安全删除
|
||||
*/
|
||||
bool isPhiInstructionDeadRecursively(PhiInst* phiInst, Loop* loop);
|
||||
|
||||
/**
|
||||
* 递归分析指令的使用链是否都是死代码
|
||||
* @param inst 要分析的指令
|
||||
* @param loop 所在循环
|
||||
* @param visited 已访问的指令集合(避免无限递归)
|
||||
* @param currentPath 当前递归路径(检测循环依赖)
|
||||
* @return 指令的使用链是否都是死代码
|
||||
*/
|
||||
bool isInstructionUseChainDeadRecursively(Instruction* inst, Loop* loop,
|
||||
std::set<Instruction*>& visited,
|
||||
std::set<Instruction*>& currentPath);
|
||||
|
||||
/**
|
||||
* 检查循环是否有副作用
|
||||
* @param loop 要检查的循环
|
||||
* @return 循环是否有副作用
|
||||
*/
|
||||
bool loopHasSideEffects(Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查指令是否被用于循环退出条件
|
||||
* @param inst 要检查的指令
|
||||
* @param loop 所在循环
|
||||
* @return 是否被用于循环退出条件
|
||||
*/
|
||||
bool isUsedInLoopExitCondition(Instruction* inst, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查指令的结果是否未被有效使用
|
||||
* @param inst 要检查的指令
|
||||
* @param loop 所在循环
|
||||
* @return 指令结果是否未被有效使用
|
||||
*/
|
||||
bool isInstructionResultUnused(Instruction* inst, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查store指令是否存储到死地址(利用别名分析)
|
||||
* @param store store指令
|
||||
* @param loop 所在循环
|
||||
* @return 是否存储到死地址
|
||||
*/
|
||||
bool isStoreToDeadLocation(StoreInst* store, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查指令是否为死代码或只在循环内部使用
|
||||
* @param inst 要检查的指令
|
||||
* @param loop 所在循环
|
||||
* @return 是否为死代码或只在循环内部使用
|
||||
*/
|
||||
bool isInstructionDeadOrInternalOnly(Instruction* inst, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查指令是否有效地为死代码(带递归深度限制)
|
||||
* @param inst 要检查的指令
|
||||
* @param loop 所在循环
|
||||
* @param maxDepth 最大递归深度
|
||||
* @return 指令是否有效地为死代码
|
||||
*/
|
||||
bool isInstructionEffectivelyDead(Instruction* inst, Loop* loop, int maxDepth);
|
||||
|
||||
/**
|
||||
* 检查store指令是否有后续的load操作
|
||||
* @param store store指令
|
||||
* @param loop 所在循环
|
||||
* @return 是否有后续的load操作
|
||||
*/
|
||||
bool hasSubsequentLoad(StoreInst* store, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查指令是否在循环外有使用
|
||||
* @param inst 要检查的指令
|
||||
* @param loop 所在循环
|
||||
* @return 是否在循环外有使用
|
||||
*/
|
||||
bool hasUsageOutsideLoop(Instruction* inst, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查store指令是否在循环外有后续的load操作
|
||||
* @param store store指令
|
||||
* @param loop 所在循环
|
||||
* @return 是否在循环外有后续的load操作
|
||||
*/
|
||||
bool hasSubsequentLoadOutsideLoop(StoreInst* store, Loop* loop);
|
||||
|
||||
/**
|
||||
* 递归检查基本块子树中是否有对指定位置的load操作
|
||||
* @param bb 基本块
|
||||
* @param ptr 指针
|
||||
* @param visited 已访问的基本块集合
|
||||
* @return 是否有load操作
|
||||
*/
|
||||
bool hasLoadInSubtree(BasicBlock* bb, Value* ptr, std::set<BasicBlock*>& visited);
|
||||
|
||||
/**
|
||||
* 收集与归纳变量相关的所有指令
|
||||
* @param phiInst phi指令
|
||||
* @param loop 所在循环
|
||||
* @return 相关指令列表
|
||||
*/
|
||||
std::vector<Instruction*> collectRelatedInstructions(PhiInst* phiInst, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查消除归纳变量的安全性
|
||||
* @param deadIV 死归纳变量
|
||||
* @return 是否可以安全消除
|
||||
*/
|
||||
bool isSafeToEliminate(const DeadInductionVariable* deadIV);
|
||||
|
||||
/**
|
||||
* 消除单个死归纳变量
|
||||
* @param deadIV 死归纳变量
|
||||
* @return 是否成功消除
|
||||
*/
|
||||
bool eliminateDeadInductionVariable(DeadInductionVariable* deadIV);
|
||||
|
||||
/**
|
||||
* 打印调试信息
|
||||
*/
|
||||
void printDebugInfo();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 归纳变量消除优化遍
|
||||
* 消除循环中无用的归纳变量,减少寄存器压力
|
||||
*/
|
||||
class InductionVariableElimination : public OptimizationPass {
|
||||
public:
|
||||
// 唯一的 Pass ID
|
||||
static void *ID;
|
||||
|
||||
InductionVariableElimination()
|
||||
: OptimizationPass("InductionVariableElimination", Granularity::Function) {}
|
||||
|
||||
/**
|
||||
* 在函数上运行归纳变量消除优化
|
||||
* @param F 目标函数
|
||||
* @param AM 分析管理器
|
||||
* @return 是否修改了IR
|
||||
*/
|
||||
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
|
||||
40
src/include/midend/Pass/Optimize/LICM.h
Normal file
40
src/include/midend/Pass/Optimize/LICM.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
#include "Pass.h"
|
||||
#include "Loop.h"
|
||||
#include "LoopCharacteristics.h"
|
||||
#include "Dom.h"
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace sysy{
|
||||
|
||||
class LICMContext {
|
||||
public:
|
||||
LICMContext(Function* func, Loop* loop, IRBuilder* builder, const LoopCharacteristics* chars)
|
||||
: func(func), loop(loop), builder(builder), chars(chars) {}
|
||||
// 运行LICM主流程,返回IR是否被修改
|
||||
bool run();
|
||||
|
||||
private:
|
||||
Function* func;
|
||||
Loop* loop;
|
||||
IRBuilder* builder;
|
||||
const LoopCharacteristics* chars; // 特征分析结果
|
||||
|
||||
// 外提所有可提升指令
|
||||
bool hoistInstructions();
|
||||
};
|
||||
|
||||
|
||||
class LICM : public OptimizationPass{
|
||||
private:
|
||||
IRBuilder *builder; ///< IR构建器,用于插入指令
|
||||
public:
|
||||
static void *ID;
|
||||
LICM(IRBuilder *builder = nullptr) : OptimizationPass("LICM", Granularity::Function) , builder(builder) {}
|
||||
bool runOnFunction(Function *F, AnalysisManager &AM) override;
|
||||
void getAnalysisUsage(std::set<void *> &, std::set<void *> &) const override;
|
||||
void *getPassID() const override { return &ID; }
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
@@ -1,24 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Pass.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class LargeArrayToGlobalPass : public OptimizationPass {
|
||||
public:
|
||||
static void *ID;
|
||||
|
||||
LargeArrayToGlobalPass() : OptimizationPass("LargeArrayToGlobal", Granularity::Module) {}
|
||||
|
||||
bool runOnModule(Module *M, AnalysisManager &AM) override;
|
||||
void *getPassID() const override {
|
||||
return &ID;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned calculateTypeSize(Type *type);
|
||||
void convertAllocaToGlobal(AllocaInst *alloca, Function *F, Module *M);
|
||||
std::string generateUniqueGlobalName(AllocaInst *alloca, Function *F);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
155
src/include/midend/Pass/Optimize/LoopNormalization.h
Normal file
155
src/include/midend/Pass/Optimize/LoopNormalization.h
Normal file
@@ -0,0 +1,155 @@
|
||||
#pragma once
|
||||
|
||||
#include "Loop.h" // 循环分析依赖
|
||||
#include "Dom.h" // 支配树分析依赖
|
||||
#include "IR.h" // IR定义
|
||||
#include "IRBuilder.h" // IR构建器
|
||||
#include "Pass.h" // Pass框架
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
/**
|
||||
* @brief 循环规范化转换Pass
|
||||
*
|
||||
* 该Pass在循环不变量提升等优化前运行,主要负责:
|
||||
* 1. 为没有前置块(preheader)的循环创建前置块
|
||||
* 2. 确保循环结构符合后续优化的要求
|
||||
* 3. 规范化循环的控制流结构
|
||||
*
|
||||
* 前置块的作用:
|
||||
* - 为循环不变量提升提供插入位置
|
||||
* - 简化循环分析和优化
|
||||
* - 确保循环有唯一的入口点
|
||||
*/
|
||||
class LoopNormalizationPass : public OptimizationPass {
|
||||
public:
|
||||
// 唯一的 Pass ID
|
||||
static void *ID;
|
||||
|
||||
LoopNormalizationPass(IRBuilder* builder) : OptimizationPass("LoopNormalization", Pass::Granularity::Function), builder(builder) {}
|
||||
|
||||
// 实现 getPassID
|
||||
void *getPassID() const override { return &ID; }
|
||||
|
||||
// 核心运行方法
|
||||
bool runOnFunction(Function *F, AnalysisManager &AM) override;
|
||||
|
||||
// 声明分析依赖和失效信息
|
||||
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override;
|
||||
|
||||
private:
|
||||
// ========== IR构建器 ==========
|
||||
IRBuilder* builder; // IR构建器
|
||||
|
||||
// ========== 缓存的分析结果 ==========
|
||||
LoopAnalysisResult* loopAnalysis; // 循环结构分析结果
|
||||
DominatorTree* domTree; // 支配树分析结果
|
||||
|
||||
// ========== 规范化统计 ==========
|
||||
struct NormalizationStats {
|
||||
size_t totalLoops; // 总循环数
|
||||
size_t loopsNeedingPreheader; // 需要前置块的循环数
|
||||
size_t preheadersCreated; // 创建的前置块数
|
||||
size_t loopsNormalized; // 规范化的循环数
|
||||
size_t redundantPhisRemoved; // 删除的冗余PHI节点数
|
||||
|
||||
NormalizationStats() : totalLoops(0), loopsNeedingPreheader(0),
|
||||
preheadersCreated(0), loopsNormalized(0),
|
||||
redundantPhisRemoved(0) {}
|
||||
} stats;
|
||||
|
||||
// ========== 核心规范化方法 ==========
|
||||
|
||||
/**
|
||||
* 规范化单个循环
|
||||
* @param loop 要规范化的循环
|
||||
* @return 是否进行了修改
|
||||
*/
|
||||
bool normalizeLoop(Loop* loop);
|
||||
|
||||
/**
|
||||
* 为循环创建前置块
|
||||
* @param loop 需要前置块的循环
|
||||
* @return 创建的前置块,如果失败则返回nullptr
|
||||
*/
|
||||
BasicBlock* createPreheaderForLoop(Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查循环是否需要前置块(基于结构性需求)
|
||||
* @param loop 要检查的循环
|
||||
* @return true如果需要前置块
|
||||
*/
|
||||
bool needsPreheader(Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查循环是否已有合适的前置块
|
||||
* @param loop 要检查的循环
|
||||
* @return 现有的前置块,如果没有则返回nullptr
|
||||
*/
|
||||
BasicBlock* getExistingPreheader(Loop* loop);
|
||||
|
||||
/**
|
||||
* 更新支配树关系(在创建新块后)
|
||||
* @param newBlock 新创建的基本块
|
||||
* @param loop 相关的循环
|
||||
*/
|
||||
void updateDominatorRelations(BasicBlock* newBlock, Loop* loop);
|
||||
|
||||
/**
|
||||
* 重定向循环外的前驱块到新的前置块
|
||||
* @param loop 目标循环
|
||||
* @param preheader 新创建的前置块
|
||||
* @param header 循环头部
|
||||
*/
|
||||
void redirectExternalPredecessors(Loop* loop, BasicBlock* preheader, BasicBlock* header, const std::vector<BasicBlock*>& externalPreds);
|
||||
|
||||
/**
|
||||
* 为前置块生成合适的名称
|
||||
* @param loop 相关的循环
|
||||
* @return 生成的前置块名称
|
||||
*/
|
||||
std::string generatePreheaderName(Loop* loop);
|
||||
|
||||
/**
|
||||
* 验证规范化结果的正确性
|
||||
* @param loop 规范化后的循环
|
||||
* @return true如果规范化正确
|
||||
*/
|
||||
bool validateNormalization(Loop* loop);
|
||||
|
||||
// ========== 辅助方法 ==========
|
||||
|
||||
/**
|
||||
* 获取循环的外部前驱块(不在循环内的前驱)
|
||||
* @param loop 目标循环
|
||||
* @return 外部前驱块列表
|
||||
*/
|
||||
std::vector<BasicBlock*> getExternalPredecessors(Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查基本块是否适合作为前置块
|
||||
* @param block 候选基本块
|
||||
* @param loop 目标循环
|
||||
* @return true如果适合作为前置块
|
||||
*/
|
||||
bool isSuitableAsPreheader(BasicBlock* block, Loop* loop);
|
||||
|
||||
/**
|
||||
* 更新PHI节点以适应新的前置块
|
||||
* @param header 循环头部
|
||||
* @param preheader 新的前置块
|
||||
* @param oldPreds 原来的外部前驱
|
||||
*/
|
||||
void updatePhiNodesForPreheader(BasicBlock* header, BasicBlock* preheader,
|
||||
const std::vector<BasicBlock*>& oldPreds);
|
||||
|
||||
/**
|
||||
* 打印规范化统计信息
|
||||
*/
|
||||
void printStats(Function* F);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
233
src/include/midend/Pass/Optimize/LoopStrengthReduction.h
Normal file
233
src/include/midend/Pass/Optimize/LoopStrengthReduction.h
Normal file
@@ -0,0 +1,233 @@
|
||||
#pragma once
|
||||
|
||||
#include "Pass.h"
|
||||
#include "IR.h"
|
||||
#include "LoopCharacteristics.h"
|
||||
#include "Loop.h"
|
||||
#include "Dom.h"
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <memory>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 前向声明
|
||||
class LoopCharacteristicsResult;
|
||||
class LoopAnalysisResult;
|
||||
|
||||
/**
|
||||
* @brief 强度削弱候选项信息
|
||||
* 记录一个可以进行强度削弱的表达式信息
|
||||
*/
|
||||
struct StrengthReductionCandidate {
|
||||
enum OpType {
|
||||
MULTIPLY, // 乘法: iv * const
|
||||
DIVIDE, // 除法: iv / 2^n (转换为右移)
|
||||
DIVIDE_CONST, // 除法: iv / const (使用mulh指令优化)
|
||||
REMAINDER // 取模: iv % 2^n (转换为位与)
|
||||
};
|
||||
|
||||
enum DivisionStrategy {
|
||||
SIMPLE_SHIFT, // 简单右移(仅适用于无符号或非负数)
|
||||
SIGNED_CORRECTION, // 有符号除法修正: (x + (x >> 31) & mask) >> k
|
||||
MULH_OPTIMIZATION // 使用mulh指令优化任意常数除法
|
||||
};
|
||||
|
||||
Instruction* originalInst; // 原始指令 (如 i*4, i/8, i%16)
|
||||
Value* inductionVar; // 归纳变量 (如 i)
|
||||
OpType operationType; // 操作类型
|
||||
DivisionStrategy divStrategy; // 除法策略(仅用于除法)
|
||||
int multiplier; // 乘数/除数/模数 (如 4, 8, 16)
|
||||
int shiftAmount; // 位移量 (对于2的幂)
|
||||
int offset; // 偏移量 (如常数项)
|
||||
BasicBlock* containingBlock; // 所在基本块
|
||||
Loop* containingLoop; // 所在循环
|
||||
bool hasNegativeValues; // 归纳变量是否可能为负数
|
||||
|
||||
// 强度削弱后的新变量
|
||||
PhiInst* newPhi = nullptr; // 新的 phi 指令
|
||||
Value* newInductionVar = nullptr; // 新的归纳变量
|
||||
|
||||
StrengthReductionCandidate(Instruction* inst, Value* iv, OpType opType, int value, int off,
|
||||
BasicBlock* bb, Loop* loop)
|
||||
: originalInst(inst), inductionVar(iv), operationType(opType),
|
||||
divStrategy(SIMPLE_SHIFT), multiplier(value), offset(off),
|
||||
containingBlock(bb), containingLoop(loop), hasNegativeValues(false) {
|
||||
|
||||
// 计算位移量(用于除法和取模的强度削弱)
|
||||
if (opType == DIVIDE || opType == REMAINDER) {
|
||||
shiftAmount = 0;
|
||||
int temp = value;
|
||||
while (temp > 1) {
|
||||
temp >>= 1;
|
||||
shiftAmount++;
|
||||
}
|
||||
} else {
|
||||
shiftAmount = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 强度削弱上下文类
|
||||
* 封装强度削弱优化的核心逻辑和状态
|
||||
*/
|
||||
class StrengthReductionContext {
|
||||
public:
|
||||
StrengthReductionContext(IRBuilder* builder) : builder(builder) {}
|
||||
|
||||
/**
|
||||
* 运行强度削弱优化
|
||||
* @param F 目标函数
|
||||
* @param AM 分析管理器
|
||||
* @return 是否修改了IR
|
||||
*/
|
||||
bool run(Function* F, AnalysisManager& AM);
|
||||
|
||||
private:
|
||||
IRBuilder* builder;
|
||||
|
||||
// 分析结果缓存
|
||||
LoopAnalysisResult* loopAnalysis = nullptr;
|
||||
LoopCharacteristicsResult* loopCharacteristics = nullptr;
|
||||
DominatorTree* dominatorTree = nullptr;
|
||||
|
||||
// 候选项存储
|
||||
std::vector<std::unique_ptr<StrengthReductionCandidate>> candidates;
|
||||
std::unordered_map<Loop*, std::vector<StrengthReductionCandidate*>> loopToCandidates;
|
||||
|
||||
// ========== 核心分析和优化阶段 ==========
|
||||
|
||||
/**
|
||||
* 阶段1:识别强度削弱候选项
|
||||
* 扫描所有循环中的乘法指令,找出可以优化的模式
|
||||
*/
|
||||
void identifyStrengthReductionCandidates(Function* F);
|
||||
|
||||
/**
|
||||
* 阶段2:分析候选项的优化潜力
|
||||
* 评估每个候选项的收益,过滤掉不值得优化的情况
|
||||
*/
|
||||
void analyzeOptimizationPotential();
|
||||
|
||||
/**
|
||||
* 阶段3:执行强度削弱变换
|
||||
* 对选中的候选项执行实际的强度削弱优化
|
||||
*/
|
||||
bool performStrengthReduction();
|
||||
|
||||
// ========== 辅助分析函数 ==========
|
||||
|
||||
/**
|
||||
* 分析归纳变量是否可能取负值
|
||||
* @param ivInfo 归纳变量信息
|
||||
* @param loop 所属循环
|
||||
* @return 如果可能为负数返回true
|
||||
*/
|
||||
bool analyzeInductionVariableRange(const InductionVarInfo* ivInfo, Loop* loop) const;
|
||||
|
||||
/**
|
||||
* 生成除法替换代码
|
||||
* @param candidate 优化候选项
|
||||
* @param builder IR构建器
|
||||
* @return 替换值
|
||||
*/
|
||||
Value* generateDivisionReplacement(StrengthReductionCandidate* candidate, IRBuilder* builder) const;
|
||||
|
||||
/**
|
||||
* 生成任意常数除法替换代码
|
||||
* @param candidate 优化候选项
|
||||
* @param builder IR构建器
|
||||
* @return 替换值
|
||||
*/
|
||||
Value* generateConstantDivisionReplacement(StrengthReductionCandidate* candidate, IRBuilder* builder) const;
|
||||
|
||||
/**
|
||||
* 检查指令是否为强度削弱候选项
|
||||
* @param inst 要检查的指令
|
||||
* @param loop 所在循环
|
||||
* @return 如果是候选项返回候选项信息,否则返回nullptr
|
||||
*/
|
||||
std::unique_ptr<StrengthReductionCandidate>
|
||||
isStrengthReductionCandidate(Instruction* inst, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查值是否为循环的归纳变量
|
||||
* @param val 要检查的值
|
||||
* @param loop 循环
|
||||
* @param characteristics 循环特征信息
|
||||
* @return 如果是归纳变量返回归纳变量信息,否则返回nullptr
|
||||
*/
|
||||
const InductionVarInfo*
|
||||
getInductionVarInfo(Value* val, Loop* loop, const LoopCharacteristics* characteristics);
|
||||
|
||||
/**
|
||||
* 为候选项创建新的归纳变量
|
||||
* @param candidate 候选项
|
||||
* @return 是否成功创建
|
||||
*/
|
||||
bool createNewInductionVariable(StrengthReductionCandidate* candidate);
|
||||
|
||||
/**
|
||||
* 替换原始指令的所有使用
|
||||
* @param candidate 候选项
|
||||
* @return 是否成功替换
|
||||
*/
|
||||
bool replaceOriginalInstruction(StrengthReductionCandidate* candidate);
|
||||
|
||||
/**
|
||||
* 估算优化收益
|
||||
* 计算强度削弱后的性能提升
|
||||
* @param candidate 候选项
|
||||
* @return 估算的收益分数
|
||||
*/
|
||||
double estimateOptimizationBenefit(const StrengthReductionCandidate* candidate);
|
||||
|
||||
/**
|
||||
* 检查优化的合法性
|
||||
* @param candidate 候选项
|
||||
* @return 是否可以安全地进行优化
|
||||
*/
|
||||
bool isOptimizationLegal(const StrengthReductionCandidate* candidate);
|
||||
|
||||
/**
|
||||
* 打印调试信息
|
||||
*/
|
||||
void printDebugInfo();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 循环强度削弱优化遍
|
||||
* 将循环中的乘法运算转换为更高效的加法运算
|
||||
*/
|
||||
class LoopStrengthReduction : public OptimizationPass {
|
||||
public:
|
||||
// 唯一的 Pass ID
|
||||
static void *ID;
|
||||
|
||||
LoopStrengthReduction(IRBuilder* builder)
|
||||
: OptimizationPass("LoopStrengthReduction", Granularity::Function),
|
||||
builder(builder) {}
|
||||
|
||||
/**
|
||||
* 在函数上运行强度削弱优化
|
||||
* @param F 目标函数
|
||||
* @param AM 分析管理器
|
||||
* @return 是否修改了IR
|
||||
*/
|
||||
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; }
|
||||
|
||||
private:
|
||||
IRBuilder* builder;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
@@ -3,6 +3,8 @@
|
||||
#include "IR.h"
|
||||
#include "Pass.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include "AliasAnalysis.h"
|
||||
#include "SideEffectAnalysis.h"
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
@@ -63,6 +65,8 @@ struct SSAPValue {
|
||||
class SCCPContext {
|
||||
private:
|
||||
IRBuilder *builder; // IR 构建器,用于插入指令和创建常量
|
||||
AliasAnalysisResult *aliasAnalysis; // 别名分析结果
|
||||
SideEffectAnalysisResult *sideEffectAnalysis; // 副作用分析结果
|
||||
|
||||
// 工作列表
|
||||
// 存储需要重新评估的指令
|
||||
@@ -92,6 +96,14 @@ private:
|
||||
SSAPValue ComputeConstant(BinaryInst *binaryinst, SSAPValue lhsVal, SSAPValue rhsVal);
|
||||
// 辅助函数:对一元操作进行常量折叠
|
||||
SSAPValue ComputeConstant(UnaryInst *unaryInst, SSAPValue operandVal);
|
||||
// 辅助函数:检查是否为已知的纯函数
|
||||
bool isKnownPureFunction(const std::string &funcName) const;
|
||||
// 辅助函数:计算纯函数的常量结果
|
||||
SSAPValue computePureFunctionResult(CallInst *call, const std::vector<SSAPValue> &argValues);
|
||||
// 辅助函数:查找存储到指定位置的常量值
|
||||
SSAPValue findStoredConstantValue(Value *ptr, BasicBlock *currentBB);
|
||||
// 辅助函数:动态检查数组访问是否为常量索引(考虑SCCP状态)
|
||||
bool hasRuntimeConstantAccess(Value *ptr);
|
||||
|
||||
// 主要优化阶段
|
||||
// 阶段1: 常量传播与折叠
|
||||
@@ -117,7 +129,13 @@ private:
|
||||
void RemovePhiIncoming(BasicBlock *phiParentBB, BasicBlock *removedPred);
|
||||
|
||||
public:
|
||||
SCCPContext(IRBuilder *builder) : builder(builder) {}
|
||||
SCCPContext(IRBuilder *builder) : builder(builder), aliasAnalysis(nullptr), sideEffectAnalysis(nullptr) {}
|
||||
|
||||
// 设置别名分析结果
|
||||
void setAliasAnalysis(AliasAnalysisResult *aa) { aliasAnalysis = aa; }
|
||||
|
||||
// 设置副作用分析结果
|
||||
void setSideEffectAnalysis(SideEffectAnalysisResult *sea) { sideEffectAnalysis = sea; }
|
||||
|
||||
// 运行 SCCP 优化
|
||||
void run(Function *func, AnalysisManager &AM);
|
||||
|
||||
@@ -107,6 +107,190 @@ public:
|
||||
// 所以当AllocaInst的basetype是PointerType时(一维数组)或者是指向ArrayType的PointerType(多位数组)时,返回true
|
||||
return aval && (baseType->isPointer() || baseType->as<PointerType>()->getBaseType()->isArray());
|
||||
}
|
||||
|
||||
|
||||
//该实现参考了libdivide的算法
|
||||
static std::pair<int, int> computeMulhMagicNumbers(int divisor) {
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "\n[SR] ===== Computing magic numbers for divisor " << divisor << " (libdivide algorithm) =====" << std::endl;
|
||||
}
|
||||
|
||||
if (divisor == 0) {
|
||||
if (DEBUG) std::cout << "[SR] Error: divisor must be != 0" << std::endl;
|
||||
return {-1, -1};
|
||||
}
|
||||
|
||||
// libdivide 常数
|
||||
const uint8_t LIBDIVIDE_ADD_MARKER = 0x40;
|
||||
const uint8_t LIBDIVIDE_NEGATIVE_DIVISOR = 0x80;
|
||||
|
||||
// 辅助函数:计算前导零个数
|
||||
auto count_leading_zeros32 = [](uint32_t val) -> uint32_t {
|
||||
if (val == 0) return 32;
|
||||
return __builtin_clz(val);
|
||||
};
|
||||
|
||||
// 辅助函数:64位除法返回32位商和余数
|
||||
auto div_64_32 = [](uint32_t high, uint32_t low, uint32_t divisor, uint32_t* rem) -> uint32_t {
|
||||
uint64_t dividend = ((uint64_t)high << 32) | low;
|
||||
uint32_t quotient = dividend / divisor;
|
||||
*rem = dividend % divisor;
|
||||
return quotient;
|
||||
};
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Input divisor: " << divisor << std::endl;
|
||||
}
|
||||
|
||||
// libdivide_internal_s32_gen 算法实现
|
||||
int32_t d = divisor;
|
||||
uint32_t ud = (uint32_t)d;
|
||||
uint32_t absD = (d < 0) ? -ud : ud;
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] absD = " << absD << std::endl;
|
||||
}
|
||||
|
||||
uint32_t floor_log_2_d = 31 - count_leading_zeros32(absD);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] floor_log_2_d = " << floor_log_2_d << std::endl;
|
||||
}
|
||||
|
||||
// 检查 absD 是否为2的幂
|
||||
if ((absD & (absD - 1)) == 0) {
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] " << absD << " 是2的幂,使用移位方法" << std::endl;
|
||||
}
|
||||
|
||||
// 对于2的幂,我们只使用移位,不需要魔数
|
||||
int shift = floor_log_2_d;
|
||||
if (d < 0) shift |= 0x80; // 标记负数
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Power of 2 result: magic=0, shift=" << shift << std::endl;
|
||||
std::cout << "[SR] ===== End magic computation =====" << std::endl;
|
||||
}
|
||||
|
||||
// 对于我们的目的,我们将在IR生成中以不同方式处理2的幂
|
||||
// 返回特殊标记
|
||||
return {0, shift};
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] " << absD << " is not a power of 2, computing magic number" << std::endl;
|
||||
}
|
||||
|
||||
// 非2的幂除数的魔数计算
|
||||
uint8_t more;
|
||||
uint32_t rem, proposed_m;
|
||||
|
||||
// 计算 proposed_m = floor(2^(floor_log_2_d + 31) / absD)
|
||||
proposed_m = div_64_32((uint32_t)1 << (floor_log_2_d - 1), 0, absD, &rem);
|
||||
const uint32_t e = absD - rem;
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] proposed_m = " << proposed_m << ", rem = " << rem << ", e = " << e << std::endl;
|
||||
}
|
||||
|
||||
// 确定是否需要"加法"版本
|
||||
const bool branchfree = false; // 使用分支版本
|
||||
|
||||
if (!branchfree && e < ((uint32_t)1 << floor_log_2_d)) {
|
||||
// 这个幂次有效
|
||||
more = (uint8_t)(floor_log_2_d - 1);
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Using basic algorithm, shift = " << (int)more << std::endl;
|
||||
}
|
||||
} else {
|
||||
// 我们需要上升一个等级
|
||||
proposed_m += proposed_m;
|
||||
const uint32_t twice_rem = rem + rem;
|
||||
if (twice_rem >= absD || twice_rem < rem) {
|
||||
proposed_m += 1;
|
||||
}
|
||||
more = (uint8_t)(floor_log_2_d | LIBDIVIDE_ADD_MARKER);
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Using add algorithm, proposed_m = " << proposed_m << ", more = " << (int)more << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
proposed_m += 1;
|
||||
int32_t magic = (int32_t)proposed_m;
|
||||
|
||||
// 处理负除数
|
||||
if (d < 0) {
|
||||
more |= LIBDIVIDE_NEGATIVE_DIVISOR;
|
||||
if (!branchfree) {
|
||||
magic = -magic;
|
||||
}
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Negative divisor, magic = " << magic << ", more = " << (int)more << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 为我们的IR生成提取移位量和标志
|
||||
int shift = more & 0x3F; // 移除标志,保留移位量(位0-5)
|
||||
bool need_add = (more & LIBDIVIDE_ADD_MARKER) != 0;
|
||||
bool is_negative = (more & LIBDIVIDE_NEGATIVE_DIVISOR) != 0;
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Final result: magic = " << magic << ", more = " << (int)more
|
||||
<< " (0x" << std::hex << (int)more << std::dec << ")" << std::endl;
|
||||
std::cout << "[SR] Shift = " << shift << ", need_add = " << need_add
|
||||
<< ", is_negative = " << is_negative << std::endl;
|
||||
|
||||
// Test the magic number using the correct libdivide algorithm
|
||||
std::cout << "[SR] Testing magic number (libdivide algorithm):" << std::endl;
|
||||
int test_values[] = {1, 7, 37, 100, 999, -1, -7, -37, -100};
|
||||
|
||||
for (int test_val : test_values) {
|
||||
int64_t quotient;
|
||||
|
||||
// 实现正确的libdivide算法
|
||||
int64_t product = (int64_t)test_val * magic;
|
||||
int64_t high_bits = product >> 32;
|
||||
|
||||
if (need_add) {
|
||||
// ADD_MARKER情况:移位前加上被除数
|
||||
// 这是libdivide的关键洞察!
|
||||
high_bits += test_val;
|
||||
quotient = high_bits >> shift;
|
||||
} else {
|
||||
// 正常情况:只是移位
|
||||
quotient = high_bits >> shift;
|
||||
}
|
||||
|
||||
// 符号修正:这是libdivide有符号除法的关键部分!
|
||||
// 如果被除数为负,商需要加1来匹配C语言的截断除法语义
|
||||
if (test_val < 0) {
|
||||
quotient += 1;
|
||||
}
|
||||
|
||||
int expected = test_val / divisor;
|
||||
|
||||
bool correct = (quotient == expected);
|
||||
std::cout << "[SR] " << test_val << " / " << divisor << " = " << quotient
|
||||
<< " (expected " << expected << ") " << (correct ? "✓" : "✗") << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "[SR] ===== End magic computation =====" << std::endl;
|
||||
}
|
||||
|
||||
// 返回魔数、移位量,并在移位中编码ADD_MARKER标志
|
||||
// 我们将使用移位的第6位表示ADD_MARKER,第7位表示负数(如果需要)
|
||||
int encoded_shift = shift;
|
||||
if (need_add) {
|
||||
encoded_shift |= 0x40; // 设置第6位表示ADD_MARKER
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Encoding ADD_MARKER in shift: " << encoded_shift << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return {magic, encoded_shift};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}// namespace sysy
|
||||
39
src/include/midend/Pass/Optimize/TailCallOpt.h
Normal file
39
src/include/midend/Pass/Optimize/TailCallOpt.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "Pass.h"
|
||||
#include "Dom.h"
|
||||
#include "Loop.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
/**
|
||||
* @class TailCallOpt
|
||||
* @brief 优化尾调用的中端优化通道。
|
||||
*
|
||||
* 该类实现了一个针对函数级别的尾调用优化的优化通道(OptimizationPass)。
|
||||
* 通过分析和转换 IR(中间表示),将可优化的尾调用转换为更高效的形式,
|
||||
* 以减少函数调用的开销,提升程序性能。
|
||||
*
|
||||
* @note 需要传入 IRBuilder 指针用于 IR 构建和修改。
|
||||
*
|
||||
* @method runOnFunction
|
||||
* 对指定函数进行尾调用优化。
|
||||
*
|
||||
* @method getPassID
|
||||
* 获取当前优化通道的唯一标识符。
|
||||
*
|
||||
* @method getAnalysisUsage
|
||||
* 指定该优化通道所依赖和失效的分析集合。
|
||||
*/
|
||||
class TailCallOpt : public OptimizationPass {
|
||||
private:
|
||||
IRBuilder* builder;
|
||||
public:
|
||||
TailCallOpt(IRBuilder* builder) : OptimizationPass("TailCallOpt", Granularity::Function), builder(builder) {}
|
||||
static void *ID;
|
||||
bool runOnFunction(Function *F, AnalysisManager &AM) override;
|
||||
void *getPassID() const override { return &ID; }
|
||||
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
@@ -151,17 +151,21 @@ public:
|
||||
}
|
||||
AnalysisPass *analysisPass = static_cast<AnalysisPass *>(basePass.get());
|
||||
|
||||
if(DEBUG){
|
||||
std::cout << "Running Analysis Pass: " << analysisPass->getName() << "\n";
|
||||
}
|
||||
// 根据分析遍的粒度处理
|
||||
switch (analysisPass->getGranularity()) {
|
||||
case Pass::Granularity::Module: {
|
||||
// 检查是否已存在有效结果
|
||||
auto it = moduleCachedResults.find(analysisID);
|
||||
if (it != moduleCachedResults.end()) {
|
||||
if(DEBUG) {
|
||||
std::cout << "Using cached result for Analysis Pass: " << analysisPass->getName() << "\n";
|
||||
}
|
||||
return static_cast<T *>(it->second.get()); // 返回缓存结果
|
||||
}
|
||||
// 只有在实际运行时才打印调试信息
|
||||
if(DEBUG){
|
||||
std::cout << "Running Analysis Pass: " << analysisPass->getName() << "\n";
|
||||
}
|
||||
// 运行模块级分析遍
|
||||
if (!pModuleRef) {
|
||||
std::cerr << "Error: Module reference not set for AnalysisManager to run Module Pass.\n";
|
||||
@@ -183,8 +187,16 @@ public:
|
||||
// 检查是否已存在有效结果
|
||||
auto it = functionCachedResults.find({F, analysisID});
|
||||
if (it != functionCachedResults.end()) {
|
||||
if(DEBUG) {
|
||||
std::cout << "Using cached result for Analysis Pass: " << analysisPass->getName() << " (Function: " << F->getName() << ")\n";
|
||||
}
|
||||
return static_cast<T *>(it->second.get()); // 返回缓存结果
|
||||
}
|
||||
// 只有在实际运行时才打印调试信息
|
||||
if(DEBUG){
|
||||
std::cout << "Running Analysis Pass: " << analysisPass->getName() << "\n";
|
||||
std::cout << "Function: " << F->getName() << "\n";
|
||||
}
|
||||
// 运行函数级分析遍
|
||||
analysisPass->runOnFunction(F, *this);
|
||||
// 获取结果并缓存
|
||||
@@ -202,8 +214,16 @@ public:
|
||||
// 检查是否已存在有效结果
|
||||
auto it = basicBlockCachedResults.find({BB, analysisID});
|
||||
if (it != basicBlockCachedResults.end()) {
|
||||
if(DEBUG) {
|
||||
std::cout << "Using cached result for Analysis Pass: " << analysisPass->getName() << " (BasicBlock: " << BB->getName() << ")\n";
|
||||
}
|
||||
return static_cast<T *>(it->second.get()); // 返回缓存结果
|
||||
}
|
||||
// 只有在实际运行时才打印调试信息
|
||||
if(DEBUG){
|
||||
std::cout << "Running Analysis Pass: " << analysisPass->getName() << "\n";
|
||||
std::cout << "BasicBlock: " << BB->getName() << "\n";
|
||||
}
|
||||
// 运行基本块级分析遍
|
||||
analysisPass->runOnBasicBlock(BB, *this);
|
||||
// 获取结果并缓存
|
||||
|
||||
@@ -51,6 +51,7 @@ public:
|
||||
Module *pModule, IRBuilder *pBuilder);
|
||||
|
||||
static void initExternalFunction(Module *pModule, IRBuilder *pBuilder);
|
||||
static void modify_timefuncname(Module *pModule);
|
||||
};
|
||||
|
||||
class SysYIRGenerator : public SysYBaseVisitor {
|
||||
|
||||
@@ -6,13 +6,25 @@ add_library(midend_lib STATIC
|
||||
Pass/Pass.cpp
|
||||
Pass/Analysis/Dom.cpp
|
||||
Pass/Analysis/Liveness.cpp
|
||||
Pass/Analysis/Loop.cpp
|
||||
Pass/Analysis/LoopCharacteristics.cpp
|
||||
Pass/Analysis/LoopVectorization.cpp
|
||||
Pass/Analysis/AliasAnalysis.cpp
|
||||
Pass/Analysis/SideEffectAnalysis.cpp
|
||||
Pass/Analysis/CallGraphAnalysis.cpp
|
||||
Pass/Optimize/DCE.cpp
|
||||
Pass/Optimize/Mem2Reg.cpp
|
||||
Pass/Optimize/Reg2Mem.cpp
|
||||
Pass/Optimize/GVN.cpp
|
||||
Pass/Optimize/SysYIRCFGOpt.cpp
|
||||
Pass/Optimize/SCCP.cpp
|
||||
Pass/Optimize/LoopNormalization.cpp
|
||||
Pass/Optimize/LICM.cpp
|
||||
Pass/Optimize/LoopStrengthReduction.cpp
|
||||
Pass/Optimize/InductionVariableElimination.cpp
|
||||
Pass/Optimize/GlobalStrengthReduction.cpp
|
||||
Pass/Optimize/BuildCFG.cpp
|
||||
Pass/Optimize/LargeArrayToGlobal.cpp
|
||||
Pass/Optimize/TailCallOpt.cpp
|
||||
)
|
||||
|
||||
# 包含中端模块所需的头文件路径
|
||||
|
||||
@@ -762,7 +762,7 @@ void BinaryInst::print(std::ostream &os) const {
|
||||
printOperand(os, getLhs());
|
||||
os << ", ";
|
||||
printOperand(os, getRhs());
|
||||
os << "\n ";
|
||||
os << "\n ";
|
||||
printVarName(os, this) << " = zext i1 %" << tmpName << " to i32";
|
||||
} else if (kind == kFCmpEQ || kind == kFCmpNE || kind == kFCmpLT ||
|
||||
kind == kFCmpGT || kind == kFCmpLE || kind == kFCmpGE) {
|
||||
@@ -777,9 +777,31 @@ void BinaryInst::print(std::ostream &os) const {
|
||||
printOperand(os, getLhs());
|
||||
os << ", ";
|
||||
printOperand(os, getRhs());
|
||||
os << "\n ";
|
||||
os << "\n ";
|
||||
printVarName(os, this) << " = zext i1 %" << tmpName << " to i32";
|
||||
} else {
|
||||
} else if(kind == kMulh){
|
||||
// 模拟高位乘法:先扩展为i64,乘法,右移32位,截断为i32
|
||||
static int mulhCount = 0;
|
||||
mulhCount++;
|
||||
std::string lhsName = getLhs()->getName();
|
||||
std::string rhsName = getRhs()->getName();
|
||||
std::string tmpLhs = "tmp_mulh_lhs_" + std::to_string(mulhCount) + "_" + lhsName;
|
||||
std::string tmpRhs = "tmp_mulh_rhs_" + std::to_string(mulhCount) + rhsName;
|
||||
std::string tmpMul = "tmp_mulh_mul_" + std::to_string(mulhCount) + getName();
|
||||
std::string tmpHigh = "tmp_mulh_high_" + std::to_string(mulhCount) + getName();
|
||||
// printVarName(os, this) << " = "; // 输出最终变量名
|
||||
|
||||
// os << "; mulh emulation\n ";
|
||||
os << "%" << tmpLhs << " = sext i32 ";
|
||||
printOperand(os, getLhs());
|
||||
os << " to i64\n ";
|
||||
os << "%" << tmpRhs << " = sext i32 ";
|
||||
printOperand(os, getRhs());
|
||||
os << " to i64\n ";
|
||||
os << "%" << tmpMul << " = mul i64 %" << tmpLhs << ", %" << tmpRhs << "\n ";
|
||||
os << "%" << tmpHigh << " = ashr i64 %" << tmpMul << ", 32\n ";
|
||||
printVarName(os, this) << " = trunc i64 %" << tmpHigh << " to i32";
|
||||
}else {
|
||||
// 算术和逻辑指令
|
||||
printVarName(os, this) << " = ";
|
||||
os << getKindString() << " " << *getType() << " ";
|
||||
@@ -825,7 +847,7 @@ void CondBrInst::print(std::ostream &os) const {
|
||||
|
||||
os << "%tmp_cond_" << condName << "_" << uniqueSuffix << " = icmp ne i32 ";
|
||||
printOperand(os, condition);
|
||||
os << ", 0\n br i1 %tmp_cond_" << condName << "_" << uniqueSuffix;
|
||||
os << ", 0\n br i1 %tmp_cond_" << condName << "_" << uniqueSuffix;
|
||||
|
||||
os << ", label %";
|
||||
printBlockName(os, getThenBlock());
|
||||
@@ -864,7 +886,7 @@ void MemsetInst::print(std::ostream &os) const {
|
||||
// This is done at print time to avoid modifying the IR structure
|
||||
os << "%tmp_bitcast_" << ptr->getName() << " = bitcast " << *ptr->getType() << " ";
|
||||
printOperand(os, ptr);
|
||||
os << " to i8*\n ";
|
||||
os << " to i8*\n ";
|
||||
|
||||
// Now call memset with the bitcast result
|
||||
os << "call void @llvm.memset.p0i8.i32(i8* %tmp_bitcast_" << ptr->getName() << ", i8 ";
|
||||
|
||||
559
src/midend/Pass/Analysis/AliasAnalysis.cpp
Normal file
559
src/midend/Pass/Analysis/AliasAnalysis.cpp
Normal file
@@ -0,0 +1,559 @@
|
||||
#include "AliasAnalysis.h"
|
||||
#include "SysYIRPrinter.h"
|
||||
#include <iostream>
|
||||
|
||||
extern int DEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 静态成员初始化
|
||||
void *SysYAliasAnalysisPass::ID = (void *)&SysYAliasAnalysisPass::ID;
|
||||
|
||||
// ========== AliasAnalysisResult 实现 ==========
|
||||
|
||||
void AliasAnalysisResult::print() const {
|
||||
std::cout << "---- Alias Analysis Results for Function: " << AssociatedFunction->getName() << " ----\n";
|
||||
|
||||
// 打印内存位置信息
|
||||
std::cout << " Memory Locations (" << LocationMap.size() << "):\n";
|
||||
for (const auto& pair : LocationMap) {
|
||||
const auto& loc = pair.second;
|
||||
std::cout << " - Base: " << loc->basePointer->getName();
|
||||
std::cout << " (Type: ";
|
||||
if (loc->isLocalArray) std::cout << "Local";
|
||||
else if (loc->isFunctionParameter) std::cout << "Parameter";
|
||||
else if (loc->isGlobalArray) std::cout << "Global";
|
||||
else std::cout << "Unknown";
|
||||
std::cout << ")\n";
|
||||
}
|
||||
|
||||
// 打印别名关系
|
||||
std::cout << " Alias Relations (" << AliasMap.size() << "):\n";
|
||||
for (const auto& pair : AliasMap) {
|
||||
std::cout << " - (" << pair.first.first->getName() << ", " << pair.first.second->getName() << "): ";
|
||||
switch (pair.second) {
|
||||
case AliasType::NO_ALIAS: std::cout << "No Alias"; break;
|
||||
case AliasType::SELF_ALIAS: std::cout << "Self Alias"; break;
|
||||
case AliasType::POSSIBLE_ALIAS: std::cout << "Possible Alias"; break;
|
||||
case AliasType::UNKNOWN_ALIAS: std::cout << "Unknown Alias"; break;
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
std::cout << "-----------------------------------------------------------\n";
|
||||
}
|
||||
|
||||
AliasType AliasAnalysisResult::queryAlias(Value* ptr1, Value* ptr2) const {
|
||||
auto key = std::make_pair(ptr1, ptr2);
|
||||
auto it = AliasMap.find(key);
|
||||
if (it != AliasMap.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// 尝试反向查找
|
||||
key = std::make_pair(ptr2, ptr1);
|
||||
it = AliasMap.find(key);
|
||||
if (it != AliasMap.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return AliasType::UNKNOWN_ALIAS; // 保守估计
|
||||
}
|
||||
|
||||
const MemoryLocation* AliasAnalysisResult::getMemoryLocation(Value* ptr) const {
|
||||
auto it = LocationMap.find(ptr);
|
||||
return (it != LocationMap.end()) ? it->second.get() : nullptr;
|
||||
}
|
||||
|
||||
bool AliasAnalysisResult::isLocalArray(Value* ptr) const {
|
||||
const MemoryLocation* loc = getMemoryLocation(ptr);
|
||||
return loc && loc->isLocalArray;
|
||||
}
|
||||
|
||||
bool AliasAnalysisResult::isFunctionParameter(Value* ptr) const {
|
||||
const MemoryLocation* loc = getMemoryLocation(ptr);
|
||||
return loc && loc->isFunctionParameter;
|
||||
}
|
||||
|
||||
bool AliasAnalysisResult::isGlobalArray(Value* ptr) const {
|
||||
const MemoryLocation* loc = getMemoryLocation(ptr);
|
||||
return loc && loc->isGlobalArray;
|
||||
}
|
||||
|
||||
bool AliasAnalysisResult::hasConstantAccess(Value* ptr) const {
|
||||
const MemoryLocation* loc = getMemoryLocation(ptr);
|
||||
return loc && loc->hasConstantIndices;
|
||||
}
|
||||
|
||||
AliasAnalysisResult::Statistics AliasAnalysisResult::getStatistics() const {
|
||||
Statistics stats = {0};
|
||||
|
||||
stats.totalQueries = AliasMap.size();
|
||||
|
||||
for (auto& pair : AliasMap) {
|
||||
switch (pair.second) {
|
||||
case AliasType::NO_ALIAS: stats.noAlias++; break;
|
||||
case AliasType::SELF_ALIAS: stats.selfAlias++; break;
|
||||
case AliasType::POSSIBLE_ALIAS: stats.possibleAlias++; break;
|
||||
case AliasType::UNKNOWN_ALIAS: stats.unknownAlias++; break;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& loc : LocationMap) {
|
||||
if (loc.second->isLocalArray) stats.localArrays++;
|
||||
if (loc.second->isFunctionParameter) stats.functionParameters++;
|
||||
if (loc.second->isGlobalArray) stats.globalArrays++;
|
||||
if (loc.second->hasConstantIndices) stats.constantAccesses++;
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
void AliasAnalysisResult::printStatics() const {
|
||||
std::cout << "=== Alias Analysis Results ===" << std::endl;
|
||||
|
||||
auto stats = getStatistics();
|
||||
std::cout << "Total queries: " << stats.totalQueries << std::endl;
|
||||
std::cout << "No alias: " << stats.noAlias << std::endl;
|
||||
std::cout << "Self alias: " << stats.selfAlias << std::endl;
|
||||
std::cout << "Possible alias: " << stats.possibleAlias << std::endl;
|
||||
std::cout << "Unknown alias: " << stats.unknownAlias << std::endl;
|
||||
std::cout << "Local arrays: " << stats.localArrays << std::endl;
|
||||
std::cout << "Function parameters: " << stats.functionParameters << std::endl;
|
||||
std::cout << "Global arrays: " << stats.globalArrays << std::endl;
|
||||
std::cout << "Constant accesses: " << stats.constantAccesses << std::endl;
|
||||
}
|
||||
|
||||
void AliasAnalysisResult::addMemoryLocation(std::unique_ptr<MemoryLocation> location) {
|
||||
Value* ptr = location->accessPointer;
|
||||
LocationMap[ptr] = std::move(location);
|
||||
}
|
||||
|
||||
void AliasAnalysisResult::addAliasRelation(Value* ptr1, Value* ptr2, AliasType type) {
|
||||
auto key = std::make_pair(ptr1, ptr2);
|
||||
AliasMap[key] = type;
|
||||
}
|
||||
|
||||
// ========== SysYAliasAnalysisPass 实现 ==========
|
||||
|
||||
bool SysYAliasAnalysisPass::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
if (DEBUG) {
|
||||
std::cout << "Running SysY Alias Analysis on function: " << F->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 创建分析结果
|
||||
CurrentResult = std::make_unique<AliasAnalysisResult>(F);
|
||||
|
||||
// 执行主要分析步骤
|
||||
collectMemoryAccesses(F);
|
||||
buildAliasRelations(F);
|
||||
optimizeForSysY(F);
|
||||
|
||||
if (DEBUG) {
|
||||
CurrentResult->print();
|
||||
CurrentResult->printStatics();
|
||||
}
|
||||
|
||||
return false; // 分析遍不修改IR
|
||||
}
|
||||
|
||||
void SysYAliasAnalysisPass::collectMemoryAccesses(Function* F) {
|
||||
// 收集函数中所有内存访问指令
|
||||
for (auto& bb : F->getBasicBlocks()) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
Value* ptr = nullptr;
|
||||
|
||||
if (auto* loadInst = dynamic_cast<LoadInst*>(inst.get())) {
|
||||
ptr = loadInst->getPointer();
|
||||
} else if (auto* storeInst = dynamic_cast<StoreInst*>(inst.get())) {
|
||||
ptr = storeInst->getPointer();
|
||||
}
|
||||
|
||||
if (ptr) {
|
||||
// 创建内存位置信息
|
||||
auto location = createMemoryLocation(ptr);
|
||||
location->accessInsts.push_back(inst.get());
|
||||
|
||||
// 更新读写标记
|
||||
if (dynamic_cast<LoadInst*>(inst.get())) {
|
||||
location->hasReads = true;
|
||||
} else {
|
||||
location->hasWrites = true;
|
||||
}
|
||||
|
||||
CurrentResult->addMemoryLocation(std::move(location));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SysYAliasAnalysisPass::buildAliasRelations(Function *F) {
|
||||
// 构建所有内存访问之间的别名关系
|
||||
auto& locationMap = CurrentResult->LocationMap;
|
||||
|
||||
std::vector<Value*> allPointers;
|
||||
for (auto& pair : locationMap) {
|
||||
allPointers.push_back(pair.first);
|
||||
}
|
||||
|
||||
// 两两比较所有指针
|
||||
for (size_t i = 0; i < allPointers.size(); ++i) {
|
||||
for (size_t j = i + 1; j < allPointers.size(); ++j) {
|
||||
Value* ptr1 = allPointers[i];
|
||||
Value* ptr2 = allPointers[j];
|
||||
|
||||
MemoryLocation* loc1 = locationMap[ptr1].get();
|
||||
MemoryLocation* loc2 = locationMap[ptr2].get();
|
||||
|
||||
AliasType aliasType = analyzeAliasBetween(loc1, loc2);
|
||||
CurrentResult->addAliasRelation(ptr1, ptr2, aliasType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SysYAliasAnalysisPass::optimizeForSysY(Function* F) {
|
||||
// SysY特化优化
|
||||
applySysYConstraints(F);
|
||||
optimizeParameterAnalysis(F);
|
||||
optimizeArrayAccessAnalysis(F);
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryLocation> SysYAliasAnalysisPass::createMemoryLocation(Value* ptr) {
|
||||
Value* basePtr = getBasePointer(ptr);
|
||||
auto location = std::make_unique<MemoryLocation>(basePtr, ptr);
|
||||
|
||||
// 分析内存类型和索引模式
|
||||
analyzeMemoryType(location.get());
|
||||
analyzeIndexPattern(location.get());
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
Value* SysYAliasAnalysisPass::getBasePointer(Value* ptr) {
|
||||
// 递归剥离GEP指令,找到真正的基指针
|
||||
if (auto* gepInst = dynamic_cast<GetElementPtrInst*>(ptr)) {
|
||||
return getBasePointer(gepInst->getBasePointer());
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void SysYAliasAnalysisPass::analyzeMemoryType(MemoryLocation* location) {
|
||||
Value* base = location->basePointer;
|
||||
|
||||
// 检查内存类型
|
||||
if (dynamic_cast<AllocaInst*>(base)) {
|
||||
location->isLocalArray = true;
|
||||
} else if (dynamic_cast<Argument*>(base)) {
|
||||
location->isFunctionParameter = true;
|
||||
} else if (dynamic_cast<GlobalValue*>(base)) {
|
||||
location->isGlobalArray = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SysYAliasAnalysisPass::analyzeIndexPattern(MemoryLocation* location) {
|
||||
// 分析GEP指令的索引模式
|
||||
if (auto* gepInst = dynamic_cast<GetElementPtrInst*>(location->accessPointer)) {
|
||||
// 初始化为true,如果发现非常量索引则设为false
|
||||
location->hasConstantIndices = true;
|
||||
|
||||
// 收集所有索引
|
||||
for (unsigned i = 0; i < gepInst->getNumIndices(); ++i) {
|
||||
Value* index = gepInst->getIndex(i);
|
||||
location->indices.push_back(index);
|
||||
|
||||
// 检查是否为常量索引
|
||||
if (!isConstantValue(index)) {
|
||||
location->hasConstantIndices = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否包含循环变量
|
||||
Function* containingFunc = nullptr;
|
||||
if (auto* inst = dynamic_cast<Instruction*>(location->basePointer)) {
|
||||
containingFunc = inst->getParent()->getParent();
|
||||
} else if (auto* arg = dynamic_cast<Argument*>(location->basePointer)) {
|
||||
containingFunc = arg->getParent();
|
||||
}
|
||||
|
||||
if (containingFunc) {
|
||||
location->hasLoopVariableIndex = hasLoopVariableInIndices(location->indices, containingFunc);
|
||||
}
|
||||
|
||||
// 计算常量偏移
|
||||
if (location->hasConstantIndices) {
|
||||
location->constantOffset = calculateConstantOffset(location->indices);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AliasType SysYAliasAnalysisPass::analyzeAliasBetween(MemoryLocation* loc1, MemoryLocation* loc2) {
|
||||
// 分析两个内存位置之间的别名关系
|
||||
|
||||
// 1. 相同基指针的情况需要进一步分析索引
|
||||
if (loc1->basePointer == loc2->basePointer) {
|
||||
// 如果是同一个访问指针,那就是完全相同的内存位置
|
||||
if (loc1->accessPointer == loc2->accessPointer) {
|
||||
return AliasType::SELF_ALIAS;
|
||||
}
|
||||
|
||||
// 相同基指针但不同访问指针,需要比较索引
|
||||
return compareIndices(loc1, loc2);
|
||||
}
|
||||
|
||||
// 2. 不同类型的内存位置
|
||||
if ((loc1->isLocalArray && loc2->isLocalArray)) {
|
||||
return compareLocalArrays(loc1, loc2);
|
||||
}
|
||||
|
||||
if ((loc1->isFunctionParameter && loc2->isFunctionParameter)) {
|
||||
return compareParameters(loc1, loc2);
|
||||
}
|
||||
|
||||
if ((loc1->isGlobalArray || loc2->isGlobalArray)) {
|
||||
return compareWithGlobal(loc1, loc2);
|
||||
}
|
||||
|
||||
return compareMixedTypes(loc1, loc2);
|
||||
}
|
||||
|
||||
AliasType SysYAliasAnalysisPass::compareIndices(MemoryLocation* loc1, MemoryLocation* loc2) {
|
||||
// 比较相同基指针下的不同索引访问
|
||||
|
||||
// 如果都有常量索引,可以精确比较
|
||||
if (loc1->hasConstantIndices && loc2->hasConstantIndices) {
|
||||
// 比较索引数量
|
||||
if (loc1->indices.size() != loc2->indices.size()) {
|
||||
return AliasType::NO_ALIAS;
|
||||
}
|
||||
|
||||
// 逐个比较索引值
|
||||
for (size_t i = 0; i < loc1->indices.size(); ++i) {
|
||||
Value* idx1 = loc1->indices[i];
|
||||
Value* idx2 = loc2->indices[i];
|
||||
|
||||
// 都是常量,比较值
|
||||
auto* const1 = dynamic_cast<ConstantInteger*>(idx1);
|
||||
auto* const2 = dynamic_cast<ConstantInteger*>(idx2);
|
||||
|
||||
if (const1 && const2) {
|
||||
int val1 = std::get<int>(const1->getVal());
|
||||
int val2 = std::get<int>(const2->getVal());
|
||||
|
||||
if (val1 != val2) {
|
||||
return AliasType::NO_ALIAS; // 不同常量索引,确定无别名
|
||||
}
|
||||
} else {
|
||||
// 不是常量,无法确定
|
||||
return AliasType::POSSIBLE_ALIAS;
|
||||
}
|
||||
}
|
||||
|
||||
// 所有索引都相同
|
||||
return AliasType::SELF_ALIAS;
|
||||
}
|
||||
|
||||
// 如果有非常量索引,保守估计
|
||||
return AliasType::POSSIBLE_ALIAS;
|
||||
}
|
||||
|
||||
AliasType SysYAliasAnalysisPass::compareLocalArrays(MemoryLocation* loc1, MemoryLocation* loc2) {
|
||||
// 不同局部数组不别名
|
||||
return AliasType::NO_ALIAS;
|
||||
}
|
||||
|
||||
AliasType SysYAliasAnalysisPass::compareParameters(MemoryLocation* loc1, MemoryLocation* loc2) {
|
||||
// SysY特化:可配置的数组参数别名策略
|
||||
//
|
||||
// SysY中数组参数的语法形式:
|
||||
// void func(int a[], int b[]) - 一维数组参数
|
||||
// void func(int a[][10], int b[]) - 多维数组参数
|
||||
//
|
||||
// 默认保守策略:不同数组参数可能别名(因为可能传入相同数组)
|
||||
// func(arr, arr); // 传入同一个数组给两个参数
|
||||
//
|
||||
// 激进策略:假设不同数组参数不会传入相同数组(适用于评测环境)
|
||||
// 在SysY评测中,这种情况很少出现
|
||||
|
||||
if (useAggressiveParameterAnalysis()) {
|
||||
// 激进策略:不同数组参数假设不别名
|
||||
return AliasType::NO_ALIAS;
|
||||
} else {
|
||||
// 保守策略:不同数组参数可能别名
|
||||
return AliasType::POSSIBLE_ALIAS;
|
||||
}
|
||||
}
|
||||
|
||||
AliasType SysYAliasAnalysisPass::compareWithGlobal(MemoryLocation* loc1, MemoryLocation* loc2) {
|
||||
// 涉及全局数组的访问分析
|
||||
// 这里处理所有涉及全局数组的情况
|
||||
|
||||
// SysY特化:局部数组与全局数组不别名
|
||||
if ((loc1->isLocalArray && loc2->isGlobalArray) ||
|
||||
(loc1->isGlobalArray && loc2->isLocalArray)) {
|
||||
// 局部数组在栈上,全局数组在全局区,确定不别名
|
||||
return AliasType::NO_ALIAS;
|
||||
}
|
||||
|
||||
// SysY特化:数组参数与全局数组可能别名(保守处理)
|
||||
if ((loc1->isFunctionParameter && loc2->isGlobalArray) ||
|
||||
(loc1->isGlobalArray && loc2->isFunctionParameter)) {
|
||||
// 数组参数可能指向全局数组,需要保守处理
|
||||
return AliasType::POSSIBLE_ALIAS;
|
||||
}
|
||||
|
||||
// 其他涉及全局数组的情况,采用保守策略
|
||||
return AliasType::POSSIBLE_ALIAS;
|
||||
}
|
||||
|
||||
AliasType SysYAliasAnalysisPass::compareMixedTypes(MemoryLocation* loc1, MemoryLocation* loc2) {
|
||||
// 混合类型访问的别名分析
|
||||
// 处理不同内存类型之间的别名关系
|
||||
|
||||
// SysY特化:局部数组与数组参数通常不别名
|
||||
// 典型场景:
|
||||
// void func(int p[]) { // p 是数组参数
|
||||
// int local[10]; // local 是局部数组
|
||||
// p[0] = local[0]; // 混合类型访问
|
||||
// }
|
||||
// 或多维数组:
|
||||
// void func(int p[][10]) { // p 是多维数组参数
|
||||
// int local[10]; // local 是局部数组
|
||||
// p[i][0] = local[0]; // 混合类型访问
|
||||
// }
|
||||
// 局部数组与数组参数:在SysY中通常不别名
|
||||
if ((loc1->isLocalArray && loc2->isFunctionParameter) ||
|
||||
(loc1->isFunctionParameter && loc2->isLocalArray)) {
|
||||
// 因为局部数组是栈上分配,而数组参数是传入的外部数组
|
||||
return AliasType::NO_ALIAS;
|
||||
}
|
||||
|
||||
// 对于其他混合情况,保守估计
|
||||
return AliasType::UNKNOWN_ALIAS;
|
||||
}
|
||||
|
||||
void SysYAliasAnalysisPass::applySysYConstraints(Function* F) {
|
||||
// SysY语言特定的约束和优化
|
||||
// 1. SysY没有指针运算,简化了别名分析
|
||||
// 2. 数组传参时保持数组语义
|
||||
// 3. 没有动态内存分配,所有数组要么是局部的要么是参数/全局
|
||||
}
|
||||
|
||||
void SysYAliasAnalysisPass::optimizeParameterAnalysis(Function* F) {
|
||||
// 数组参数别名分析优化
|
||||
// 为SysY评测环境提供可配置的优化策略
|
||||
|
||||
if (!enableParameterOptimization()) {
|
||||
return; // 保持默认的保守策略
|
||||
}
|
||||
|
||||
// 可选的参数优化:假设不同数组参数不会传入相同数组
|
||||
// 典型的SysY函数调用:
|
||||
// int arr1[10], arr2[20];
|
||||
// func(arr1, arr2); // 传入不同数组
|
||||
// 而不是:
|
||||
// func(arr1, arr1); // 传入相同数组给两个参数
|
||||
// 这在SysY评测中通常是安全的假设
|
||||
auto& locationMap = CurrentResult->LocationMap;
|
||||
|
||||
for (auto it1 = locationMap.begin(); it1 != locationMap.end(); ++it1) {
|
||||
for (auto it2 = std::next(it1); it2 != locationMap.end(); ++it2) {
|
||||
MemoryLocation* loc1 = it1->second.get();
|
||||
MemoryLocation* loc2 = it2->second.get();
|
||||
|
||||
// 如果两个都是数组参数且基指针不同,设为NO_ALIAS
|
||||
if (loc1->isFunctionParameter && loc2->isFunctionParameter &&
|
||||
loc1->basePointer != loc2->basePointer) {
|
||||
CurrentResult->addAliasRelation(it1->first, it2->first, AliasType::NO_ALIAS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SysYAliasAnalysisPass::optimizeArrayAccessAnalysis(Function* F) {
|
||||
// 数组访问别名分析优化
|
||||
// 基于SysY语言的特点进行简单优化
|
||||
|
||||
// 优化1:同一数组的不同常量索引访问确定无别名
|
||||
optimizeConstantIndexAccesses();
|
||||
|
||||
// 优化2:识别简单的顺序访问模式
|
||||
optimizeSequentialAccesses();
|
||||
}
|
||||
|
||||
bool SysYAliasAnalysisPass::isConstantValue(Value* val) {
|
||||
return dynamic_cast<ConstantInteger*>(val) != nullptr; // 简化,只检查整数常量
|
||||
}
|
||||
|
||||
bool SysYAliasAnalysisPass::hasLoopVariableInIndices(const std::vector<Value*>& indices, Function* F) {
|
||||
// 保守策略:所有非常量索引都视为可能的循环变量
|
||||
// 这样可以避免复杂的循环分析依赖,保持分析的独立性
|
||||
for (Value* index : indices) {
|
||||
if (!isConstantValue(index)) {
|
||||
return true; // 保守估计,确保正确性
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int SysYAliasAnalysisPass::calculateConstantOffset(const std::vector<Value*>& indices) {
|
||||
int offset = 0;
|
||||
for (Value* index : indices) {
|
||||
if (auto* constInt = dynamic_cast<ConstantInteger*>(index)) {
|
||||
// ConstantInteger的getVal()返回variant,需要提取int值
|
||||
auto val = constInt->getVal();
|
||||
if (std::holds_alternative<int>(val)) {
|
||||
offset += std::get<int>(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
void SysYAliasAnalysisPass::printStatistics() const {
|
||||
if (CurrentResult) {
|
||||
CurrentResult->print();
|
||||
}
|
||||
}
|
||||
|
||||
void SysYAliasAnalysisPass::optimizeConstantIndexAccesses() {
|
||||
// 优化常量索引访问的别名关系
|
||||
// 对于相同基指针的访问,如果索引都是常量且不同,则确定无别名
|
||||
|
||||
auto& locationMap = CurrentResult->LocationMap;
|
||||
std::vector<Value*> allPointers;
|
||||
for (auto& pair : locationMap) {
|
||||
allPointers.push_back(pair.first);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < allPointers.size(); ++i) {
|
||||
for (size_t j = i + 1; j < allPointers.size(); ++j) {
|
||||
Value* ptr1 = allPointers[i];
|
||||
Value* ptr2 = allPointers[j];
|
||||
MemoryLocation* loc1 = locationMap[ptr1].get();
|
||||
MemoryLocation* loc2 = locationMap[ptr2].get();
|
||||
|
||||
// 相同基指针且都有常量索引
|
||||
if (loc1->basePointer == loc2->basePointer &&
|
||||
loc1->hasConstantIndices && loc2->hasConstantIndices) {
|
||||
|
||||
// 比较常量偏移
|
||||
if (loc1->constantOffset != loc2->constantOffset) {
|
||||
// 不同的常量偏移,确定无别名
|
||||
CurrentResult->addAliasRelation(ptr1, ptr2, AliasType::NO_ALIAS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SysYAliasAnalysisPass::optimizeSequentialAccesses() {
|
||||
// 识别和优化顺序访问模式
|
||||
// 这是一个简化的实现,主要用于识别数组的顺序遍历
|
||||
|
||||
// 在SysY中,大多数数组访问都是通过循环进行的
|
||||
// 对于非常量索引的访问,我们采用保守策略,不进行过多优化
|
||||
// 这样可以保持分析的简单性和正确性
|
||||
|
||||
// 未来如果需要更精确的分析,可以在这里添加更复杂的逻辑
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
417
src/midend/Pass/Analysis/CallGraphAnalysis.cpp
Normal file
417
src/midend/Pass/Analysis/CallGraphAnalysis.cpp
Normal file
@@ -0,0 +1,417 @@
|
||||
#include "CallGraphAnalysis.h"
|
||||
#include "SysYIRPrinter.h"
|
||||
#include <iostream>
|
||||
#include <stack>
|
||||
#include <unordered_set>
|
||||
|
||||
extern int DEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 静态成员初始化
|
||||
void* CallGraphAnalysisPass::ID = (void*)&CallGraphAnalysisPass::ID;
|
||||
|
||||
// ========== CallGraphAnalysisResult 实现 ==========
|
||||
|
||||
CallGraphAnalysisResult::Statistics CallGraphAnalysisResult::getStatistics() const {
|
||||
Statistics stats = {};
|
||||
stats.totalFunctions = nodes.size();
|
||||
|
||||
size_t totalCallEdges = 0;
|
||||
size_t recursiveFunctions = 0;
|
||||
size_t selfRecursiveFunctions = 0;
|
||||
size_t totalCallers = 0;
|
||||
size_t totalCallees = 0;
|
||||
|
||||
for (const auto& pair : nodes) {
|
||||
const auto& node = pair.second;
|
||||
totalCallEdges += node->callees.size();
|
||||
totalCallers += node->callers.size();
|
||||
totalCallees += node->callees.size();
|
||||
|
||||
if (node->isRecursive) recursiveFunctions++;
|
||||
if (node->isSelfRecursive) selfRecursiveFunctions++;
|
||||
}
|
||||
|
||||
stats.totalCallEdges = totalCallEdges;
|
||||
stats.recursiveFunctions = recursiveFunctions;
|
||||
stats.selfRecursiveFunctions = selfRecursiveFunctions;
|
||||
stats.stronglyConnectedComponents = sccs.size();
|
||||
|
||||
// 计算最大SCC大小
|
||||
size_t maxSCCSize = 0;
|
||||
for (const auto& scc : sccs) {
|
||||
maxSCCSize = std::max(maxSCCSize, scc.size());
|
||||
}
|
||||
stats.maxSCCSize = maxSCCSize;
|
||||
|
||||
// 计算平均值
|
||||
if (stats.totalFunctions > 0) {
|
||||
stats.avgCallersPerFunction = static_cast<double>(totalCallers) / stats.totalFunctions;
|
||||
stats.avgCalleesPerFunction = static_cast<double>(totalCallees) / stats.totalFunctions;
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
void CallGraphAnalysisResult::print() const {
|
||||
std::cout << "---- Call Graph Analysis Results for Module ----\n";
|
||||
|
||||
// 打印基本统计信息
|
||||
auto stats = getStatistics();
|
||||
std::cout << " Statistics:\n";
|
||||
std::cout << " Total Functions: " << stats.totalFunctions << "\n";
|
||||
std::cout << " Total Call Edges: " << stats.totalCallEdges << "\n";
|
||||
std::cout << " Recursive Functions: " << stats.recursiveFunctions << "\n";
|
||||
std::cout << " Self-Recursive Functions: " << stats.selfRecursiveFunctions << "\n";
|
||||
std::cout << " Strongly Connected Components: " << stats.stronglyConnectedComponents << "\n";
|
||||
std::cout << " Max SCC Size: " << stats.maxSCCSize << "\n";
|
||||
std::cout << " Avg Callers per Function: " << stats.avgCallersPerFunction << "\n";
|
||||
std::cout << " Avg Callees per Function: " << stats.avgCalleesPerFunction << "\n";
|
||||
|
||||
// 打印拓扑排序结果
|
||||
std::cout << " Topological Order (" << topologicalOrder.size() << "):\n";
|
||||
for (size_t i = 0; i < topologicalOrder.size(); ++i) {
|
||||
std::cout << " " << i << ": " << topologicalOrder[i]->getName() << "\n";
|
||||
}
|
||||
|
||||
// 打印强连通分量
|
||||
if (!sccs.empty()) {
|
||||
std::cout << " Strongly Connected Components:\n";
|
||||
for (size_t i = 0; i < sccs.size(); ++i) {
|
||||
std::cout << " SCC " << i << " (size " << sccs[i].size() << "): ";
|
||||
for (size_t j = 0; j < sccs[i].size(); ++j) {
|
||||
if (j > 0) std::cout << ", ";
|
||||
std::cout << sccs[i][j]->getName();
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// 打印每个函数的详细信息
|
||||
std::cout << " Function Details:\n";
|
||||
for (const auto& pair : nodes) {
|
||||
const auto& node = pair.second;
|
||||
std::cout << " Function: " << node->function->getName();
|
||||
|
||||
if (node->isRecursive) {
|
||||
std::cout << " (Recursive";
|
||||
if (node->isSelfRecursive) std::cout << ", Self";
|
||||
if (node->recursiveDepth >= 0) std::cout << ", Depth=" << node->recursiveDepth;
|
||||
std::cout << ")";
|
||||
}
|
||||
std::cout << "\n";
|
||||
|
||||
if (!node->callers.empty()) {
|
||||
std::cout << " Callers (" << node->callers.size() << "): ";
|
||||
bool first = true;
|
||||
for (Function* caller : node->callers) {
|
||||
if (!first) std::cout << ", ";
|
||||
std::cout << caller->getName();
|
||||
first = false;
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
if (!node->callees.empty()) {
|
||||
std::cout << " Callees (" << node->callees.size() << "): ";
|
||||
bool first = true;
|
||||
for (Function* callee : node->callees) {
|
||||
if (!first) std::cout << ", ";
|
||||
std::cout << callee->getName();
|
||||
first = false;
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "--------------------------------------------------\n";
|
||||
}
|
||||
|
||||
void CallGraphAnalysisResult::addNode(Function* F) {
|
||||
if (nodes.find(F) == nodes.end()) {
|
||||
nodes[F] = std::make_unique<CallGraphNode>(F);
|
||||
}
|
||||
}
|
||||
|
||||
void CallGraphAnalysisResult::addCallEdge(Function* caller, Function* callee) {
|
||||
// 确保两个函数都有对应的节点
|
||||
addNode(caller);
|
||||
addNode(callee);
|
||||
|
||||
// 添加调用边
|
||||
nodes[caller]->callees.insert(callee);
|
||||
nodes[callee]->callers.insert(caller);
|
||||
|
||||
// 更新统计信息
|
||||
nodes[caller]->totalCallees = nodes[caller]->callees.size();
|
||||
nodes[callee]->totalCallers = nodes[callee]->callers.size();
|
||||
|
||||
// 检查自递归
|
||||
if (caller == callee) {
|
||||
nodes[caller]->isSelfRecursive = true;
|
||||
nodes[caller]->isRecursive = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CallGraphAnalysisResult::computeTopologicalOrder() {
|
||||
topologicalOrder.clear();
|
||||
std::unordered_set<Function*> visited;
|
||||
|
||||
// 对每个未访问的函数进行DFS
|
||||
for (const auto& pair : nodes) {
|
||||
Function* F = pair.first;
|
||||
if (visited.find(F) == visited.end()) {
|
||||
dfsTopological(F, visited, topologicalOrder);
|
||||
}
|
||||
}
|
||||
|
||||
// 反转结果(因为我们在后序遍历中添加)
|
||||
std::reverse(topologicalOrder.begin(), topologicalOrder.end());
|
||||
}
|
||||
|
||||
void CallGraphAnalysisResult::dfsTopological(Function* F, std::unordered_set<Function*>& visited,
|
||||
std::vector<Function*>& result) {
|
||||
visited.insert(F);
|
||||
|
||||
auto node = getNode(F);
|
||||
if (node) {
|
||||
// 先访问所有被调用的函数
|
||||
for (Function* callee : node->callees) {
|
||||
if (visited.find(callee) == visited.end()) {
|
||||
dfsTopological(callee, visited, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 后序遍历:访问完所有子节点后添加当前节点
|
||||
result.push_back(F);
|
||||
}
|
||||
|
||||
void CallGraphAnalysisResult::computeStronglyConnectedComponents() {
|
||||
tarjanSCC();
|
||||
|
||||
// 为每个函数设置其所属的SCC
|
||||
functionToSCC.clear();
|
||||
for (size_t i = 0; i < sccs.size(); ++i) {
|
||||
for (Function* F : sccs[i]) {
|
||||
functionToSCC[F] = static_cast<int>(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CallGraphAnalysisResult::tarjanSCC() {
|
||||
sccs.clear();
|
||||
|
||||
std::vector<int> indices(nodes.size(), -1);
|
||||
std::vector<int> lowlinks(nodes.size(), -1);
|
||||
std::vector<Function*> stack;
|
||||
std::unordered_set<Function*> onStack;
|
||||
int index = 0;
|
||||
|
||||
// 为函数分配索引
|
||||
std::map<Function*, int> functionIndex;
|
||||
int idx = 0;
|
||||
for (const auto& pair : nodes) {
|
||||
functionIndex[pair.first] = idx++;
|
||||
}
|
||||
|
||||
// 对每个未访问的函数运行Tarjan算法
|
||||
for (const auto& pair : nodes) {
|
||||
Function* F = pair.first;
|
||||
int fIdx = functionIndex[F];
|
||||
if (indices[fIdx] == -1) {
|
||||
tarjanDFS(F, index, indices, lowlinks, stack, onStack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CallGraphAnalysisResult::tarjanDFS(Function* F, int& index, std::vector<int>& indices,
|
||||
std::vector<int>& lowlinks, std::vector<Function*>& stack,
|
||||
std::unordered_set<Function*>& onStack) {
|
||||
// 这里需要函数到索引的映射,简化实现
|
||||
// 在实际实现中应该维护一个全局的函数索引映射
|
||||
static std::map<Function*, int> functionIndex;
|
||||
static int nextIndex = 0;
|
||||
|
||||
if (functionIndex.find(F) == functionIndex.end()) {
|
||||
functionIndex[F] = nextIndex++;
|
||||
}
|
||||
|
||||
int fIdx = functionIndex[F];
|
||||
|
||||
// 确保向量足够大
|
||||
if (fIdx >= static_cast<int>(indices.size())) {
|
||||
indices.resize(fIdx + 1, -1);
|
||||
lowlinks.resize(fIdx + 1, -1);
|
||||
}
|
||||
|
||||
indices[fIdx] = index;
|
||||
lowlinks[fIdx] = index;
|
||||
index++;
|
||||
|
||||
stack.push_back(F);
|
||||
onStack.insert(F);
|
||||
|
||||
auto node = getNode(F);
|
||||
if (node) {
|
||||
for (Function* callee : node->callees) {
|
||||
int calleeIdx = functionIndex[callee];
|
||||
|
||||
// 确保向量足够大
|
||||
if (calleeIdx >= static_cast<int>(indices.size())) {
|
||||
indices.resize(calleeIdx + 1, -1);
|
||||
lowlinks.resize(calleeIdx + 1, -1);
|
||||
}
|
||||
|
||||
if (indices[calleeIdx] == -1) {
|
||||
// 递归访问
|
||||
tarjanDFS(callee, index, indices, lowlinks, stack, onStack);
|
||||
lowlinks[fIdx] = std::min(lowlinks[fIdx], lowlinks[calleeIdx]);
|
||||
} else if (onStack.find(callee) != onStack.end()) {
|
||||
// 后向边
|
||||
lowlinks[fIdx] = std::min(lowlinks[fIdx], indices[calleeIdx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果F是SCC的根
|
||||
if (lowlinks[fIdx] == indices[fIdx]) {
|
||||
std::vector<Function*> scc;
|
||||
Function* w;
|
||||
do {
|
||||
w = stack.back();
|
||||
stack.pop_back();
|
||||
onStack.erase(w);
|
||||
scc.push_back(w);
|
||||
} while (w != F);
|
||||
|
||||
sccs.push_back(std::move(scc));
|
||||
}
|
||||
}
|
||||
|
||||
void CallGraphAnalysisResult::analyzeRecursion() {
|
||||
// 基于SCC分析递归
|
||||
for (const auto& scc : sccs) {
|
||||
if (scc.size() > 1) {
|
||||
// 多函数的SCC,标记为相互递归
|
||||
for (Function* F : scc) {
|
||||
auto* node = getMutableNode(F);
|
||||
if (node) {
|
||||
node->isRecursive = true;
|
||||
node->recursiveDepth = -1; // 相互递归,深度未定义
|
||||
}
|
||||
}
|
||||
} else if (scc.size() == 1) {
|
||||
// 单函数SCC,检查是否自递归
|
||||
Function* F = scc[0];
|
||||
auto* node = getMutableNode(F);
|
||||
if (node && node->callees.count(F) > 0) {
|
||||
node->isSelfRecursive = true;
|
||||
node->isRecursive = true;
|
||||
node->recursiveDepth = -1; // 简化:不计算递归深度
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ========== CallGraphAnalysisPass 实现 ==========
|
||||
|
||||
bool CallGraphAnalysisPass::runOnModule(Module* M, AnalysisManager& AM) {
|
||||
if (DEBUG) {
|
||||
std::cout << "Running Call Graph Analysis on module\n";
|
||||
}
|
||||
|
||||
// 创建分析结果
|
||||
CurrentResult = std::make_unique<CallGraphAnalysisResult>(M);
|
||||
|
||||
// 执行主要分析步骤
|
||||
buildCallGraph(M);
|
||||
CurrentResult->computeTopologicalOrder();
|
||||
CurrentResult->computeStronglyConnectedComponents();
|
||||
CurrentResult->analyzeRecursion();
|
||||
|
||||
if (DEBUG) {
|
||||
CurrentResult->print();
|
||||
}
|
||||
|
||||
return false; // 分析遍不修改IR
|
||||
}
|
||||
|
||||
void CallGraphAnalysisPass::buildCallGraph(Module* M) {
|
||||
// 1. 为所有函数创建节点(包括声明但未定义的函数)
|
||||
for (auto& pair : M->getFunctions()) {
|
||||
Function* F = pair.second.get();
|
||||
if (!isLibraryFunction(F) && !isIntrinsicFunction(F)) {
|
||||
CurrentResult->addNode(F);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 扫描所有函数的调用关系
|
||||
for (auto& pair : M->getFunctions()) {
|
||||
Function* F = pair.second.get();
|
||||
if (!isLibraryFunction(F) && !isIntrinsicFunction(F)) {
|
||||
scanFunctionCalls(F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CallGraphAnalysisPass::scanFunctionCalls(Function* F) {
|
||||
// 遍历函数中的所有基本块和指令
|
||||
for (auto& BB : F->getBasicBlocks_NoRange()) {
|
||||
for (auto& I : BB->getInstructions()) {
|
||||
if (CallInst* call = dynamic_cast<CallInst*>(I.get())) {
|
||||
processCallInstruction(call, F);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CallGraphAnalysisPass::processCallInstruction(CallInst* call, Function* caller) {
|
||||
Function* callee = call->getCallee();
|
||||
|
||||
if (!callee) {
|
||||
// 间接调用,无法静态确定目标函数
|
||||
return;
|
||||
}
|
||||
|
||||
if (isLibraryFunction(callee) || isIntrinsicFunction(callee)) {
|
||||
// 跳过标准库函数和内置函数
|
||||
return;
|
||||
}
|
||||
|
||||
// 添加调用边
|
||||
CurrentResult->addCallEdge(caller, callee);
|
||||
|
||||
// 更新调用点统计
|
||||
auto* node = CurrentResult->getMutableNode(caller);
|
||||
if (node) {
|
||||
node->callSiteCount++;
|
||||
}
|
||||
}
|
||||
|
||||
bool CallGraphAnalysisPass::isLibraryFunction(Function* F) const {
|
||||
std::string name = F->getName();
|
||||
|
||||
// SysY标准库函数
|
||||
return name == "getint" || name == "getch" || name == "getfloat" ||
|
||||
name == "getarray" || name == "getfarray" ||
|
||||
name == "putint" || name == "putch" || name == "putfloat" ||
|
||||
name == "putarray" || name == "putfarray" ||
|
||||
name == "_sysy_starttime" || name == "_sysy_stoptime";
|
||||
}
|
||||
|
||||
bool CallGraphAnalysisPass::isIntrinsicFunction(Function* F) const {
|
||||
std::string name = F->getName();
|
||||
|
||||
// 编译器内置函数(后续可以增加某些内置函数)
|
||||
return name.substr(0, 5) == "llvm." || name.substr(0, 5) == "sysy.";
|
||||
}
|
||||
|
||||
void CallGraphAnalysisPass::printStatistics() const {
|
||||
if (CurrentResult) {
|
||||
CurrentResult->print();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
415
src/midend/Pass/Analysis/Loop.cpp
Normal file
415
src/midend/Pass/Analysis/Loop.cpp
Normal file
@@ -0,0 +1,415 @@
|
||||
#include "Dom.h" // 确保包含 DominatorTreeAnalysisPass 的定义
|
||||
#include "Loop.h" //
|
||||
#include "AliasAnalysis.h" // 添加别名分析依赖
|
||||
#include "SideEffectAnalysis.h" // 添加副作用分析依赖
|
||||
#include <iostream>
|
||||
#include <queue> // 用于 BFS 遍历设置循环层级
|
||||
|
||||
// 调试模式开关
|
||||
#ifndef DEBUG
|
||||
#define DEBUG 0
|
||||
#endif
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 定义 Pass 的唯一 ID
|
||||
void *LoopAnalysisPass::ID = (void *)&LoopAnalysisPass::ID;
|
||||
|
||||
// 定义 Loop 类的静态变量
|
||||
int Loop::NextLoopID = 0;
|
||||
// **实现 LoopAnalysisResult::print() 方法**
|
||||
|
||||
|
||||
void LoopAnalysisResult::printBBSet(const std::string &prefix, const std::set<BasicBlock *> &s) const{
|
||||
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 << "}";
|
||||
}
|
||||
|
||||
// **辅助函数:打印 Loop 指针向量**
|
||||
void LoopAnalysisResult::printLoopVector(const std::string &prefix, const std::vector<Loop *> &loops) const {
|
||||
if (!DEBUG) return;
|
||||
std::cout << prefix << "[";
|
||||
bool first = true;
|
||||
for (const auto &loop : loops) {
|
||||
if (!first) std::cout << ", ";
|
||||
std::cout << loop->getName(); // 假设 Loop::getName() 存在
|
||||
first = false;
|
||||
}
|
||||
std::cout << "]";
|
||||
}
|
||||
|
||||
void LoopAnalysisResult::print() const {
|
||||
if (!DEBUG) return; // 只有在 DEBUG 模式下才打印
|
||||
|
||||
std::cout << "\n--- Loop Analysis Results for Function: " << AssociatedFunction->getName() << " ---" << std::endl;
|
||||
|
||||
if (AllLoops.empty()) {
|
||||
std::cout << " No loops found." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "Total Loops Found: " << AllLoops.size() << std::endl;
|
||||
|
||||
// 1. 按层级分组循环
|
||||
std::map<int, std::vector<Loop*>> loopsByLevel;
|
||||
int maxLevel = 0;
|
||||
for (const auto& loop_ptr : AllLoops) {
|
||||
if (loop_ptr->getLoopLevel() != -1) { // 确保层级已计算
|
||||
loopsByLevel[loop_ptr->getLoopLevel()].push_back(loop_ptr.get());
|
||||
if (loop_ptr->getLoopLevel() > maxLevel) {
|
||||
maxLevel = loop_ptr->getLoopLevel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 打印循环层次结构
|
||||
std::cout << "\n--- Loop Hierarchy ---" << std::endl;
|
||||
for (int level = 0; level <= maxLevel; ++level) {
|
||||
if (loopsByLevel.count(level)) {
|
||||
std::cout << "Level " << level << " Loops:" << std::endl;
|
||||
for (Loop* loop : loopsByLevel[level]) {
|
||||
std::string indent(level * 2, ' '); // 根据层级缩进
|
||||
std::cout << indent << "- Loop Header: " << loop->getName() << std::endl;
|
||||
std::cout << indent << " Blocks: ";
|
||||
printBBSet("", loop->getBlocks());
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << indent << " Exit Blocks: ";
|
||||
printBBSet("", loop->getExitBlocks());
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << indent << " Pre-Header: " << (loop->getPreHeader() ? loop->getPreHeader()->getName() : "None") << std::endl;
|
||||
std::cout << indent << " Parent Loop: " << (loop->getParentLoop() ? loop->getParentLoop()->getName() : "None (Outermost)") << std::endl;
|
||||
std::cout << indent << " Nested Loops: ";
|
||||
printLoopVector("", loop->getNestedLoops());
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 打印最外层/最内层循环摘要
|
||||
std::cout << "\n--- Loop Summary ---" << std::endl;
|
||||
std::cout << "Outermost Loops: ";
|
||||
printLoopVector("", getOutermostLoops());
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << "Innermost Loops: ";
|
||||
printLoopVector("", getInnermostLoops());
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << "-----------------------------------------------" << std::endl;
|
||||
}
|
||||
|
||||
bool LoopAnalysisPass::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
if (F->getBasicBlocks().empty()) {
|
||||
CurrentResult = std::make_unique<LoopAnalysisResult>(F);
|
||||
return false; // 空函数,没有循环
|
||||
}
|
||||
|
||||
if (DEBUG)
|
||||
std::cout << "Running LoopAnalysisPass on function: " << F->getName() << std::endl;
|
||||
|
||||
// 获取支配树分析结果
|
||||
// 这是循环分析的关键依赖
|
||||
DominatorTree *DT = AM.getAnalysisResult<DominatorTree, DominatorTreeAnalysisPass>(F);
|
||||
if (!DT) {
|
||||
// 无法获取支配树,无法进行循环分析
|
||||
std::cerr << "Error: DominatorTreeAnalysisResult not available for function " << F->getName() << std::endl;
|
||||
CurrentResult = std::make_unique<LoopAnalysisResult>(F);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取别名分析结果 - 用于循环内存访问分析
|
||||
AliasAnalysisResult *aliasAnalysis = AM.getAnalysisResult<AliasAnalysisResult, SysYAliasAnalysisPass>(F);
|
||||
if (DEBUG && aliasAnalysis) {
|
||||
std::cout << "Loop Analysis: Using alias analysis results for enhanced memory pattern detection" << std::endl;
|
||||
}
|
||||
|
||||
// 获取副作用分析结果 - 用于循环纯度分析
|
||||
SideEffectAnalysisResult *sideEffectAnalysis = AM.getAnalysisResult<SideEffectAnalysisResult, SysYSideEffectAnalysisPass>();
|
||||
if (DEBUG && sideEffectAnalysis) {
|
||||
std::cout << "Loop Analysis: Using side effect analysis results for loop purity detection" << std::endl;
|
||||
}
|
||||
|
||||
CurrentResult = std::make_unique<LoopAnalysisResult>(F);
|
||||
bool changed = false; // 循环分析本身不修改IR,所以通常返回false
|
||||
|
||||
// 步骤 1: 识别回边和对应的自然循环
|
||||
// 回边 (N -> D) 定义:D 支配 N
|
||||
std::vector<std::pair<BasicBlock *, BasicBlock *>> backEdges;
|
||||
for (auto &BB : F->getBasicBlocks()) {
|
||||
auto Block = BB.get();
|
||||
for (BasicBlock *Succ : Block->getSuccessors()) {
|
||||
if (DT->getDominators(Block) && DT->getDominators(Block)->count(Succ)) {
|
||||
// Succ 支配 Block,所以 (Block -> Succ) 是一条回边
|
||||
backEdges.push_back({Block, Succ});
|
||||
if (DEBUG)
|
||||
std::cout << "Found back edge: " << Block->getName() << " -> " << Succ->getName() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG)
|
||||
std::cout << "Total back edges found: " << backEdges.size() << std::endl;
|
||||
|
||||
// 步骤 2: 为每条回边构建自然循环
|
||||
std::map<BasicBlock*, std::unique_ptr<Loop>> loopMap; // 按循环头分组
|
||||
|
||||
for (auto &edge : backEdges) {
|
||||
BasicBlock *N = edge.first; // 回边的尾部
|
||||
BasicBlock *D = edge.second; // 回边的头部 (循环头)
|
||||
|
||||
// 检查是否已经为此循环头创建了循环
|
||||
if (loopMap.find(D) == loopMap.end()) {
|
||||
// 创建新的 Loop 对象
|
||||
loopMap[D] = std::make_unique<Loop>(D);
|
||||
}
|
||||
|
||||
Loop* currentLoop = loopMap[D].get();
|
||||
|
||||
// 收集此回边对应的循环体块:从 N 逆向遍历到 D
|
||||
std::set<BasicBlock *> loopBlocks; // 临时存储循环块
|
||||
std::queue<BasicBlock *> q;
|
||||
|
||||
// 循环头总是循环体的一部分
|
||||
loopBlocks.insert(D);
|
||||
|
||||
// 如果回边的尾部不是循环头本身,则将其加入队列进行遍历
|
||||
if (N != D) {
|
||||
q.push(N);
|
||||
loopBlocks.insert(N);
|
||||
}
|
||||
|
||||
while (!q.empty()) {
|
||||
BasicBlock *current = q.front();
|
||||
q.pop();
|
||||
|
||||
for (BasicBlock *pred : current->getPredecessors()) {
|
||||
// 如果前驱还没有被访问过,则将其加入循环体并继续遍历
|
||||
if (loopBlocks.find(pred) == loopBlocks.end()) {
|
||||
loopBlocks.insert(pred);
|
||||
q.push(pred);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 将收集到的块添加到 Loop 对象中(合并所有回边的结果)
|
||||
for (BasicBlock *loopBB : loopBlocks) {
|
||||
currentLoop->addBlock(loopBB);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理每个合并后的循环
|
||||
for (auto &[header, currentLoop] : loopMap) {
|
||||
const auto &loopBlocks = currentLoop->getBlocks();
|
||||
|
||||
// 步骤 3: 识别循环出口块 (Exit Blocks)
|
||||
for (BasicBlock *loopBB : loopBlocks) {
|
||||
for (BasicBlock *succ : loopBB->getSuccessors()) {
|
||||
if (loopBlocks.find(succ) == loopBlocks.end()) {
|
||||
// 如果后继不在循环体内,则 loopBB 是一个出口块
|
||||
currentLoop->addExitBlock(loopBB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 步骤 4: 识别循环前置块 (Pre-Header)
|
||||
BasicBlock *candidatePreHeader = nullptr;
|
||||
int externalPredecessorCount = 0;
|
||||
for (BasicBlock *predOfHeader : header->getPredecessors()) {
|
||||
// 使用 currentLoop->contains() 来检查前驱是否在循环体内
|
||||
if (!currentLoop->contains(predOfHeader)) {
|
||||
// 如果前驱不在循环体内,则是一个外部前驱
|
||||
externalPredecessorCount++;
|
||||
candidatePreHeader = predOfHeader;
|
||||
}
|
||||
}
|
||||
|
||||
if (externalPredecessorCount == 1) {
|
||||
currentLoop->setPreHeader(candidatePreHeader);
|
||||
}
|
||||
CurrentResult->addLoop(std::move(currentLoop));
|
||||
}
|
||||
|
||||
// 步骤 5: 处理嵌套循环 (确定父子关系和层级)
|
||||
const auto &allLoops = CurrentResult->getAllLoops();
|
||||
|
||||
// 1. 首先,清除所有循环已设置的父子关系和嵌套子循环列表,确保重新计算
|
||||
for (const auto &loop_ptr : allLoops) {
|
||||
loop_ptr->setParentLoop(nullptr); // 清除父指针
|
||||
loop_ptr->clearNestedLoops(); // 清除子循环列表
|
||||
loop_ptr->setLoopLevel(-1); // 重置循环层级
|
||||
}
|
||||
|
||||
// 2. 遍历所有循环,为每个循环找到其直接父循环并建立关系
|
||||
for (const auto &innerLoop_ptr : allLoops) {
|
||||
Loop *innerLoop = innerLoop_ptr.get();
|
||||
Loop *immediateParent = nullptr; // 用于存储当前 innerLoop 的最近父循环
|
||||
|
||||
for (const auto &outerLoop_ptr : allLoops) {
|
||||
Loop *outerLoop = outerLoop_ptr.get();
|
||||
|
||||
// 一个循环不能是它自己的父循环
|
||||
if (outerLoop == innerLoop) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查 outerLoop 是否包含 innerLoop 的所有条件:
|
||||
// Condition 1: outerLoop 的头支配 innerLoop 的头
|
||||
if (!(DT->getDominators(innerLoop->getHeader()) &&
|
||||
DT->getDominators(innerLoop->getHeader())->count(outerLoop->getHeader()))) {
|
||||
continue; // outerLoop 不支配 innerLoop 的头,因此不是一个外层循环
|
||||
}
|
||||
|
||||
// Condition 2: innerLoop 的所有基本块都在 outerLoop 的基本块集合中
|
||||
bool allInnerBlocksInOuter = true;
|
||||
for (BasicBlock *innerBB : innerLoop->getBlocks()) {
|
||||
if (!outerLoop->contains(innerBB)) { //
|
||||
allInnerBlocksInOuter = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!allInnerBlocksInOuter) {
|
||||
continue; // outerLoop 不包含 innerLoop 的所有块
|
||||
}
|
||||
|
||||
// 到此为止,outerLoop 已经被确认为 innerLoop 的一个“候选父循环”(即它包含了 innerLoop)
|
||||
|
||||
if (immediateParent == nullptr) {
|
||||
// 这是找到的第一个候选父循环
|
||||
immediateParent = outerLoop;
|
||||
} else {
|
||||
// 已经有了一个 immediateParent,需要判断哪个是更“紧密”的父循环
|
||||
// 更紧密的父循环是那个包含另一个候选父循环的。
|
||||
// 如果当前的 immediateParent 包含了 outerLoop 的头,那么 outerLoop 是更深的循环(更接近 innerLoop)
|
||||
if (immediateParent->contains(outerLoop->getHeader())) { //
|
||||
immediateParent = outerLoop; // outerLoop 是更紧密的父循环
|
||||
}
|
||||
// 否则(outerLoop 包含了 immediateParent 的头),说明 immediateParent 更紧密,保持不变
|
||||
// 或者它们互不包含(不应该发生,因为它们都包含了 innerLoop),也保持 immediateParent
|
||||
}
|
||||
}
|
||||
|
||||
// 设置 innerLoop 的直接父循环,并添加到父循环的嵌套列表中
|
||||
if (immediateParent) {
|
||||
innerLoop->setParentLoop(immediateParent);
|
||||
immediateParent->addNestedLoop(innerLoop);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 计算循环层级 (Level)
|
||||
std::queue<Loop *> q_level;
|
||||
|
||||
// 查找所有最外层循环(没有父循环的),设置其层级为0,并加入队列
|
||||
for (const auto &loop_ptr : allLoops) {
|
||||
if (loop_ptr->isOutermost()) {
|
||||
loop_ptr->setLoopLevel(0);
|
||||
q_level.push(loop_ptr.get());
|
||||
}
|
||||
}
|
||||
|
||||
// 使用 BFS 遍历循环树,计算所有嵌套循环的层级
|
||||
while (!q_level.empty()) {
|
||||
Loop *current = q_level.front();
|
||||
q_level.pop();
|
||||
|
||||
for (Loop *nestedLoop : current->getNestedLoops()) {
|
||||
nestedLoop->setLoopLevel(current->getLoopLevel() + 1);
|
||||
q_level.push(nestedLoop);
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "Loop Analysis completed for function: " << F->getName() << std::endl;
|
||||
std::cout << "Total loops found: " << CurrentResult->getLoopCount() << std::endl;
|
||||
std::cout << "Max loop depth: " << CurrentResult->getMaxLoopDepth() << std::endl;
|
||||
std::cout << "Innermost loops: " << CurrentResult->getInnermostLoops().size() << std::endl;
|
||||
std::cout << "Outermost loops: " << CurrentResult->getOutermostLoops().size() << std::endl;
|
||||
|
||||
// 打印各深度的循环分布
|
||||
for (int depth = 1; depth <= CurrentResult->getMaxLoopDepth(); ++depth) {
|
||||
int count = CurrentResult->getLoopCountAtDepth(depth);
|
||||
if (count > 0) {
|
||||
std::cout << "Loops at depth " << depth << ": " << count << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 输出缓存统计
|
||||
auto cacheStats = CurrentResult->getCacheStats();
|
||||
std::cout << "Cache statistics - Total cached queries: " << cacheStats.totalCachedQueries << std::endl;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
// ========== Loop 类的新增方法实现 ==========
|
||||
|
||||
bool Loop::mayHaveSideEffects(SideEffectAnalysisResult* sideEffectAnalysis) const {
|
||||
if (!sideEffectAnalysis) return true; // 保守假设
|
||||
|
||||
for (BasicBlock* bb : LoopBlocks) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (sideEffectAnalysis->hasSideEffect(inst.get())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Loop::accessesGlobalMemory(AliasAnalysisResult* aliasAnalysis) const {
|
||||
if (!aliasAnalysis) return true; // 保守假设
|
||||
|
||||
for (BasicBlock* bb : LoopBlocks) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (auto* loadInst = dynamic_cast<LoadInst*>(inst.get())) {
|
||||
if (!aliasAnalysis->isLocalArray(loadInst->getPointer())) {
|
||||
return true;
|
||||
}
|
||||
} else if (auto* storeInst = dynamic_cast<StoreInst*>(inst.get())) {
|
||||
if (!aliasAnalysis->isLocalArray(storeInst->getPointer())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Loop::hasMemoryAliasConflicts(AliasAnalysisResult* aliasAnalysis) const {
|
||||
if (!aliasAnalysis) return true; // 保守假设
|
||||
|
||||
std::vector<Value*> memoryAccesses;
|
||||
|
||||
// 收集所有内存访问
|
||||
for (BasicBlock* bb : LoopBlocks) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (auto* loadInst = dynamic_cast<LoadInst*>(inst.get())) {
|
||||
memoryAccesses.push_back(loadInst->getPointer());
|
||||
} else if (auto* storeInst = dynamic_cast<StoreInst*>(inst.get())) {
|
||||
memoryAccesses.push_back(storeInst->getPointer());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查两两之间是否有别名
|
||||
for (size_t i = 0; i < memoryAccesses.size(); ++i) {
|
||||
for (size_t j = i + 1; j < memoryAccesses.size(); ++j) {
|
||||
auto aliasType = aliasAnalysis->queryAlias(memoryAccesses[i], memoryAccesses[j]);
|
||||
if (aliasType == AliasType::SELF_ALIAS || aliasType == AliasType::POSSIBLE_ALIAS) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
1099
src/midend/Pass/Analysis/LoopCharacteristics.cpp
Normal file
1099
src/midend/Pass/Analysis/LoopCharacteristics.cpp
Normal file
File diff suppressed because it is too large
Load Diff
803
src/midend/Pass/Analysis/LoopVectorization.cpp
Normal file
803
src/midend/Pass/Analysis/LoopVectorization.cpp
Normal file
@@ -0,0 +1,803 @@
|
||||
#include "LoopVectorization.h"
|
||||
#include "Dom.h"
|
||||
#include "Loop.h"
|
||||
#include "Liveness.h"
|
||||
#include "AliasAnalysis.h"
|
||||
#include "SideEffectAnalysis.h"
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <set>
|
||||
|
||||
extern int DEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 定义 Pass 的唯一 ID
|
||||
void *LoopVectorizationPass::ID = (void *)&LoopVectorizationPass::ID;
|
||||
|
||||
std::vector<int> DependenceVector::getDirectionVector() const {
|
||||
std::vector<int> direction;
|
||||
direction.reserve(distances.size());
|
||||
|
||||
for (int dist : distances) {
|
||||
if (dist > 0) direction.push_back(1); // 前向依赖
|
||||
else if (dist < 0) direction.push_back(-1); // 后向依赖
|
||||
else direction.push_back(0); // 无依赖
|
||||
}
|
||||
|
||||
return direction;
|
||||
}
|
||||
|
||||
bool DependenceVector::isVectorizationSafe() const {
|
||||
if (!isKnown) return false; // 未知依赖,不安全
|
||||
|
||||
// 对于向量化,我们主要关心最内层循环的依赖
|
||||
if (distances.empty()) return true;
|
||||
|
||||
int innermostDistance = distances.back(); // 最内层循环的距离
|
||||
|
||||
// 前向依赖 (距离 > 0) 通常是安全的,可以通过调整向量化顺序处理
|
||||
// 后向依赖 (距离 < 0) 通常不安全,会阻止向量化
|
||||
// 距离 = 0 表示同一迭代内的依赖,通常安全
|
||||
|
||||
return innermostDistance >= 0;
|
||||
}
|
||||
|
||||
size_t LoopVectorizationResult::getVectorizableLoopCount() const {
|
||||
size_t count = 0;
|
||||
for (const auto& [loop, analysis] : VectorizationMap) {
|
||||
if (analysis.isVectorizable) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t LoopVectorizationResult::getParallelizableLoopCount() const {
|
||||
size_t count = 0;
|
||||
for (const auto& [loop, analysis] : ParallelizationMap) {
|
||||
if (analysis.isParallelizable) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
std::vector<Loop*> LoopVectorizationResult::getVectorizationCandidates() const {
|
||||
std::vector<Loop*> candidates;
|
||||
for (const auto& [loop, analysis] : VectorizationMap) {
|
||||
if (analysis.isVectorizable) {
|
||||
candidates.push_back(loop);
|
||||
}
|
||||
}
|
||||
|
||||
// 按建议的向量宽度排序,优先处理收益更大的循环
|
||||
std::sort(candidates.begin(), candidates.end(),
|
||||
[this](Loop* a, Loop* b) {
|
||||
const auto& analysisA = VectorizationMap.at(a);
|
||||
const auto& analysisB = VectorizationMap.at(b);
|
||||
return analysisA.suggestedVectorWidth > analysisB.suggestedVectorWidth;
|
||||
});
|
||||
|
||||
return candidates;
|
||||
}
|
||||
|
||||
std::vector<Loop*> LoopVectorizationResult::getParallelizationCandidates() const {
|
||||
std::vector<Loop*> candidates;
|
||||
for (const auto& [loop, analysis] : ParallelizationMap) {
|
||||
if (analysis.isParallelizable) {
|
||||
candidates.push_back(loop);
|
||||
}
|
||||
}
|
||||
|
||||
// 按建议的线程数排序
|
||||
std::sort(candidates.begin(), candidates.end(),
|
||||
[this](Loop* a, Loop* b) {
|
||||
const auto& analysisA = ParallelizationMap.at(a);
|
||||
const auto& analysisB = ParallelizationMap.at(b);
|
||||
return analysisA.suggestedThreadCount > analysisB.suggestedThreadCount;
|
||||
});
|
||||
|
||||
return candidates;
|
||||
}
|
||||
|
||||
void LoopVectorizationResult::print() const {
|
||||
if (!DEBUG) return;
|
||||
|
||||
std::cout << "\n--- Loop Vectorization/Parallelization Analysis Results for Function: "
|
||||
<< AssociatedFunction->getName() << " ---" << std::endl;
|
||||
|
||||
if (VectorizationMap.empty() && ParallelizationMap.empty()) {
|
||||
std::cout << " No vectorization/parallelization analysis results." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// 统计信息
|
||||
std::cout << "\n=== Summary ===" << std::endl;
|
||||
std::cout << "Total Loops Analyzed: " << VectorizationMap.size() << std::endl;
|
||||
std::cout << "Vectorizable Loops: " << getVectorizableLoopCount() << std::endl;
|
||||
std::cout << "Parallelizable Loops: " << getParallelizableLoopCount() << std::endl;
|
||||
|
||||
// 详细分析结果
|
||||
for (const auto& [loop, vecAnalysis] : VectorizationMap) {
|
||||
std::cout << "\n--- Loop: " << loop->getName() << " ---" << std::endl;
|
||||
|
||||
// 向量化分析 (暂时搁置)
|
||||
std::cout << " Vectorization: " << (vecAnalysis.isVectorizable ? "YES" : "NO") << std::endl;
|
||||
if (!vecAnalysis.preventingFactors.empty()) {
|
||||
std::cout << " Preventing Factors: ";
|
||||
for (const auto& factor : vecAnalysis.preventingFactors) {
|
||||
std::cout << factor << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// 并行化分析
|
||||
auto parallelIt = ParallelizationMap.find(loop);
|
||||
if (parallelIt != ParallelizationMap.end()) {
|
||||
const auto& parAnalysis = parallelIt->second;
|
||||
std::cout << " Parallelization: " << (parAnalysis.isParallelizable ? "YES" : "NO") << std::endl;
|
||||
if (parAnalysis.isParallelizable) {
|
||||
std::cout << " Suggested Thread Count: " << parAnalysis.suggestedThreadCount << std::endl;
|
||||
if (parAnalysis.requiresReduction) {
|
||||
std::cout << " Requires Reduction: Yes" << std::endl;
|
||||
}
|
||||
if (parAnalysis.requiresBarrier) {
|
||||
std::cout << " Requires Barrier: Yes" << std::endl;
|
||||
}
|
||||
} else if (!parAnalysis.preventingFactors.empty()) {
|
||||
std::cout << " Preventing Factors: ";
|
||||
for (const auto& factor : parAnalysis.preventingFactors) {
|
||||
std::cout << factor << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 依赖关系
|
||||
auto depIt = DependenceMap.find(loop);
|
||||
if (depIt != DependenceMap.end()) {
|
||||
const auto& dependences = depIt->second;
|
||||
std::cout << " Dependences: " << dependences.size() << " found" << std::endl;
|
||||
for (const auto& dep : dependences) {
|
||||
if (dep.dependenceVector.isKnown) {
|
||||
std::cout << " " << dep.source->getName() << " -> " << dep.sink->getName();
|
||||
std::cout << " [";
|
||||
for (size_t i = 0; i < dep.dependenceVector.distances.size(); ++i) {
|
||||
if (i > 0) std::cout << ",";
|
||||
std::cout << dep.dependenceVector.distances[i];
|
||||
}
|
||||
std::cout << "]" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "-----------------------------------------------" << std::endl;
|
||||
}
|
||||
|
||||
bool LoopVectorizationPass::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
if (F->getBasicBlocks().empty()) {
|
||||
CurrentResult = std::make_unique<LoopVectorizationResult>(F);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "Running LoopVectorizationPass on function: " << F->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 获取循环分析结果
|
||||
auto* loopAnalysisResult = AM.getAnalysisResult<LoopAnalysisResult, LoopAnalysisPass>(F);
|
||||
if (!loopAnalysisResult || !loopAnalysisResult->hasLoops()) {
|
||||
CurrentResult = std::make_unique<LoopVectorizationResult>(F);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取循环特征分析结果
|
||||
auto* loopCharacteristics = AM.getAnalysisResult<LoopCharacteristicsResult, LoopCharacteristicsPass>(F);
|
||||
if (!loopCharacteristics) {
|
||||
if (DEBUG) {
|
||||
std::cout << "Warning: LoopCharacteristics analysis not available" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取别名分析结果
|
||||
auto* aliasAnalysis = AM.getAnalysisResult<AliasAnalysisResult, SysYAliasAnalysisPass>(F);
|
||||
|
||||
// 获取副作用分析结果
|
||||
auto* sideEffectAnalysis = AM.getAnalysisResult<SideEffectAnalysisResult, SysYSideEffectAnalysisPass>();
|
||||
|
||||
CurrentResult = std::make_unique<LoopVectorizationResult>(F);
|
||||
|
||||
// 分析每个循环的向量化/并行化可行性
|
||||
for (const auto& loop_ptr : loopAnalysisResult->getAllLoops()) {
|
||||
Loop* loop = loop_ptr.get();
|
||||
|
||||
// 获取该循环的特征信息
|
||||
LoopCharacteristics* characteristics = nullptr;
|
||||
if (loopCharacteristics) {
|
||||
characteristics = const_cast<LoopCharacteristics*>(loopCharacteristics->getCharacteristics(loop));
|
||||
}
|
||||
|
||||
analyzeLoop(loop, characteristics, aliasAnalysis, sideEffectAnalysis);
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "LoopVectorizationPass completed. Found "
|
||||
<< CurrentResult->getVectorizableLoopCount() << " vectorizable loops, "
|
||||
<< CurrentResult->getParallelizableLoopCount() << " parallelizable loops" << std::endl;
|
||||
}
|
||||
|
||||
return false; // 分析遍不修改IR
|
||||
}
|
||||
|
||||
void LoopVectorizationPass::analyzeLoop(Loop* loop, LoopCharacteristics* characteristics,
|
||||
AliasAnalysisResult* aliasAnalysis, SideEffectAnalysisResult* sideEffectAnalysis) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Analyzing advanced features for loop: " << loop->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 1. 计算精确依赖向量
|
||||
auto dependences = computeDependenceVectors(loop, aliasAnalysis);
|
||||
CurrentResult->addDependenceAnalysis(loop, dependences);
|
||||
|
||||
// 2. 分析向量化可行性 (暂时搁置,总是返回不可向量化)
|
||||
auto vecAnalysis = analyzeVectorizability(loop, dependences, characteristics);
|
||||
CurrentResult->addVectorizationAnalysis(loop, vecAnalysis);
|
||||
|
||||
// 3. 分析并行化可行性
|
||||
auto parAnalysis = analyzeParallelizability(loop, dependences, characteristics);
|
||||
CurrentResult->addParallelizationAnalysis(loop, parAnalysis);
|
||||
}
|
||||
|
||||
// ========== 依赖向量分析实现 ==========
|
||||
|
||||
std::vector<PreciseDependence> LoopVectorizationPass::computeDependenceVectors(Loop* loop,
|
||||
AliasAnalysisResult* aliasAnalysis) {
|
||||
std::vector<PreciseDependence> dependences;
|
||||
std::vector<Instruction*> memoryInsts;
|
||||
|
||||
// 收集所有内存操作指令
|
||||
for (BasicBlock* bb : loop->getBlocks()) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (dynamic_cast<LoadInst*>(inst.get()) || dynamic_cast<StoreInst*>(inst.get())) {
|
||||
memoryInsts.push_back(inst.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分析每对内存操作之间的依赖关系
|
||||
for (size_t i = 0; i < memoryInsts.size(); ++i) {
|
||||
for (size_t j = i + 1; j < memoryInsts.size(); ++j) {
|
||||
Instruction* inst1 = memoryInsts[i];
|
||||
Instruction* inst2 = memoryInsts[j];
|
||||
|
||||
Value* ptr1 = nullptr;
|
||||
Value* ptr2 = nullptr;
|
||||
|
||||
if (auto* load = dynamic_cast<LoadInst*>(inst1)) {
|
||||
ptr1 = load->getPointer();
|
||||
} else if (auto* store = dynamic_cast<StoreInst*>(inst1)) {
|
||||
ptr1 = store->getPointer();
|
||||
}
|
||||
|
||||
if (auto* load = dynamic_cast<LoadInst*>(inst2)) {
|
||||
ptr2 = load->getPointer();
|
||||
} else if (auto* store = dynamic_cast<StoreInst*>(inst2)) {
|
||||
ptr2 = store->getPointer();
|
||||
}
|
||||
|
||||
if (!ptr1 || !ptr2) continue;
|
||||
|
||||
// 检查是否可能存在别名关系
|
||||
bool mayAlias = false;
|
||||
if (aliasAnalysis) {
|
||||
mayAlias = aliasAnalysis->queryAlias(ptr1, ptr2) != AliasType::NO_ALIAS;
|
||||
} else {
|
||||
mayAlias = (ptr1 != ptr2); // 保守估计
|
||||
}
|
||||
|
||||
if (mayAlias) {
|
||||
// 创建依赖关系
|
||||
PreciseDependence dep(loop->getLoopDepth());
|
||||
dep.source = inst1;
|
||||
dep.sink = inst2;
|
||||
dep.memoryLocation = ptr1;
|
||||
|
||||
// 确定依赖类型
|
||||
bool isStore1 = dynamic_cast<StoreInst*>(inst1) != nullptr;
|
||||
bool isStore2 = dynamic_cast<StoreInst*>(inst2) != nullptr;
|
||||
|
||||
if (isStore1 && !isStore2) {
|
||||
dep.type = DependenceType::TRUE_DEPENDENCE; // Write -> Read (RAW)
|
||||
} else if (!isStore1 && isStore2) {
|
||||
dep.type = DependenceType::ANTI_DEPENDENCE; // Read -> Write (WAR)
|
||||
} else if (isStore1 && isStore2) {
|
||||
dep.type = DependenceType::OUTPUT_DEPENDENCE; // Write -> Write (WAW)
|
||||
} else {
|
||||
continue; // Read -> Read (RAR) - 跳过,不是真正的依赖
|
||||
}
|
||||
|
||||
// 计算依赖向量
|
||||
dep.dependenceVector = computeAccessDependence(inst1, inst2, loop);
|
||||
|
||||
// 判断是否允许并行化
|
||||
dep.allowsParallelization = dep.dependenceVector.isLoopIndependent() ||
|
||||
(dep.dependenceVector.isKnown &&
|
||||
std::all_of(dep.dependenceVector.distances.begin(),
|
||||
dep.dependenceVector.distances.end(),
|
||||
[](int d) { return d >= 0; }));
|
||||
|
||||
dependences.push_back(dep);
|
||||
|
||||
if (DEBUG && dep.dependenceVector.isKnown) {
|
||||
std::cout << " Found dependence: " << inst1->getName()
|
||||
<< " -> " << inst2->getName() << " [";
|
||||
for (size_t k = 0; k < dep.dependenceVector.distances.size(); ++k) {
|
||||
if (k > 0) std::cout << ",";
|
||||
std::cout << dep.dependenceVector.distances[k];
|
||||
}
|
||||
std::cout << "]" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dependences;
|
||||
}
|
||||
|
||||
DependenceVector LoopVectorizationPass::computeAccessDependence(Instruction* inst1, Instruction* inst2, Loop* loop) {
|
||||
DependenceVector depVec(loop->getLoopDepth());
|
||||
|
||||
Value* ptr1 = nullptr;
|
||||
Value* ptr2 = nullptr;
|
||||
|
||||
if (auto* load = dynamic_cast<LoadInst*>(inst1)) {
|
||||
ptr1 = load->getPointer();
|
||||
} else if (auto* store = dynamic_cast<StoreInst*>(inst1)) {
|
||||
ptr1 = store->getPointer();
|
||||
}
|
||||
|
||||
if (auto* load = dynamic_cast<LoadInst*>(inst2)) {
|
||||
ptr2 = load->getPointer();
|
||||
} else if (auto* store = dynamic_cast<StoreInst*>(inst2)) {
|
||||
ptr2 = store->getPointer();
|
||||
}
|
||||
|
||||
if (!ptr1 || !ptr2) return depVec;
|
||||
|
||||
// 尝试分析仿射关系
|
||||
if (areAccessesAffinelyRelated(ptr1, ptr2, loop)) {
|
||||
auto coeff1 = extractInductionCoefficients(ptr1, loop);
|
||||
auto coeff2 = extractInductionCoefficients(ptr2, loop);
|
||||
|
||||
if (coeff1.size() == coeff2.size()) {
|
||||
depVec.isKnown = true;
|
||||
depVec.isConstant = true;
|
||||
|
||||
for (size_t i = 0; i < coeff1.size(); ++i) {
|
||||
depVec.distances[i] = coeff2[i] - coeff1[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return depVec;
|
||||
}
|
||||
|
||||
bool LoopVectorizationPass::areAccessesAffinelyRelated(Value* ptr1, Value* ptr2, Loop* loop) {
|
||||
// 简化实现:检查是否都是基于归纳变量的数组访问
|
||||
// 真正的实现需要复杂的仿射关系分析
|
||||
|
||||
// 检查是否为 GEP 指令
|
||||
auto* gep1 = dynamic_cast<GetElementPtrInst*>(ptr1);
|
||||
auto* gep2 = dynamic_cast<GetElementPtrInst*>(ptr2);
|
||||
|
||||
if (!gep1 || !gep2) return false;
|
||||
|
||||
// 检查是否访问同一个数组基址
|
||||
if (gep1->getBasePointer() != gep2->getBasePointer()) return false;
|
||||
|
||||
// 简化:假设都是仿射的
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== 向量化分析实现 (暂时搁置) ==========
|
||||
|
||||
VectorizationAnalysis LoopVectorizationPass::analyzeVectorizability(Loop* loop,
|
||||
const std::vector<PreciseDependence>& dependences,
|
||||
LoopCharacteristics* characteristics) {
|
||||
VectorizationAnalysis analysis; // 构造函数已设置为不可向量化
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Vectorization analysis: DISABLED (temporarily)" << std::endl;
|
||||
}
|
||||
|
||||
// 向量化功能暂时搁置,总是返回不可向量化
|
||||
// 这里可以添加一些基本的诊断信息用于日志
|
||||
if (!loop->isInnermost()) {
|
||||
analysis.preventingFactors.push_back("Not innermost loop");
|
||||
}
|
||||
if (loop->getBlocks().size() > 1) {
|
||||
analysis.preventingFactors.push_back("Complex control flow");
|
||||
}
|
||||
if (!dependences.empty()) {
|
||||
analysis.preventingFactors.push_back("Has dependences (not analyzed in detail)");
|
||||
}
|
||||
|
||||
return analysis;
|
||||
}
|
||||
|
||||
// ========== 并行化分析实现 ==========
|
||||
|
||||
ParallelizationAnalysis LoopVectorizationPass::analyzeParallelizability(Loop* loop,
|
||||
const std::vector<PreciseDependence>& dependences,
|
||||
LoopCharacteristics* characteristics) {
|
||||
ParallelizationAnalysis analysis;
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Analyzing parallelizability for loop: " << loop->getName() << std::endl;
|
||||
std::cout << " Found " << dependences.size() << " dependences" << std::endl;
|
||||
}
|
||||
|
||||
// 按依赖类型分类分析
|
||||
bool hasTrueDependences = false;
|
||||
bool hasAntiDependences = false;
|
||||
bool hasOutputDependences = false;
|
||||
|
||||
for (const auto& dep : dependences) {
|
||||
switch (dep.type) {
|
||||
case DependenceType::TRUE_DEPENDENCE:
|
||||
hasTrueDependences = true;
|
||||
// 真依赖通常是最难处理的,需要检查是否为归约模式
|
||||
if (dep.isReductionDependence) {
|
||||
analysis.requiresReduction = true;
|
||||
analysis.reductionVariables.insert(dep.memoryLocation);
|
||||
} else {
|
||||
analysis.preventingFactors.push_back("Non-reduction true dependence");
|
||||
}
|
||||
break;
|
||||
case DependenceType::ANTI_DEPENDENCE:
|
||||
hasAntiDependences = true;
|
||||
// 反依赖可以通过变量私有化解决
|
||||
analysis.privatizableVariables.insert(dep.memoryLocation);
|
||||
break;
|
||||
case DependenceType::OUTPUT_DEPENDENCE:
|
||||
hasOutputDependences = true;
|
||||
// 输出依赖可以通过变量私有化或原子操作解决
|
||||
analysis.sharedVariables.insert(dep.memoryLocation);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 确定并行化类型
|
||||
analysis.parallelType = determineParallelizationType(loop, dependences);
|
||||
|
||||
// 基于依赖类型评估可并行性
|
||||
if (!hasTrueDependences && !hasOutputDependences) {
|
||||
// 只有反依赖或无依赖,完全可并行
|
||||
analysis.parallelType = ParallelizationAnalysis::EMBARRASSINGLY_PARALLEL;
|
||||
analysis.isParallelizable = true;
|
||||
} else if (analysis.requiresReduction) {
|
||||
// 有归约模式,可以并行但需要特殊处理
|
||||
analysis.parallelType = ParallelizationAnalysis::REDUCTION_PARALLEL;
|
||||
analysis.isParallelizable = true;
|
||||
} else if (hasTrueDependences) {
|
||||
// 有非归约的真依赖,通常不能并行化
|
||||
analysis.isParallelizable = false;
|
||||
analysis.preventingFactors.push_back("Non-reduction loop-carried true dependences");
|
||||
}
|
||||
|
||||
if (analysis.isParallelizable) {
|
||||
// 进一步分析并行化收益和成本
|
||||
estimateParallelizationBenefit(loop, &analysis, characteristics);
|
||||
analyzeSynchronizationNeeds(loop, &analysis, dependences);
|
||||
analysis.suggestedThreadCount = estimateOptimalThreadCount(loop, characteristics);
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Parallelizable: " << (analysis.isParallelizable ? "YES" : "NO") << std::endl;
|
||||
if (analysis.isParallelizable) {
|
||||
std::cout << " Type: " << (int)analysis.parallelType << ", Threads: " << analysis.suggestedThreadCount << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return analysis;
|
||||
}
|
||||
|
||||
bool LoopVectorizationPass::checkParallelizationLegality(Loop* loop, const std::vector<PreciseDependence>& dependences) {
|
||||
// 检查所有依赖是否允许并行化
|
||||
for (const auto& dep : dependences) {
|
||||
if (!dep.allowsParallelization) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否有无法并行化的操作
|
||||
for (BasicBlock* bb : loop->getBlocks()) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
// 检查原子操作、同步操作等
|
||||
if (auto* call = dynamic_cast<CallInst*>(inst.get())) {
|
||||
// 简化:假设函数调用需要特殊处理
|
||||
// 在实际实现中,需要分析函数的副作用
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int LoopVectorizationPass::estimateOptimalThreadCount(Loop* loop, LoopCharacteristics* characteristics) {
|
||||
// 基于循环特征估计最优线程数
|
||||
if (!characteristics) return 2;
|
||||
|
||||
// 基于循环体大小和计算密度
|
||||
int baseThreads = 2;
|
||||
|
||||
if (characteristics->instructionCount > 50) baseThreads = 4;
|
||||
if (characteristics->instructionCount > 200) baseThreads = 8;
|
||||
|
||||
// 基于计算与内存比率调整
|
||||
if (characteristics->computeToMemoryRatio > 2.0) {
|
||||
baseThreads *= 2; // 计算密集型,可以使用更多线程
|
||||
}
|
||||
|
||||
return std::min(baseThreads, 16); // 限制最大线程数
|
||||
}
|
||||
|
||||
// ========== 辅助方法实现 ==========
|
||||
|
||||
bool LoopVectorizationPass::isConstantStride(Value* ptr, Loop* loop, int& stride) {
|
||||
// 简化实现:检查是否为常量步长访问
|
||||
stride = 1; // 默认步长
|
||||
|
||||
auto* gep = dynamic_cast<GetElementPtrInst*>(ptr);
|
||||
if (!gep) return false;
|
||||
|
||||
// 检查最后一个索引是否为归纳变量 + 常量
|
||||
if (gep->getNumIndices() > 0) {
|
||||
Value* lastIndex = gep->getIndex(gep->getNumIndices() - 1);
|
||||
|
||||
// 简化:假设是 i 或 i+c 的形式
|
||||
if (auto* binInst = dynamic_cast<BinaryInst*>(lastIndex)) {
|
||||
if (binInst->getKind() == Instruction::kAdd) {
|
||||
// 检查是否为 i + constant
|
||||
if (auto* constInt = dynamic_cast<ConstantInteger*>(binInst->getRhs())) {
|
||||
stride = constInt->getInt();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 默认为步长1的连续访问
|
||||
stride = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<int> LoopVectorizationPass::extractInductionCoefficients(Value* ptr, Loop* loop) {
|
||||
// 简化实现:返回默认的仿射系数
|
||||
std::vector<int> coefficients;
|
||||
|
||||
// 假设是简单的 a[i] 形式,系数为 [0, 1]
|
||||
coefficients.push_back(0); // 常数项
|
||||
coefficients.push_back(1); // 归纳变量系数
|
||||
|
||||
return coefficients;
|
||||
}
|
||||
|
||||
// ========== 缺失的方法实现 ==========
|
||||
|
||||
ParallelizationAnalysis::ParallelizationType LoopVectorizationPass::determineParallelizationType(
|
||||
Loop* loop, const std::vector<PreciseDependence>& dependences) {
|
||||
|
||||
// 检查是否有任何依赖
|
||||
if (dependences.empty()) {
|
||||
return ParallelizationAnalysis::EMBARRASSINGLY_PARALLEL;
|
||||
}
|
||||
|
||||
// 检查是否只有归约模式
|
||||
bool hasReduction = false;
|
||||
bool hasOtherDependences = false;
|
||||
|
||||
for (const auto& dep : dependences) {
|
||||
if (dep.isReductionDependence) {
|
||||
hasReduction = true;
|
||||
} else if (dep.type == DependenceType::TRUE_DEPENDENCE) {
|
||||
hasOtherDependences = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasReduction && !hasOtherDependences) {
|
||||
return ParallelizationAnalysis::REDUCTION_PARALLEL;
|
||||
} else if (!hasOtherDependences) {
|
||||
return ParallelizationAnalysis::EMBARRASSINGLY_PARALLEL;
|
||||
}
|
||||
|
||||
return ParallelizationAnalysis::NONE;
|
||||
}
|
||||
|
||||
void LoopVectorizationPass::analyzeReductionPatterns(Loop* loop, ParallelizationAnalysis* analysis) {
|
||||
// 简化实现:查找常见的归约模式
|
||||
for (BasicBlock* bb : loop->getBlocks()) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (auto* binInst = dynamic_cast<BinaryInst*>(inst.get())) {
|
||||
if (binInst->getKind() == Instruction::kAdd || binInst->getKind() == Instruction::kMul) {
|
||||
// 检查是否为累加/累乘模式
|
||||
Value* lhs = binInst->getLhs();
|
||||
if (hasReductionPattern(lhs, loop)) {
|
||||
analysis->requiresReduction = true;
|
||||
analysis->reductionVariables.insert(lhs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LoopVectorizationPass::analyzeMemoryAccessPatterns(Loop* loop, ParallelizationAnalysis* analysis,
|
||||
AliasAnalysisResult* aliasAnalysis) {
|
||||
std::vector<Value*> memoryAccesses;
|
||||
|
||||
// 收集所有内存访问
|
||||
for (BasicBlock* bb : loop->getBlocks()) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (auto* load = dynamic_cast<LoadInst*>(inst.get())) {
|
||||
memoryAccesses.push_back(load->getPointer());
|
||||
} else if (auto* store = dynamic_cast<StoreInst*>(inst.get())) {
|
||||
memoryAccesses.push_back(store->getPointer());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分析内存访问独立性
|
||||
bool hasIndependentAccess = true;
|
||||
for (size_t i = 0; i < memoryAccesses.size(); ++i) {
|
||||
for (size_t j = i + 1; j < memoryAccesses.size(); ++j) {
|
||||
if (!isIndependentMemoryAccess(memoryAccesses[i], memoryAccesses[j], loop)) {
|
||||
hasIndependentAccess = false;
|
||||
analysis->hasMemoryConflicts = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
analysis->hasIndependentAccess = hasIndependentAccess;
|
||||
}
|
||||
|
||||
void LoopVectorizationPass::estimateParallelizationBenefit(Loop* loop, ParallelizationAnalysis* analysis,
|
||||
LoopCharacteristics* characteristics) {
|
||||
if (!analysis->isParallelizable) {
|
||||
analysis->parallelizationBenefit = 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
// 基于计算复杂度和并行度计算收益
|
||||
double workComplexity = estimateWorkComplexity(loop);
|
||||
double parallelFraction = 1.0; // 假设完全可并行
|
||||
|
||||
// 根据依赖调整并行度
|
||||
if (analysis->requiresReduction) {
|
||||
parallelFraction *= 0.8; // 归约降低并行效率
|
||||
}
|
||||
if (analysis->hasMemoryConflicts) {
|
||||
parallelFraction *= 0.6; // 内存冲突降低效率
|
||||
}
|
||||
|
||||
// Amdahl定律估算
|
||||
double serialFraction = 1.0 - parallelFraction;
|
||||
int threadCount = analysis->suggestedThreadCount;
|
||||
double speedup = 1.0 / (serialFraction + parallelFraction / threadCount);
|
||||
|
||||
analysis->parallelizationBenefit = std::min((speedup - 1.0) / threadCount, 1.0);
|
||||
|
||||
// 估算同步和通信开销
|
||||
analysis->synchronizationCost = analysis->requiresBarrier ? 100 : 0;
|
||||
analysis->communicationCost = analysis->sharedVariables.size() * 50;
|
||||
}
|
||||
|
||||
void LoopVectorizationPass::identifyPrivatizableVariables(Loop* loop, ParallelizationAnalysis* analysis) {
|
||||
// 简化实现:标识循环内定义的变量为可私有化
|
||||
for (BasicBlock* bb : loop->getBlocks()) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (!inst->getType()->isVoid()) {
|
||||
// 如果变量只在循环内使用,可能可以私有化
|
||||
bool onlyUsedInLoop = true;
|
||||
for (auto& use : inst->getUses()) {
|
||||
if (auto* userInst = dynamic_cast<Instruction*>(use->getUser())) {
|
||||
if (!loop->contains(userInst->getParent())) {
|
||||
onlyUsedInLoop = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (onlyUsedInLoop) {
|
||||
analysis->privatizableVariables.insert(inst.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LoopVectorizationPass::analyzeSynchronizationNeeds(Loop* loop, ParallelizationAnalysis* analysis,
|
||||
const std::vector<PreciseDependence>& dependences) {
|
||||
// 根据依赖类型确定同步需求
|
||||
for (const auto& dep : dependences) {
|
||||
if (dep.type == DependenceType::OUTPUT_DEPENDENCE) {
|
||||
analysis->requiresBarrier = true;
|
||||
analysis->sharedVariables.insert(dep.memoryLocation);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果有归约,需要特殊的归约同步
|
||||
if (analysis->requiresReduction) {
|
||||
analysis->requiresBarrier = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool LoopVectorizationPass::isIndependentMemoryAccess(Value* ptr1, Value* ptr2, Loop* loop) {
|
||||
// 简化实现:基本的独立性检查
|
||||
if (ptr1 == ptr2) return false;
|
||||
|
||||
// 如果是不同的基址,认为是独立的
|
||||
auto* gep1 = dynamic_cast<GetElementPtrInst*>(ptr1);
|
||||
auto* gep2 = dynamic_cast<GetElementPtrInst*>(ptr2);
|
||||
|
||||
if (gep1 && gep2) {
|
||||
if (gep1->getBasePointer() != gep2->getBasePointer()) {
|
||||
return true; // 不同的基址
|
||||
}
|
||||
// 相同基址,需要更精细的分析(这里简化为不独立)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true; // 默认认为独立
|
||||
}
|
||||
|
||||
double LoopVectorizationPass::estimateWorkComplexity(Loop* loop) {
|
||||
double complexity = 0.0;
|
||||
|
||||
for (BasicBlock* bb : loop->getBlocks()) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
// 基于指令类型分配复杂度权重
|
||||
if (auto* binInst = dynamic_cast<BinaryInst*>(inst.get())) {
|
||||
switch (binInst->getKind()) {
|
||||
case Instruction::kAdd:
|
||||
case Instruction::kSub:
|
||||
complexity += 1.0;
|
||||
break;
|
||||
case Instruction::kMul:
|
||||
complexity += 3.0;
|
||||
break;
|
||||
case Instruction::kDiv:
|
||||
complexity += 10.0;
|
||||
break;
|
||||
default:
|
||||
complexity += 2.0;
|
||||
}
|
||||
} else if (dynamic_cast<LoadInst*>(inst.get()) || dynamic_cast<StoreInst*>(inst.get())) {
|
||||
complexity += 2.0; // 内存访问
|
||||
} else {
|
||||
complexity += 1.0; // 其他指令
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return complexity;
|
||||
}
|
||||
|
||||
bool LoopVectorizationPass::hasReductionPattern(Value* var, Loop* loop) {
|
||||
// 简化实现:检查是否为简单的累加/累乘模式
|
||||
for (auto& use : var->getUses()) {
|
||||
if (auto* binInst = dynamic_cast<BinaryInst*>(use->getUser())) {
|
||||
if (binInst->getKind() == Instruction::kAdd || binInst->getKind() == Instruction::kMul) {
|
||||
// 检查是否为 var = var op something 的模式
|
||||
if (binInst->getLhs() == var || binInst->getRhs() == var) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
413
src/midend/Pass/Analysis/SideEffectAnalysis.cpp
Normal file
413
src/midend/Pass/Analysis/SideEffectAnalysis.cpp
Normal file
@@ -0,0 +1,413 @@
|
||||
#include "SideEffectAnalysis.h"
|
||||
#include "AliasAnalysis.h"
|
||||
#include "CallGraphAnalysis.h"
|
||||
#include "SysYIRPrinter.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 副作用分析遍的静态 ID
|
||||
void *SysYSideEffectAnalysisPass::ID = (void *)&SysYSideEffectAnalysisPass::ID;
|
||||
|
||||
// ======================================================================
|
||||
// SideEffectAnalysisResult 类的实现
|
||||
// ======================================================================
|
||||
|
||||
SideEffectAnalysisResult::SideEffectAnalysisResult() { initializeKnownFunctions(); }
|
||||
|
||||
const SideEffectInfo &SideEffectAnalysisResult::getInstructionSideEffect(Instruction *inst) const {
|
||||
auto it = instructionSideEffects.find(inst);
|
||||
if (it != instructionSideEffects.end()) {
|
||||
return it->second;
|
||||
}
|
||||
// 返回默认的无副作用信息
|
||||
static SideEffectInfo noEffect;
|
||||
return noEffect;
|
||||
}
|
||||
|
||||
const SideEffectInfo &SideEffectAnalysisResult::getFunctionSideEffect(Function *func) const {
|
||||
// 首先检查分析过的用户定义函数
|
||||
auto it = functionSideEffects.find(func);
|
||||
if (it != functionSideEffects.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// 如果没有找到,检查是否为已知的库函数
|
||||
if (func) {
|
||||
std::string funcName = func->getName();
|
||||
const SideEffectInfo *knownInfo = getKnownFunctionSideEffect(funcName);
|
||||
if (knownInfo) {
|
||||
return *knownInfo;
|
||||
}
|
||||
}
|
||||
|
||||
// 返回默认的无副作用信息
|
||||
static SideEffectInfo noEffect;
|
||||
return noEffect;
|
||||
}
|
||||
|
||||
void SideEffectAnalysisResult::setInstructionSideEffect(Instruction *inst, const SideEffectInfo &info) {
|
||||
instructionSideEffects[inst] = info;
|
||||
}
|
||||
|
||||
void SideEffectAnalysisResult::setFunctionSideEffect(Function *func, const SideEffectInfo &info) {
|
||||
functionSideEffects[func] = info;
|
||||
}
|
||||
|
||||
bool SideEffectAnalysisResult::hasSideEffect(Instruction *inst) const {
|
||||
const auto &info = getInstructionSideEffect(inst);
|
||||
return info.type != SideEffectType::NO_SIDE_EFFECT;
|
||||
}
|
||||
|
||||
bool SideEffectAnalysisResult::mayModifyMemory(Instruction *inst) const {
|
||||
const auto &info = getInstructionSideEffect(inst);
|
||||
return info.mayModifyMemory;
|
||||
}
|
||||
|
||||
bool SideEffectAnalysisResult::mayModifyGlobal(Instruction *inst) const {
|
||||
const auto &info = getInstructionSideEffect(inst);
|
||||
return info.mayModifyGlobal;
|
||||
}
|
||||
|
||||
bool SideEffectAnalysisResult::isPureFunction(Function *func) const {
|
||||
const auto &info = getFunctionSideEffect(func);
|
||||
return info.isPure;
|
||||
}
|
||||
|
||||
void SideEffectAnalysisResult::initializeKnownFunctions() {
|
||||
// SysY标准库函数的副作用信息
|
||||
|
||||
// I/O函数 - 有副作用
|
||||
SideEffectInfo ioEffect;
|
||||
ioEffect.type = SideEffectType::IO_OPERATION;
|
||||
ioEffect.mayModifyGlobal = true;
|
||||
ioEffect.mayModifyMemory = true;
|
||||
ioEffect.mayCallFunction = true;
|
||||
ioEffect.isPure = false;
|
||||
|
||||
// knownFunctions["printf"] = ioEffect;
|
||||
// knownFunctions["scanf"] = ioEffect;
|
||||
knownFunctions["getint"] = ioEffect;
|
||||
knownFunctions["getch"] = ioEffect;
|
||||
knownFunctions["getfloat"] = ioEffect;
|
||||
knownFunctions["getarray"] = ioEffect;
|
||||
knownFunctions["getfarray"] = ioEffect;
|
||||
knownFunctions["putint"] = ioEffect;
|
||||
knownFunctions["putch"] = ioEffect;
|
||||
knownFunctions["putfloat"] = ioEffect;
|
||||
knownFunctions["putarray"] = ioEffect;
|
||||
knownFunctions["putfarray"] = ioEffect;
|
||||
|
||||
// 时间函数 - 有副作用
|
||||
SideEffectInfo timeEffect;
|
||||
timeEffect.type = SideEffectType::FUNCTION_CALL;
|
||||
timeEffect.mayModifyGlobal = true;
|
||||
timeEffect.mayModifyMemory = false;
|
||||
timeEffect.mayCallFunction = true;
|
||||
timeEffect.isPure = false;
|
||||
|
||||
knownFunctions["_sysy_starttime"] = timeEffect;
|
||||
knownFunctions["_sysy_stoptime"] = timeEffect;
|
||||
}
|
||||
|
||||
const SideEffectInfo *SideEffectAnalysisResult::getKnownFunctionSideEffect(const std::string &funcName) const {
|
||||
auto it = knownFunctions.find(funcName);
|
||||
return (it != knownFunctions.end()) ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// SysYSideEffectAnalysisPass 类的实现
|
||||
// ======================================================================
|
||||
|
||||
bool SysYSideEffectAnalysisPass::runOnModule(Module *M, AnalysisManager &AM) {
|
||||
if (DEBUG) {
|
||||
std::cout << "Running SideEffect analysis on module" << std::endl;
|
||||
}
|
||||
|
||||
// 创建分析结果(构造函数中已经调用了initializeKnownFunctions)
|
||||
result = std::make_unique<SideEffectAnalysisResult>();
|
||||
|
||||
// 获取调用图分析结果
|
||||
callGraphAnalysis = AM.getAnalysisResult<CallGraphAnalysisResult, CallGraphAnalysisPass>();
|
||||
if (!callGraphAnalysis) {
|
||||
std::cerr << "Warning: CallGraphAnalysis not available, falling back to conservative analysis" << std::endl;
|
||||
}
|
||||
|
||||
// 按拓扑序分析函数,确保被调用函数先于调用者分析
|
||||
if (callGraphAnalysis) {
|
||||
// 使用调用图的拓扑排序结果
|
||||
const auto &topOrder = callGraphAnalysis->getTopologicalOrder();
|
||||
|
||||
// 处理强连通分量(递归函数群)
|
||||
const auto &sccs = callGraphAnalysis->getStronglyConnectedComponents();
|
||||
for (const auto &scc : sccs) {
|
||||
if (scc.size() > 1) {
|
||||
// 多个函数的强连通分量,使用不动点算法
|
||||
analyzeStronglyConnectedComponent(scc, AM);
|
||||
} else {
|
||||
// 单个函数,检查是否自递归
|
||||
Function *func = scc[0];
|
||||
if (callGraphAnalysis->isSelfRecursive(func)) {
|
||||
// 自递归函数也需要不动点算法
|
||||
analyzeStronglyConnectedComponent(scc, AM);
|
||||
} else {
|
||||
// 非递归函数,直接分析
|
||||
SideEffectInfo funcEffect = analyzeFunction(func, AM);
|
||||
result->setFunctionSideEffect(func, funcEffect);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 没有调用图,保守地分析每个函数
|
||||
for (auto &pair : M->getFunctions()) {
|
||||
Function *func = pair.second.get();
|
||||
SideEffectInfo funcEffect = analyzeFunction(func, AM);
|
||||
result->setFunctionSideEffect(func, funcEffect);
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "---- Side Effect Analysis Results for Module ----\n";
|
||||
for (auto &pair : M->getFunctions()) {
|
||||
Function *func = pair.second.get();
|
||||
const auto &funcInfo = result->getFunctionSideEffect(func);
|
||||
|
||||
std::cout << "Function " << func->getName() << ": ";
|
||||
switch (funcInfo.type) {
|
||||
case SideEffectType::NO_SIDE_EFFECT:
|
||||
std::cout << "No Side Effect";
|
||||
break;
|
||||
case SideEffectType::MEMORY_WRITE:
|
||||
std::cout << "Memory Write";
|
||||
break;
|
||||
case SideEffectType::FUNCTION_CALL:
|
||||
std::cout << "Function Call";
|
||||
break;
|
||||
case SideEffectType::IO_OPERATION:
|
||||
std::cout << "I/O Operation";
|
||||
break;
|
||||
case SideEffectType::UNKNOWN:
|
||||
std::cout << "Unknown";
|
||||
break;
|
||||
}
|
||||
std::cout << " (Pure: " << (funcInfo.isPure ? "Yes" : "No")
|
||||
<< ", Modifies Global: " << (funcInfo.mayModifyGlobal ? "Yes" : "No") << ")\n";
|
||||
}
|
||||
std::cout << "--------------------------------------------------\n";
|
||||
}
|
||||
|
||||
return false; // Analysis passes return false since they don't modify the IR
|
||||
}
|
||||
|
||||
std::unique_ptr<AnalysisResultBase> SysYSideEffectAnalysisPass::getResult() { return std::move(result); }
|
||||
|
||||
SideEffectInfo SysYSideEffectAnalysisPass::analyzeFunction(Function *func, AnalysisManager &AM) {
|
||||
SideEffectInfo functionSideEffect;
|
||||
|
||||
// 为每个指令分析副作用
|
||||
for (auto &BB : func->getBasicBlocks()) {
|
||||
for (auto &I : BB->getInstructions_Range()) {
|
||||
Instruction *inst = I.get();
|
||||
SideEffectInfo instEffect = analyzeInstruction(inst, func, AM);
|
||||
|
||||
// 记录指令的副作用信息
|
||||
result->setInstructionSideEffect(inst, instEffect);
|
||||
|
||||
// 合并到函数级别的副作用信息中
|
||||
functionSideEffect = functionSideEffect.merge(instEffect);
|
||||
}
|
||||
}
|
||||
|
||||
return functionSideEffect;
|
||||
}
|
||||
|
||||
void SysYSideEffectAnalysisPass::analyzeStronglyConnectedComponent(const std::vector<Function *> &scc,
|
||||
AnalysisManager &AM) {
|
||||
// 使用不动点算法处理递归函数群
|
||||
std::unordered_map<Function *, SideEffectInfo> currentEffects;
|
||||
std::unordered_map<Function *, SideEffectInfo> previousEffects;
|
||||
|
||||
// 初始化:所有函数都假设为纯函数
|
||||
for (Function *func : scc) {
|
||||
SideEffectInfo initialEffect;
|
||||
initialEffect.isPure = true;
|
||||
currentEffects[func] = initialEffect;
|
||||
result->setFunctionSideEffect(func, initialEffect);
|
||||
}
|
||||
|
||||
bool converged = false;
|
||||
int iterations = 0;
|
||||
const int maxIterations = 10; // 防止无限循环
|
||||
|
||||
while (!converged && iterations < maxIterations) {
|
||||
previousEffects = currentEffects;
|
||||
|
||||
// 重新分析每个函数
|
||||
for (Function *func : scc) {
|
||||
SideEffectInfo newEffect = analyzeFunction(func, AM);
|
||||
currentEffects[func] = newEffect;
|
||||
result->setFunctionSideEffect(func, newEffect);
|
||||
}
|
||||
|
||||
// 检查是否收敛
|
||||
converged = hasConverged(previousEffects, currentEffects);
|
||||
iterations++;
|
||||
}
|
||||
|
||||
if (iterations >= maxIterations) {
|
||||
std::cerr << "Warning: SideEffect analysis did not converge for SCC after " << maxIterations << " iterations"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
bool SysYSideEffectAnalysisPass::hasConverged(const std::unordered_map<Function *, SideEffectInfo> &oldEffects,
|
||||
const std::unordered_map<Function *, SideEffectInfo> &newEffects) const {
|
||||
for (const auto &pair : oldEffects) {
|
||||
Function *func = pair.first;
|
||||
const SideEffectInfo &oldEffect = pair.second;
|
||||
|
||||
auto it = newEffects.find(func);
|
||||
if (it == newEffects.end()) {
|
||||
return false; // 函数不存在于新结果中
|
||||
}
|
||||
|
||||
const SideEffectInfo &newEffect = it->second;
|
||||
|
||||
// 比较关键属性是否相同
|
||||
if (oldEffect.type != newEffect.type || oldEffect.mayModifyGlobal != newEffect.mayModifyGlobal ||
|
||||
oldEffect.mayModifyMemory != newEffect.mayModifyMemory ||
|
||||
oldEffect.mayCallFunction != newEffect.mayCallFunction || oldEffect.isPure != newEffect.isPure) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SideEffectInfo SysYSideEffectAnalysisPass::analyzeInstruction(Instruction *inst, Function *currentFunc,
|
||||
AnalysisManager &AM) {
|
||||
SideEffectInfo info;
|
||||
|
||||
// 根据指令类型进行分析
|
||||
if (inst->isCall()) {
|
||||
return analyzeCallInstruction(static_cast<CallInst *>(inst), currentFunc, AM);
|
||||
} else if (inst->isStore()) {
|
||||
return analyzeStoreInstruction(static_cast<StoreInst *>(inst), currentFunc, AM);
|
||||
} else if (inst->isMemset()) {
|
||||
return analyzeMemsetInstruction(static_cast<MemsetInst *>(inst), currentFunc, AM);
|
||||
} else if (inst->isBranch() || inst->isReturn()) {
|
||||
// 控制流指令无副作用,但必须保留
|
||||
info.type = SideEffectType::NO_SIDE_EFFECT;
|
||||
info.isPure = true;
|
||||
} else {
|
||||
// 其他指令(算术、逻辑、比较等)通常无副作用
|
||||
info.type = SideEffectType::NO_SIDE_EFFECT;
|
||||
info.isPure = true;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
SideEffectInfo SysYSideEffectAnalysisPass::analyzeCallInstruction(CallInst *call, Function *currentFunc,
|
||||
AnalysisManager &AM) {
|
||||
SideEffectInfo info;
|
||||
|
||||
// 获取被调用的函数
|
||||
Function *calledFunc = call->getCallee();
|
||||
if (!calledFunc) {
|
||||
// 间接调用,保守处理
|
||||
info.type = SideEffectType::UNKNOWN;
|
||||
info.mayModifyGlobal = true;
|
||||
info.mayModifyMemory = true;
|
||||
info.mayCallFunction = true;
|
||||
info.isPure = false;
|
||||
return info;
|
||||
}
|
||||
|
||||
std::string funcName = calledFunc->getName();
|
||||
|
||||
// 检查是否为已知的标准库函数
|
||||
const SideEffectInfo *knownInfo = result->getKnownFunctionSideEffect(funcName);
|
||||
if (knownInfo) {
|
||||
return *knownInfo;
|
||||
}
|
||||
|
||||
// 利用调用图分析结果进行精确分析
|
||||
if (callGraphAnalysis) {
|
||||
// 检查被调用函数是否已分析过
|
||||
const SideEffectInfo &funcEffect = result->getFunctionSideEffect(calledFunc);
|
||||
if (funcEffect.type != SideEffectType::NO_SIDE_EFFECT || !funcEffect.isPure) {
|
||||
return funcEffect;
|
||||
}
|
||||
|
||||
// 检查递归调用
|
||||
if (callGraphAnalysis->isRecursive(calledFunc)) {
|
||||
// 递归函数保守处理(在不动点算法中会精确分析)
|
||||
info.type = SideEffectType::FUNCTION_CALL;
|
||||
info.mayModifyGlobal = true;
|
||||
info.mayModifyMemory = true;
|
||||
info.mayCallFunction = true;
|
||||
info.isPure = false;
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
// 对于未分析的用户函数,保守处理
|
||||
info.type = SideEffectType::FUNCTION_CALL;
|
||||
info.mayModifyGlobal = true;
|
||||
info.mayModifyMemory = true;
|
||||
info.mayCallFunction = true;
|
||||
info.isPure = false;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
SideEffectInfo SysYSideEffectAnalysisPass::analyzeStoreInstruction(StoreInst *store, Function *currentFunc,
|
||||
AnalysisManager &AM) {
|
||||
SideEffectInfo info;
|
||||
info.type = SideEffectType::MEMORY_WRITE;
|
||||
info.mayModifyMemory = true;
|
||||
info.isPure = false;
|
||||
|
||||
// 获取函数的别名分析结果
|
||||
AliasAnalysisResult *aliasAnalysis = AM.getAnalysisResult<AliasAnalysisResult, SysYAliasAnalysisPass>(currentFunc);
|
||||
if (aliasAnalysis) {
|
||||
Value *storePtr = store->getPointer();
|
||||
|
||||
// 如果存储到全局变量或可能别名的位置,则可能修改全局状态
|
||||
if (!aliasAnalysis->isLocalArray(storePtr)) {
|
||||
info.mayModifyGlobal = true;
|
||||
}
|
||||
} else {
|
||||
// 没有别名分析结果,保守处理
|
||||
info.mayModifyGlobal = true;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
SideEffectInfo SysYSideEffectAnalysisPass::analyzeMemsetInstruction(MemsetInst *memset, Function *currentFunc,
|
||||
AnalysisManager &AM) {
|
||||
SideEffectInfo info;
|
||||
info.type = SideEffectType::MEMORY_WRITE;
|
||||
info.mayModifyMemory = true;
|
||||
info.isPure = false;
|
||||
|
||||
// 获取函数的别名分析结果
|
||||
AliasAnalysisResult *aliasAnalysis = AM.getAnalysisResult<AliasAnalysisResult, SysYAliasAnalysisPass>(currentFunc);
|
||||
if (aliasAnalysis) {
|
||||
Value *memsetPtr = memset->getPointer();
|
||||
|
||||
// 如果memset操作全局变量或可能别名的位置,则可能修改全局状态
|
||||
if (!aliasAnalysis->isLocalArray(memsetPtr)) {
|
||||
info.mayModifyGlobal = true;
|
||||
}
|
||||
} else {
|
||||
// 没有别名分析结果,保守处理
|
||||
info.mayModifyGlobal = true;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "DCE.h" // 包含DCE遍的头文件
|
||||
#include "IR.h" // 包含IR相关的定义
|
||||
#include "SysYIROptUtils.h" // 包含SysY IR优化工具类的定义
|
||||
#include <cassert> // 用于断言
|
||||
#include <iostream> // 用于调试输出
|
||||
#include <set> // 包含set,虽然DCEContext内部用unordered_set,但这里保留
|
||||
#include "DCE.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include "SideEffectAnalysis.h"
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
@@ -17,10 +17,26 @@ void *DCE::ID = (void *)&DCE::ID;
|
||||
|
||||
// DCEContext 的 run 方法实现
|
||||
void DCEContext::run(Function *func, AnalysisManager *AM, bool &changed) {
|
||||
// 获取别名分析结果
|
||||
if (AM) {
|
||||
aliasAnalysis = AM->getAnalysisResult<AliasAnalysisResult, SysYAliasAnalysisPass>(func);
|
||||
// 获取副作用分析结果(Module级别)
|
||||
sideEffectAnalysis = AM->getAnalysisResult<SideEffectAnalysisResult, SysYSideEffectAnalysisPass>();
|
||||
|
||||
if (DEBUG) {
|
||||
if (aliasAnalysis) {
|
||||
std::cout << "DCE: Using alias analysis results" << std::endl;
|
||||
}
|
||||
if (sideEffectAnalysis) {
|
||||
std::cout << "DCE: Using side effect analysis results" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 清空活跃指令集合,确保每次运行都是新的状态
|
||||
alive_insts.clear();
|
||||
|
||||
// 第一次遍历:扫描所有指令,识别“天然活跃”的指令并将其及其依赖标记为活跃
|
||||
// 第一次遍历:扫描所有指令,识别"天然活跃"的指令并将其及其依赖标记为活跃
|
||||
// 使用 func->getBasicBlocks() 获取基本块列表,保留用户风格
|
||||
auto basicBlocks = func->getBasicBlocks();
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
@@ -51,7 +67,7 @@ void DCEContext::run(Function *func, AnalysisManager *AM, bool &changed) {
|
||||
// 如果指令不在活跃集合中,则删除它。
|
||||
// 分支和返回指令由 isAlive 处理,并会被保留。
|
||||
if (alive_insts.count(currentInst) == 0) {
|
||||
instIter = SysYIROptUtils::usedelete(instIter); // 删除后返回下一个迭代器
|
||||
instIter = SysYIROptUtils::usedelete(instIter); // 删除后返回下一个迭代器
|
||||
changed = true; // 标记 IR 已被修改
|
||||
} else {
|
||||
++instIter; // 指令活跃,移动到下一个
|
||||
@@ -60,20 +76,58 @@ void DCEContext::run(Function *func, AnalysisManager *AM, bool &changed) {
|
||||
}
|
||||
}
|
||||
|
||||
// 判断指令是否是“天然活跃”的实现
|
||||
// 判断指令是否是"天然活跃"的实现
|
||||
// 只有具有副作用的指令(如存储、函数调用、原子操作)
|
||||
// 和控制流指令(如分支、返回)是天然活跃的。
|
||||
bool DCEContext::isAlive(Instruction *inst) {
|
||||
// TODO: 后续程序并发考虑原子操作
|
||||
// 其结果不被其他指令使用的指令(例如 StoreInst, BranchInst, ReturnInst)。
|
||||
// dynamic_cast<ir::CallInst>(inst) 检查是否是函数调用指令,
|
||||
// 函数调用通常有副作用。
|
||||
// 终止指令 (BranchInst, ReturnInst) 必须是活跃的,因为它控制了程序的执行流程。
|
||||
// 保留用户提供的 isAlive 逻辑
|
||||
bool isBranchOrReturn = inst->isBranch() || inst->isReturn();
|
||||
bool isCall = inst->isCall();
|
||||
bool isStoreOrMemset = inst->isStore() || inst->isMemset();
|
||||
return isBranchOrReturn || isCall || isStoreOrMemset;
|
||||
// 终止指令 (BranchInst, ReturnInst) 必须是活跃的,因为它控制了程序的执行流程
|
||||
if (inst->isBranch() || inst->isReturn()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 使用副作用分析来判断指令是否有副作用
|
||||
if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(inst)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 特殊处理Store指令:使用别名分析进行更精确的判断
|
||||
if (inst->isStore()) {
|
||||
auto* storeInst = static_cast<StoreInst*>(inst);
|
||||
return mayHaveSideEffect(storeInst);
|
||||
}
|
||||
|
||||
// 特殊处理Memset指令:总是保留(因为它修改内存)
|
||||
if (inst->isMemset()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 函数调用指令:总是保留(可能有未知副作用)
|
||||
if (inst->isCall()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 其他指令(算术、逻辑、Load等):无副作用,可以删除
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查Store指令是否可能有副作用(通过别名分析)
|
||||
bool DCEContext::mayHaveSideEffect(StoreInst* store) {
|
||||
if (!aliasAnalysis) {
|
||||
// 没有别名分析结果时,保守地认为所有store都有副作用
|
||||
return true;
|
||||
}
|
||||
|
||||
Value* storePtr = store->getPointer();
|
||||
|
||||
// 如果是对本地数组的存储且访问模式是常量,可能可以安全删除
|
||||
if (aliasAnalysis->isLocalArray(storePtr)) {
|
||||
// 检查是否有其他指令可能读取这个位置
|
||||
// 这里需要更复杂的活性分析,暂时保守处理
|
||||
return true; // 保守地保留所有本地数组的存储
|
||||
}
|
||||
|
||||
// 对全局变量、函数参数等的存储总是有副作用
|
||||
return true;
|
||||
}
|
||||
|
||||
// 递归地将活跃指令及其依赖加入到 alive_insts 集合中
|
||||
@@ -102,7 +156,6 @@ void DCEContext::addAlive(Instruction *inst) {
|
||||
|
||||
// DCE 遍的 runOnFunction 方法实现
|
||||
bool DCE::runOnFunction(Function *func, AnalysisManager &AM) {
|
||||
|
||||
DCEContext ctx;
|
||||
bool changed = false;
|
||||
ctx.run(func, &AM, changed); // 运行 DCE 优化
|
||||
@@ -120,7 +173,11 @@ bool DCE::runOnFunction(Function *func, AnalysisManager &AM) {
|
||||
|
||||
// 声明DCE遍的分析依赖和失效信息
|
||||
void DCE::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
|
||||
// DCE不依赖特定的分析结果,它通过遍历和副作用判断来工作。
|
||||
// DCE依赖别名分析来更精确地判断Store指令的副作用
|
||||
analysisDependencies.insert(&SysYAliasAnalysisPass::ID);
|
||||
|
||||
// DCE依赖副作用分析来判断指令是否有副作用
|
||||
analysisDependencies.insert(&SysYSideEffectAnalysisPass::ID);
|
||||
|
||||
// DCE会删除指令,这会影响许多分析结果。
|
||||
// 至少,它会影响活跃性分析、支配树、控制流图(如果删除导致基本块为空并被合并)。
|
||||
|
||||
492
src/midend/Pass/Optimize/GVN.cpp
Normal file
492
src/midend/Pass/Optimize/GVN.cpp
Normal file
@@ -0,0 +1,492 @@
|
||||
#include "GVN.h"
|
||||
#include "Dom.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
extern int DEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// GVN 遍的静态 ID
|
||||
void *GVN::ID = (void *)&GVN::ID;
|
||||
|
||||
// ======================================================================
|
||||
// GVN 类的实现
|
||||
// ======================================================================
|
||||
|
||||
bool GVN::runOnFunction(Function *func, AnalysisManager &AM) {
|
||||
if (func->getBasicBlocks().empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "\n=== Running GVN on function: " << func->getName() << " ===" << std::endl;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
GVNContext context;
|
||||
context.run(func, &AM, changed);
|
||||
|
||||
if (DEBUG) {
|
||||
if (changed) {
|
||||
std::cout << "GVN: Function " << func->getName() << " was modified" << std::endl;
|
||||
} else {
|
||||
std::cout << "GVN: Function " << func->getName() << " was not modified" << std::endl;
|
||||
}
|
||||
std::cout << "=== GVN completed for function: " << func->getName() << " ===" << std::endl;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
void GVN::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
|
||||
// GVN依赖以下分析:
|
||||
// 1. 支配树分析 - 用于检查指令的支配关系,确保替换的安全性
|
||||
analysisDependencies.insert(&DominatorTreeAnalysisPass::ID);
|
||||
|
||||
// 2. 副作用分析 - 用于判断函数调用是否可以进行GVN
|
||||
analysisDependencies.insert(&SysYSideEffectAnalysisPass::ID);
|
||||
|
||||
// GVN不会使任何分析失效,因为:
|
||||
// - GVN只删除冗余计算,不改变CFG结构
|
||||
// - GVN不修改程序的语义,只是消除重复计算
|
||||
// - 支配关系保持不变
|
||||
// - 副作用分析结果保持不变
|
||||
// analysisInvalidations 保持为空
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "GVN: Declared analysis dependencies (DominatorTree, SideEffectAnalysis)" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// GVNContext 类的实现 - 重构版本
|
||||
// ======================================================================
|
||||
|
||||
// 简单的表达式哈希结构
|
||||
struct ExpressionKey {
|
||||
enum Type { BINARY, UNARY, LOAD, GEP, CALL } type;
|
||||
int opcode;
|
||||
std::vector<Value*> operands;
|
||||
Type* resultType;
|
||||
|
||||
bool operator==(const ExpressionKey& other) const {
|
||||
return type == other.type && opcode == other.opcode &&
|
||||
operands == other.operands && resultType == other.resultType;
|
||||
}
|
||||
};
|
||||
|
||||
struct ExpressionKeyHash {
|
||||
size_t operator()(const ExpressionKey& key) const {
|
||||
size_t hash = std::hash<int>()(static_cast<int>(key.type)) ^
|
||||
std::hash<int>()(key.opcode);
|
||||
for (auto op : key.operands) {
|
||||
hash ^= std::hash<Value*>()(op) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
void GVNContext::run(Function *func, AnalysisManager *AM, bool &changed) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Starting GVN analysis for function: " << func->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 获取分析结果
|
||||
if (AM) {
|
||||
domTree = AM->getAnalysisResult<DominatorTree, DominatorTreeAnalysisPass>(func);
|
||||
sideEffectAnalysis = AM->getAnalysisResult<SideEffectAnalysisResult, SysYSideEffectAnalysisPass>();
|
||||
|
||||
if (DEBUG) {
|
||||
if (domTree) {
|
||||
std::cout << " GVN: Using dominator tree analysis" << std::endl;
|
||||
} else {
|
||||
std::cout << " GVN: Warning - dominator tree analysis not available" << std::endl;
|
||||
}
|
||||
if (sideEffectAnalysis) {
|
||||
std::cout << " GVN: Using side effect analysis" << std::endl;
|
||||
} else {
|
||||
std::cout << " GVN: Warning - side effect analysis not available" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 清空状态
|
||||
valueToNumber.clear();
|
||||
numberToValue.clear();
|
||||
expressionToNumber.clear();
|
||||
nextValueNumber = 1;
|
||||
visited.clear();
|
||||
rpoBlocks.clear();
|
||||
needRemove.clear();
|
||||
|
||||
// 计算逆后序遍历
|
||||
computeRPO(func);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Computed RPO with " << rpoBlocks.size() << " blocks" << std::endl;
|
||||
}
|
||||
|
||||
// 按逆后序遍历基本块进行GVN
|
||||
int blockCount = 0;
|
||||
for (auto bb : rpoBlocks) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Processing block " << ++blockCount << "/" << rpoBlocks.size()
|
||||
<< ": " << bb->getName() << std::endl;
|
||||
}
|
||||
|
||||
processBasicBlock(bb, changed);
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Found " << needRemove.size() << " redundant instructions to remove" << std::endl;
|
||||
}
|
||||
|
||||
// 删除冗余指令
|
||||
eliminateRedundantInstructions(changed);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " GVN analysis completed for function: " << func->getName() << std::endl;
|
||||
std::cout << " Total values numbered: " << valueToNumber.size() << std::endl;
|
||||
std::cout << " Instructions eliminated: " << needRemove.size() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void GVNContext::computeRPO(Function *func) {
|
||||
rpoBlocks.clear();
|
||||
visited.clear();
|
||||
|
||||
auto entry = func->getEntryBlock();
|
||||
if (entry) {
|
||||
dfs(entry);
|
||||
std::reverse(rpoBlocks.begin(), rpoBlocks.end());
|
||||
}
|
||||
}
|
||||
|
||||
void GVNContext::dfs(BasicBlock *bb) {
|
||||
if (!bb || visited.count(bb)) {
|
||||
return;
|
||||
}
|
||||
|
||||
visited.insert(bb);
|
||||
|
||||
// 访问所有后继基本块
|
||||
for (auto succ : bb->getSuccessors()) {
|
||||
if (visited.find(succ) == visited.end()) {
|
||||
dfs(succ);
|
||||
}
|
||||
}
|
||||
|
||||
rpoBlocks.push_back(bb);
|
||||
}
|
||||
|
||||
unsigned GVNContext::getValueNumber(Value* value) {
|
||||
// 如果已经有值编号,直接返回
|
||||
auto it = valueToNumber.find(value);
|
||||
if (it != valueToNumber.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// 为新值分配编号
|
||||
return assignValueNumber(value);
|
||||
}
|
||||
|
||||
unsigned GVNContext::assignValueNumber(Value* value) {
|
||||
unsigned number = nextValueNumber++;
|
||||
valueToNumber[value] = number;
|
||||
numberToValue[number] = value;
|
||||
|
||||
if (DEBUG >= 2) {
|
||||
std::cout << " Assigned value number " << number
|
||||
<< " to " << value->getName() << std::endl;
|
||||
}
|
||||
|
||||
return number;
|
||||
}
|
||||
|
||||
void GVNContext::processBasicBlock(BasicBlock* bb, bool& changed) {
|
||||
int instCount = 0;
|
||||
for (auto &instPtr : bb->getInstructions()) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Processing instruction " << ++instCount
|
||||
<< ": " << instPtr->getName() << std::endl;
|
||||
}
|
||||
|
||||
if (processInstruction(instPtr.get())) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GVNContext::processInstruction(Instruction* inst) {
|
||||
// 跳过分支指令和其他不可优化的指令
|
||||
if (inst->isBranch() || dynamic_cast<ReturnInst*>(inst) ||
|
||||
dynamic_cast<AllocaInst*>(inst) || dynamic_cast<StoreInst*>(inst)) {
|
||||
|
||||
// 如果是store指令,需要使相关的内存值失效
|
||||
if (auto store = dynamic_cast<StoreInst*>(inst)) {
|
||||
invalidateMemoryValues(store);
|
||||
}
|
||||
|
||||
// 为这些指令分配值编号但不尝试优化
|
||||
getValueNumber(inst);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Processing optimizable instruction: " << inst->getName()
|
||||
<< " (kind: " << static_cast<int>(inst->getKind()) << ")" << std::endl;
|
||||
}
|
||||
|
||||
// 构建表达式键
|
||||
std::string exprKey = buildExpressionKey(inst);
|
||||
if (exprKey.empty()) {
|
||||
// 不可优化的指令,只分配值编号
|
||||
getValueNumber(inst);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG >= 2) {
|
||||
std::cout << " Expression key: " << exprKey << std::endl;
|
||||
}
|
||||
|
||||
// 查找已存在的等价值
|
||||
Value* existing = findExistingValue(exprKey, inst);
|
||||
if (existing && existing != inst) {
|
||||
// 检查支配关系
|
||||
if (auto existingInst = dynamic_cast<Instruction*>(existing)) {
|
||||
if (dominates(existingInst, inst)) {
|
||||
if (DEBUG) {
|
||||
std::cout << " GVN: Replacing " << inst->getName()
|
||||
<< " with existing " << existing->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 用已存在的值替换当前指令
|
||||
inst->replaceAllUsesWith(existing);
|
||||
needRemove.insert(inst);
|
||||
|
||||
// 将当前指令的值编号指向已存在的值
|
||||
unsigned existingNumber = getValueNumber(existing);
|
||||
valueToNumber[inst] = existingNumber;
|
||||
|
||||
return true;
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
std::cout << " Found equivalent but dominance check failed" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 没有找到等价值,为这个表达式分配新的值编号
|
||||
unsigned number = assignValueNumber(inst);
|
||||
expressionToNumber[exprKey] = number;
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Instruction " << inst->getName() << " is unique" << std::endl;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string GVNContext::buildExpressionKey(Instruction* inst) {
|
||||
std::ostringstream oss;
|
||||
|
||||
if (auto binary = dynamic_cast<BinaryInst*>(inst)) {
|
||||
oss << "binary_" << static_cast<int>(binary->getKind()) << "_";
|
||||
oss << getValueNumber(binary->getLhs()) << "_" << getValueNumber(binary->getRhs());
|
||||
|
||||
// 对于可交换操作,确保操作数顺序一致
|
||||
if (binary->isCommutative()) {
|
||||
unsigned lhsNum = getValueNumber(binary->getLhs());
|
||||
unsigned rhsNum = getValueNumber(binary->getRhs());
|
||||
if (lhsNum > rhsNum) {
|
||||
oss.str("");
|
||||
oss << "binary_" << static_cast<int>(binary->getKind()) << "_";
|
||||
oss << rhsNum << "_" << lhsNum;
|
||||
}
|
||||
}
|
||||
} else if (auto unary = dynamic_cast<UnaryInst*>(inst)) {
|
||||
oss << "unary_" << static_cast<int>(unary->getKind()) << "_";
|
||||
oss << getValueNumber(unary->getOperand());
|
||||
} else if (auto gep = dynamic_cast<GetElementPtrInst*>(inst)) {
|
||||
oss << "gep_" << getValueNumber(gep->getBasePointer());
|
||||
for (unsigned i = 0; i < gep->getNumIndices(); ++i) {
|
||||
oss << "_" << getValueNumber(gep->getIndex(i));
|
||||
}
|
||||
} else if (auto load = dynamic_cast<LoadInst*>(inst)) {
|
||||
oss << "load_" << getValueNumber(load->getPointer());
|
||||
oss << "_" << reinterpret_cast<uintptr_t>(load->getType()); // 类型区分
|
||||
} else if (auto call = dynamic_cast<CallInst*>(inst)) {
|
||||
// 只为无副作用的函数调用建立表达式
|
||||
if (sideEffectAnalysis && sideEffectAnalysis->isPureFunction(call->getCallee())) {
|
||||
oss << "call_" << call->getCallee()->getName();
|
||||
for (size_t i = 1; i < call->getNumOperands(); ++i) { // 跳过函数指针
|
||||
oss << "_" << getValueNumber(call->getOperand(i));
|
||||
}
|
||||
} else {
|
||||
return ""; // 有副作用的函数调用不可优化
|
||||
}
|
||||
} else {
|
||||
return ""; // 不支持的指令类型
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
Value* GVNContext::findExistingValue(const std::string& exprKey, Instruction* inst) {
|
||||
auto it = expressionToNumber.find(exprKey);
|
||||
if (it != expressionToNumber.end()) {
|
||||
unsigned number = it->second;
|
||||
auto valueIt = numberToValue.find(number);
|
||||
if (valueIt != numberToValue.end()) {
|
||||
Value* existing = valueIt->second;
|
||||
|
||||
// 对于load指令,需要额外检查内存安全性
|
||||
if (auto loadInst = dynamic_cast<LoadInst*>(inst)) {
|
||||
if (auto existingLoad = dynamic_cast<LoadInst*>(existing)) {
|
||||
if (!isMemorySafe(existingLoad, loadInst)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return existing;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool GVNContext::dominates(Instruction* a, Instruction* b) {
|
||||
auto aBB = a->getParent();
|
||||
auto bBB = b->getParent();
|
||||
|
||||
// 同一基本块内的情况
|
||||
if (aBB == bBB) {
|
||||
auto &insts = aBB->getInstructions();
|
||||
auto aIt = std::find_if(insts.begin(), insts.end(),
|
||||
[a](const auto &ptr) { return ptr.get() == a; });
|
||||
auto bIt = std::find_if(insts.begin(), insts.end(),
|
||||
[b](const auto &ptr) { return ptr.get() == b; });
|
||||
|
||||
if (aIt == insts.end() || bIt == insts.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::distance(insts.begin(), aIt) < std::distance(insts.begin(), bIt);
|
||||
}
|
||||
|
||||
// 不同基本块的情况,使用支配树
|
||||
if (domTree) {
|
||||
auto dominators = domTree->getDominators(bBB);
|
||||
return dominators && dominators->count(aBB);
|
||||
}
|
||||
|
||||
return false; // 保守做法
|
||||
}
|
||||
|
||||
bool GVNContext::isMemorySafe(LoadInst* earlierLoad, LoadInst* laterLoad) {
|
||||
// 检查两个load是否访问相同的内存位置
|
||||
unsigned earlierPtr = getValueNumber(earlierLoad->getPointer());
|
||||
unsigned laterPtr = getValueNumber(laterLoad->getPointer());
|
||||
|
||||
if (earlierPtr != laterPtr) {
|
||||
return false; // 不同的内存位置
|
||||
}
|
||||
|
||||
// 检查类型是否匹配
|
||||
if (earlierLoad->getType() != laterLoad->getType()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 简单情况:如果在同一个基本块且没有中间的store,则安全
|
||||
auto earlierBB = earlierLoad->getParent();
|
||||
auto laterBB = laterLoad->getParent();
|
||||
|
||||
if (earlierBB != laterBB) {
|
||||
// 跨基本块的情况需要更复杂的分析,暂时保守处理
|
||||
return false;
|
||||
}
|
||||
|
||||
// 同一基本块内检查是否有中间的store
|
||||
auto &insts = earlierBB->getInstructions();
|
||||
auto earlierIt = std::find_if(insts.begin(), insts.end(),
|
||||
[earlierLoad](const auto &ptr) { return ptr.get() == earlierLoad; });
|
||||
auto laterIt = std::find_if(insts.begin(), insts.end(),
|
||||
[laterLoad](const auto &ptr) { return ptr.get() == laterLoad; });
|
||||
|
||||
if (earlierIt == insts.end() || laterIt == insts.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 确保earlierLoad真的在laterLoad之前
|
||||
if (std::distance(insts.begin(), earlierIt) >= std::distance(insts.begin(), laterIt)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查中间是否有store指令修改了相同的内存位置
|
||||
for (auto it = std::next(earlierIt); it != laterIt; ++it) {
|
||||
if (auto store = dynamic_cast<StoreInst*>(it->get())) {
|
||||
unsigned storePtr = getValueNumber(store->getPointer());
|
||||
if (storePtr == earlierPtr) {
|
||||
return false; // 找到中间的store
|
||||
}
|
||||
}
|
||||
|
||||
// 检查函数调用是否可能修改内存
|
||||
if (auto call = dynamic_cast<CallInst*>(it->get())) {
|
||||
if (sideEffectAnalysis && !sideEffectAnalysis->isPureFunction(call->getCallee())) {
|
||||
// 保守处理:有副作用的函数可能修改内存
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true; // 安全
|
||||
}
|
||||
|
||||
void GVNContext::invalidateMemoryValues(StoreInst* store) {
|
||||
unsigned storePtr = getValueNumber(store->getPointer());
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Invalidating memory values affected by store" << std::endl;
|
||||
}
|
||||
|
||||
// 找到所有可能被这个store影响的load表达式
|
||||
std::vector<std::string> toRemove;
|
||||
|
||||
for (auto& [exprKey, number] : expressionToNumber) {
|
||||
if (exprKey.find("load_" + std::to_string(storePtr)) == 0) {
|
||||
toRemove.push_back(exprKey);
|
||||
if (DEBUG) {
|
||||
std::cout << " Invalidating expression: " << exprKey << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 移除失效的表达式
|
||||
for (const auto& key : toRemove) {
|
||||
expressionToNumber.erase(key);
|
||||
}
|
||||
}
|
||||
|
||||
void GVNContext::eliminateRedundantInstructions(bool& changed) {
|
||||
int removeCount = 0;
|
||||
for (auto inst : needRemove) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Removing redundant instruction " << ++removeCount
|
||||
<< "/" << needRemove.size() << ": " << inst->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 删除指令前先断开所有使用关系
|
||||
// inst->replaceAllUsesWith 已在 processInstruction 中调用
|
||||
SysYIROptUtils::usedelete(inst);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
897
src/midend/Pass/Optimize/GlobalStrengthReduction.cpp
Normal file
897
src/midend/Pass/Optimize/GlobalStrengthReduction.cpp
Normal file
@@ -0,0 +1,897 @@
|
||||
#include "GlobalStrengthReduction.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include "IRBuilder.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
|
||||
extern int DEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 全局强度削弱优化遍的静态 ID
|
||||
void *GlobalStrengthReduction::ID = (void *)&GlobalStrengthReduction::ID;
|
||||
|
||||
// ======================================================================
|
||||
// GlobalStrengthReduction 类的实现
|
||||
// ======================================================================
|
||||
|
||||
bool GlobalStrengthReduction::runOnFunction(Function *func, AnalysisManager &AM) {
|
||||
if (func->getBasicBlocks().empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "\n=== Running GlobalStrengthReduction on function: " << func->getName() << " ===" << std::endl;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
GlobalStrengthReductionContext context(builder);
|
||||
context.run(func, &AM, changed);
|
||||
|
||||
if (DEBUG) {
|
||||
if (changed) {
|
||||
std::cout << "GlobalStrengthReduction: Function " << func->getName() << " was modified" << std::endl;
|
||||
} else {
|
||||
std::cout << "GlobalStrengthReduction: Function " << func->getName() << " was not modified" << std::endl;
|
||||
}
|
||||
std::cout << "=== GlobalStrengthReduction completed for function: " << func->getName() << " ===" << std::endl;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
void GlobalStrengthReduction::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
|
||||
// 强度削弱依赖副作用分析来判断指令是否可以安全优化
|
||||
analysisDependencies.insert(&SysYSideEffectAnalysisPass::ID);
|
||||
|
||||
// 强度削弱不会使分析失效,因为:
|
||||
// - 只替换计算指令,不改变控制流
|
||||
// - 不修改内存,不影响别名分析
|
||||
// - 保持程序语义不变
|
||||
// analysisInvalidations 保持为空
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "GlobalStrengthReduction: Declared analysis dependencies (SideEffectAnalysis)" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// GlobalStrengthReductionContext 类的实现
|
||||
// ======================================================================
|
||||
|
||||
void GlobalStrengthReductionContext::run(Function *func, AnalysisManager *AM, bool &changed) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Starting GlobalStrengthReduction analysis for function: " << func->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 获取分析结果
|
||||
if (AM) {
|
||||
sideEffectAnalysis = AM->getAnalysisResult<SideEffectAnalysisResult, SysYSideEffectAnalysisPass>();
|
||||
|
||||
if (DEBUG) {
|
||||
if (sideEffectAnalysis) {
|
||||
std::cout << " GlobalStrengthReduction: Using side effect analysis" << std::endl;
|
||||
} else {
|
||||
std::cout << " GlobalStrengthReduction: Warning - side effect analysis not available" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 重置计数器
|
||||
algebraicOptCount = 0;
|
||||
strengthReductionCount = 0;
|
||||
divisionOptCount = 0;
|
||||
|
||||
// 遍历所有基本块进行优化
|
||||
for (auto &bb_ptr : func->getBasicBlocks()) {
|
||||
if (processBasicBlock(bb_ptr.get())) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " GlobalStrengthReduction completed for function: " << func->getName() << std::endl;
|
||||
std::cout << " Algebraic optimizations: " << algebraicOptCount << std::endl;
|
||||
std::cout << " Strength reductions: " << strengthReductionCount << std::endl;
|
||||
std::cout << " Division optimizations: " << divisionOptCount << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
bool GlobalStrengthReductionContext::processBasicBlock(BasicBlock *bb) {
|
||||
bool changed = false;
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Processing block: " << bb->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 收集需要处理的指令(避免迭代器失效)
|
||||
std::vector<Instruction*> instructions;
|
||||
for (auto &inst_ptr : bb->getInstructions()) {
|
||||
instructions.push_back(inst_ptr.get());
|
||||
}
|
||||
|
||||
// 处理每条指令
|
||||
for (auto inst : instructions) {
|
||||
if (processInstruction(inst)) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool GlobalStrengthReductionContext::processInstruction(Instruction *inst) {
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Processing instruction: " << inst->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 先尝试代数优化
|
||||
if (tryAlgebraicOptimization(inst)) {
|
||||
algebraicOptCount++;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 再尝试强度削弱
|
||||
if (tryStrengthReduction(inst)) {
|
||||
strengthReductionCount++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// 代数优化方法
|
||||
// ======================================================================
|
||||
|
||||
bool GlobalStrengthReductionContext::tryAlgebraicOptimization(Instruction *inst) {
|
||||
auto binary = dynamic_cast<BinaryInst*>(inst);
|
||||
if (!binary) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (binary->getKind()) {
|
||||
case Instruction::kAdd:
|
||||
return optimizeAddition(binary);
|
||||
case Instruction::kSub:
|
||||
return optimizeSubtraction(binary);
|
||||
case Instruction::kMul:
|
||||
return optimizeMultiplication(binary);
|
||||
case Instruction::kDiv:
|
||||
return optimizeDivision(binary);
|
||||
case Instruction::kICmpEQ:
|
||||
case Instruction::kICmpNE:
|
||||
case Instruction::kICmpLT:
|
||||
case Instruction::kICmpGT:
|
||||
case Instruction::kICmpLE:
|
||||
case Instruction::kICmpGE:
|
||||
return optimizeComparison(binary);
|
||||
case Instruction::kAnd:
|
||||
case Instruction::kOr:
|
||||
return optimizeLogical(binary);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool GlobalStrengthReductionContext::optimizeAddition(BinaryInst *inst) {
|
||||
Value *lhs = inst->getLhs();
|
||||
Value *rhs = inst->getRhs();
|
||||
int constVal;
|
||||
|
||||
// x + 0 = x
|
||||
if (isConstantInt(rhs, constVal) && constVal == 0) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Algebraic: " << inst->getName() << " = x + 0 -> x" << std::endl;
|
||||
}
|
||||
replaceWithOptimized(inst, lhs);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0 + x = x
|
||||
if (isConstantInt(lhs, constVal) && constVal == 0) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Algebraic: " << inst->getName() << " = 0 + x -> x" << std::endl;
|
||||
}
|
||||
replaceWithOptimized(inst, rhs);
|
||||
return true;
|
||||
}
|
||||
|
||||
// x + (-y) = x - y
|
||||
if (auto rhsInst = dynamic_cast<UnaryInst*>(rhs)) {
|
||||
if (rhsInst->getKind() == Instruction::kNeg) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Algebraic: " << inst->getName() << " = x + (-y) -> x - y" << std::endl;
|
||||
}
|
||||
// 创建减法指令
|
||||
builder->setPosition(inst->getParent(), inst->getParent()->findInstIterator(inst));
|
||||
auto subInst = builder->createSubInst(lhs, rhsInst->getOperand());
|
||||
replaceWithOptimized(inst, subInst);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GlobalStrengthReductionContext::optimizeSubtraction(BinaryInst *inst) {
|
||||
Value *lhs = inst->getLhs();
|
||||
Value *rhs = inst->getRhs();
|
||||
int constVal;
|
||||
|
||||
// x - 0 = x
|
||||
if (isConstantInt(rhs, constVal) && constVal == 0) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Algebraic: " << inst->getName() << " = x - 0 -> x" << std::endl;
|
||||
}
|
||||
replaceWithOptimized(inst, lhs);
|
||||
return true;
|
||||
}
|
||||
|
||||
// x - x = 0 (如果x没有副作用)
|
||||
if (lhs == rhs && hasOnlyLocalUses(dynamic_cast<Instruction*>(lhs))) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Algebraic: " << inst->getName() << " = x - x -> 0" << std::endl;
|
||||
}
|
||||
replaceWithOptimized(inst, getConstantInt(0));
|
||||
return true;
|
||||
}
|
||||
|
||||
// x - (-y) = x + y
|
||||
if (auto rhsInst = dynamic_cast<UnaryInst*>(rhs)) {
|
||||
if (rhsInst->getKind() == Instruction::kNeg) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Algebraic: " << inst->getName() << " = x - (-y) -> x + y" << std::endl;
|
||||
}
|
||||
builder->setPosition(inst->getParent(), inst->getParent()->findInstIterator(inst));
|
||||
auto addInst = builder->createAddInst(lhs, rhsInst->getOperand());
|
||||
replaceWithOptimized(inst, addInst);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GlobalStrengthReductionContext::optimizeMultiplication(BinaryInst *inst) {
|
||||
Value *lhs = inst->getLhs();
|
||||
Value *rhs = inst->getRhs();
|
||||
int constVal;
|
||||
|
||||
// x * 0 = 0
|
||||
if (isConstantInt(rhs, constVal) && constVal == 0) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Algebraic: " << inst->getName() << " = x * 0 -> 0" << std::endl;
|
||||
}
|
||||
replaceWithOptimized(inst, getConstantInt(0));
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0 * x = 0
|
||||
if (isConstantInt(lhs, constVal) && constVal == 0) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Algebraic: " << inst->getName() << " = 0 * x -> 0" << std::endl;
|
||||
}
|
||||
replaceWithOptimized(inst, getConstantInt(0));
|
||||
return true;
|
||||
}
|
||||
|
||||
// x * 1 = x
|
||||
if (isConstantInt(rhs, constVal) && constVal == 1) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Algebraic: " << inst->getName() << " = x * 1 -> x" << std::endl;
|
||||
}
|
||||
replaceWithOptimized(inst, lhs);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 1 * x = x
|
||||
if (isConstantInt(lhs, constVal) && constVal == 1) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Algebraic: " << inst->getName() << " = 1 * x -> x" << std::endl;
|
||||
}
|
||||
replaceWithOptimized(inst, rhs);
|
||||
return true;
|
||||
}
|
||||
|
||||
// x * (-1) = -x
|
||||
if (isConstantInt(rhs, constVal) && constVal == -1) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Algebraic: " << inst->getName() << " = x * (-1) -> -x" << std::endl;
|
||||
}
|
||||
builder->setPosition(inst->getParent(), inst->getParent()->findInstIterator(inst));
|
||||
auto negInst = builder->createNegInst(lhs);
|
||||
replaceWithOptimized(inst, negInst);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GlobalStrengthReductionContext::optimizeDivision(BinaryInst *inst) {
|
||||
Value *lhs = inst->getLhs();
|
||||
Value *rhs = inst->getRhs();
|
||||
int constVal;
|
||||
|
||||
// x / 1 = x
|
||||
if (isConstantInt(rhs, constVal) && constVal == 1) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Algebraic: " << inst->getName() << " = x / 1 -> x" << std::endl;
|
||||
}
|
||||
replaceWithOptimized(inst, lhs);
|
||||
return true;
|
||||
}
|
||||
|
||||
// x / (-1) = -x
|
||||
if (isConstantInt(rhs, constVal) && constVal == -1) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Algebraic: " << inst->getName() << " = x / (-1) -> -x" << std::endl;
|
||||
}
|
||||
builder->setPosition(inst->getParent(), inst->getParent()->findInstIterator(inst));
|
||||
auto negInst = builder->createNegInst(lhs);
|
||||
replaceWithOptimized(inst, negInst);
|
||||
return true;
|
||||
}
|
||||
|
||||
// x / x = 1 (如果x != 0且没有副作用)
|
||||
if (lhs == rhs && hasOnlyLocalUses(dynamic_cast<Instruction*>(lhs))) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Algebraic: " << inst->getName() << " = x / x -> 1" << std::endl;
|
||||
}
|
||||
replaceWithOptimized(inst, getConstantInt(1));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GlobalStrengthReductionContext::optimizeComparison(BinaryInst *inst) {
|
||||
Value *lhs = inst->getLhs();
|
||||
Value *rhs = inst->getRhs();
|
||||
|
||||
// x == x = true (如果x没有副作用)
|
||||
if (inst->getKind() == Instruction::kICmpEQ && lhs == rhs &&
|
||||
hasOnlyLocalUses(dynamic_cast<Instruction*>(lhs))) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Algebraic: " << inst->getName() << " = x == x -> true" << std::endl;
|
||||
}
|
||||
replaceWithOptimized(inst, getConstantInt(1));
|
||||
return true;
|
||||
}
|
||||
|
||||
// x != x = false (如果x没有副作用)
|
||||
if (inst->getKind() == Instruction::kICmpNE && lhs == rhs &&
|
||||
hasOnlyLocalUses(dynamic_cast<Instruction*>(lhs))) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Algebraic: " << inst->getName() << " = x != x -> false" << std::endl;
|
||||
}
|
||||
replaceWithOptimized(inst, getConstantInt(0));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GlobalStrengthReductionContext::optimizeLogical(BinaryInst *inst) {
|
||||
Value *lhs = inst->getLhs();
|
||||
Value *rhs = inst->getRhs();
|
||||
int constVal;
|
||||
|
||||
if (inst->getKind() == Instruction::kAnd) {
|
||||
// x && 0 = 0
|
||||
if (isConstantInt(rhs, constVal) && constVal == 0) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Algebraic: " << inst->getName() << " = x && 0 -> 0" << std::endl;
|
||||
}
|
||||
replaceWithOptimized(inst, getConstantInt(0));
|
||||
return true;
|
||||
}
|
||||
|
||||
// x && -1 = x
|
||||
if (isConstantInt(rhs, constVal) && constVal == -1) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Algebraic: " << inst->getName() << " = x && 1 -> x" << std::endl;
|
||||
}
|
||||
replaceWithOptimized(inst, lhs);
|
||||
return true;
|
||||
}
|
||||
|
||||
// x && x = x
|
||||
if (lhs == rhs) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Algebraic: " << inst->getName() << " = x && x -> x" << std::endl;
|
||||
}
|
||||
replaceWithOptimized(inst, lhs);
|
||||
return true;
|
||||
}
|
||||
} else if (inst->getKind() == Instruction::kOr) {
|
||||
// x || 0 = x
|
||||
if (isConstantInt(rhs, constVal) && constVal == 0) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Algebraic: " << inst->getName() << " = x || 0 -> x" << std::endl;
|
||||
}
|
||||
replaceWithOptimized(inst, lhs);
|
||||
return true;
|
||||
}
|
||||
|
||||
// x || x = x
|
||||
if (lhs == rhs) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Algebraic: " << inst->getName() << " = x || x -> x" << std::endl;
|
||||
}
|
||||
replaceWithOptimized(inst, lhs);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// 强度削弱方法
|
||||
// ======================================================================
|
||||
|
||||
bool GlobalStrengthReductionContext::tryStrengthReduction(Instruction *inst) {
|
||||
if (auto binary = dynamic_cast<BinaryInst*>(inst)) {
|
||||
switch (binary->getKind()) {
|
||||
case Instruction::kMul:
|
||||
return reduceMultiplication(binary);
|
||||
case Instruction::kDiv:
|
||||
return reduceDivision(binary);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} else if (auto call = dynamic_cast<CallInst*>(inst)) {
|
||||
return reducePower(call);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GlobalStrengthReductionContext::reduceMultiplication(BinaryInst *inst) {
|
||||
Value *lhs = inst->getLhs();
|
||||
Value *rhs = inst->getRhs();
|
||||
int constVal;
|
||||
|
||||
// 尝试右操作数为常数
|
||||
Value* variable = lhs;
|
||||
if (isConstantInt(rhs, constVal) && constVal > 0) {
|
||||
return tryComplexMultiplication(inst, variable, constVal);
|
||||
}
|
||||
|
||||
// 尝试左操作数为常数
|
||||
if (isConstantInt(lhs, constVal) && constVal > 0) {
|
||||
variable = rhs;
|
||||
return tryComplexMultiplication(inst, variable, constVal);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GlobalStrengthReductionContext::tryComplexMultiplication(BinaryInst* inst, Value* variable, int constant) {
|
||||
// 首先检查是否为2的幂,使用简单位移
|
||||
if (isPowerOfTwo(constant)) {
|
||||
int shiftAmount = log2OfPowerOfTwo(constant);
|
||||
if (DEBUG) {
|
||||
std::cout << " StrengthReduction: " << inst->getName()
|
||||
<< " = x * " << constant << " -> x << " << shiftAmount << std::endl;
|
||||
}
|
||||
|
||||
builder->setPosition(inst->getParent(), inst->getParent()->findInstIterator(inst));
|
||||
auto shiftInst = builder->createBinaryInst(Instruction::kSll, Type::getIntType(), variable, getConstantInt(shiftAmount));
|
||||
replaceWithOptimized(inst, shiftInst);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 尝试分解为位移和加法的组合
|
||||
std::vector<int> shifts;
|
||||
if (findOptimalShiftDecomposition(constant, shifts)) {
|
||||
if (DEBUG) {
|
||||
std::cout << " StrengthReduction: " << inst->getName()
|
||||
<< " = x * " << constant << " -> shift decomposition with " << shifts.size() << " terms" << std::endl;
|
||||
}
|
||||
|
||||
Value* result = createShiftDecomposition(inst, variable, shifts);
|
||||
if (result) {
|
||||
replaceWithOptimized(inst, result);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GlobalStrengthReductionContext::findOptimalShiftDecomposition(int constant, std::vector<int>& shifts) {
|
||||
shifts.clear();
|
||||
|
||||
// 常见的有效分解模式
|
||||
switch (constant) {
|
||||
case 3: // 3 = 2^1 + 2^0 -> (x << 1) + x
|
||||
shifts = {1, 0};
|
||||
return true;
|
||||
case 5: // 5 = 2^2 + 2^0 -> (x << 2) + x
|
||||
shifts = {2, 0};
|
||||
return true;
|
||||
case 6: // 6 = 2^2 + 2^1 -> (x << 2) + (x << 1)
|
||||
shifts = {2, 1};
|
||||
return true;
|
||||
case 7: // 7 = 2^2 + 2^1 + 2^0 -> (x << 2) + (x << 1) + x
|
||||
shifts = {2, 1, 0};
|
||||
return true;
|
||||
case 9: // 9 = 2^3 + 2^0 -> (x << 3) + x
|
||||
shifts = {3, 0};
|
||||
return true;
|
||||
case 10: // 10 = 2^3 + 2^1 -> (x << 3) + (x << 1)
|
||||
shifts = {3, 1};
|
||||
return true;
|
||||
case 11: // 11 = 2^3 + 2^1 + 2^0 -> (x << 3) + (x << 1) + x
|
||||
shifts = {3, 1, 0};
|
||||
return true;
|
||||
case 12: // 12 = 2^3 + 2^2 -> (x << 3) + (x << 2)
|
||||
shifts = {3, 2};
|
||||
return true;
|
||||
case 13: // 13 = 2^3 + 2^2 + 2^0 -> (x << 3) + (x << 2) + x
|
||||
shifts = {3, 2, 0};
|
||||
return true;
|
||||
case 14: // 14 = 2^3 + 2^2 + 2^1 -> (x << 3) + (x << 2) + (x << 1)
|
||||
shifts = {3, 2, 1};
|
||||
return true;
|
||||
case 15: // 15 = 2^3 + 2^2 + 2^1 + 2^0 -> (x << 3) + (x << 2) + (x << 1) + x
|
||||
shifts = {3, 2, 1, 0};
|
||||
return true;
|
||||
case 17: // 17 = 2^4 + 2^0 -> (x << 4) + x
|
||||
shifts = {4, 0};
|
||||
return true;
|
||||
case 18: // 18 = 2^4 + 2^1 -> (x << 4) + (x << 1)
|
||||
shifts = {4, 1};
|
||||
return true;
|
||||
case 20: // 20 = 2^4 + 2^2 -> (x << 4) + (x << 2)
|
||||
shifts = {4, 2};
|
||||
return true;
|
||||
case 24: // 24 = 2^4 + 2^3 -> (x << 4) + (x << 3)
|
||||
shifts = {4, 3};
|
||||
return true;
|
||||
case 25: // 25 = 2^4 + 2^3 + 2^0 -> (x << 4) + (x << 3) + x
|
||||
shifts = {4, 3, 0};
|
||||
return true;
|
||||
case 100: // 100 = 2^6 + 2^5 + 2^2 -> (x << 6) + (x << 5) + (x << 2)
|
||||
shifts = {6, 5, 2};
|
||||
return true;
|
||||
}
|
||||
|
||||
// 通用二进制分解(最多4个项,避免过度复杂化)
|
||||
if (constant > 0 && constant < 256) {
|
||||
std::vector<int> binaryShifts;
|
||||
int temp = constant;
|
||||
int bit = 0;
|
||||
|
||||
while (temp > 0 && binaryShifts.size() < 4) {
|
||||
if (temp & 1) {
|
||||
binaryShifts.push_back(bit);
|
||||
}
|
||||
temp >>= 1;
|
||||
bit++;
|
||||
}
|
||||
|
||||
// 只有当项数不超过3个时才使用二进制分解(比直接乘法更有效)
|
||||
if (binaryShifts.size() <= 3 && binaryShifts.size() >= 2) {
|
||||
shifts = binaryShifts;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Value* GlobalStrengthReductionContext::createShiftDecomposition(BinaryInst* inst, Value* variable, const std::vector<int>& shifts) {
|
||||
if (shifts.empty()) return nullptr;
|
||||
|
||||
builder->setPosition(inst->getParent(), inst->getParent()->findInstIterator(inst));
|
||||
|
||||
Value* result = nullptr;
|
||||
|
||||
for (int shift : shifts) {
|
||||
Value* term;
|
||||
if (shift == 0) {
|
||||
// 0位移就是原变量
|
||||
term = variable;
|
||||
} else {
|
||||
// 创建位移指令
|
||||
term = builder->createBinaryInst(Instruction::kSll, Type::getIntType(), variable, getConstantInt(shift));
|
||||
}
|
||||
|
||||
if (result == nullptr) {
|
||||
result = term;
|
||||
} else {
|
||||
// 累加到结果中
|
||||
result = builder->createAddInst(result, term);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool GlobalStrengthReductionContext::reduceDivision(BinaryInst *inst) {
|
||||
Value *lhs = inst->getLhs();
|
||||
Value *rhs = inst->getRhs();
|
||||
uint32_t constVal;
|
||||
|
||||
// x / 2^n = x >> n (对于无符号除法或已知为正数的情况)
|
||||
if (isConstantInt(rhs, constVal) && constVal > 0 && isPowerOfTwo(constVal)) {
|
||||
builder->setPosition(inst->getParent(), inst->getParent()->findInstIterator(inst));
|
||||
int shiftAmount = log2OfPowerOfTwo(constVal);
|
||||
// 有符号除法校正:(x + (x >> 31) & mask) >> k
|
||||
int maskValue = constVal - 1;
|
||||
|
||||
// x >> 31 (算术右移获取符号位)
|
||||
Value* signShift = ConstantInteger::get(31);
|
||||
Value* signBits = builder->createBinaryInst(
|
||||
Instruction::Kind::kSra, // 算术右移
|
||||
lhs->getType(),
|
||||
lhs,
|
||||
signShift
|
||||
);
|
||||
|
||||
// (x >> 31) & mask
|
||||
Value* mask = ConstantInteger::get(maskValue);
|
||||
Value* correction = builder->createBinaryInst(
|
||||
Instruction::Kind::kAnd,
|
||||
lhs->getType(),
|
||||
signBits,
|
||||
mask
|
||||
);
|
||||
|
||||
// x + correction
|
||||
Value* corrected = builder->createAddInst(lhs, correction);
|
||||
|
||||
// (x + correction) >> k
|
||||
Value* divShift = ConstantInteger::get(shiftAmount);
|
||||
Value* shiftInst = builder->createBinaryInst(
|
||||
Instruction::Kind::kSra, // 算术右移
|
||||
lhs->getType(),
|
||||
corrected,
|
||||
divShift
|
||||
);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " StrengthReduction: " << inst->getName()
|
||||
<< " = x / " << constVal << " -> (x + (x >> 31) & mask) >> " << shiftAmount << std::endl;
|
||||
}
|
||||
|
||||
// builder->setPosition(inst->getParent(), inst->getParent()->findInstIterator(inst));
|
||||
// Value* divisor_minus_1 = ConstantInteger::get(constVal - 1);
|
||||
// Value* adjusted = builder->createAddInst(lhs, divisor_minus_1);
|
||||
// Value* shiftInst = builder->createBinaryInst(Instruction::kSra, Type::getIntType(), adjusted, getConstantInt(shiftAmount));
|
||||
replaceWithOptimized(inst, shiftInst);
|
||||
strengthReductionCount++;
|
||||
return true;
|
||||
}
|
||||
|
||||
// x / c = x * magic_number (魔数乘法优化 - 使用libdivide算法)
|
||||
if (isConstantInt(rhs, constVal) && constVal > 1 && constVal != (uint32_t)(-1)) {
|
||||
// auto magicPair = computeMulhMagicNumbers(static_cast<int>(constVal));
|
||||
Value* magicResult = createMagicDivisionLibdivide(inst, static_cast<int>(constVal));
|
||||
replaceWithOptimized(inst, magicResult);
|
||||
divisionOptCount++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GlobalStrengthReductionContext::reducePower(CallInst *inst) {
|
||||
// 检查是否是pow函数调用
|
||||
Function* callee = inst->getCallee();
|
||||
if (!callee || callee->getName() != "pow") {
|
||||
return false;
|
||||
}
|
||||
|
||||
// pow(x, 2) = x * x
|
||||
if (inst->getNumOperands() >= 2) {
|
||||
int exponent;
|
||||
if (isConstantInt(inst->getOperand(1), exponent)) {
|
||||
if (exponent == 2) {
|
||||
if (DEBUG) {
|
||||
std::cout << " StrengthReduction: pow(x, 2) -> x * x" << std::endl;
|
||||
}
|
||||
|
||||
Value* base = inst->getOperand(0);
|
||||
builder->setPosition(inst->getParent(), inst->getParent()->findInstIterator(inst));
|
||||
auto mulInst = builder->createMulInst(base, base);
|
||||
replaceWithOptimized(inst, mulInst);
|
||||
strengthReductionCount++;
|
||||
return true;
|
||||
} else if (exponent >= 3 && exponent <= 8) {
|
||||
// 对于小的指数,展开为连续乘法
|
||||
if (DEBUG) {
|
||||
std::cout << " StrengthReduction: pow(x, " << exponent << ") -> repeated multiplication" << std::endl;
|
||||
}
|
||||
|
||||
Value* base = inst->getOperand(0);
|
||||
Value* result = base;
|
||||
builder->setPosition(inst->getParent(), inst->getParent()->findInstIterator(inst));
|
||||
|
||||
for (int i = 1; i < exponent; i++) {
|
||||
result = builder->createMulInst(result, base);
|
||||
}
|
||||
|
||||
replaceWithOptimized(inst, result);
|
||||
strengthReductionCount++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Value* GlobalStrengthReductionContext::createMagicDivisionLibdivide(BinaryInst* divInst, int divisor) {
|
||||
builder->setPosition(divInst->getParent(), divInst->getParent()->findInstIterator(divInst));
|
||||
// 使用mulh指令优化任意常数除法
|
||||
auto [magic, shift] = SysYIROptUtils::computeMulhMagicNumbers(divisor);
|
||||
|
||||
// 检查是否无法优化(magic == -1, shift == -1 表示失败)
|
||||
if (magic == -1 && shift == -1) {
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Cannot optimize division by " << divisor
|
||||
<< ", keeping original division" << std::endl;
|
||||
}
|
||||
// 返回 nullptr 表示无法优化,调用方应该保持原始除法
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 2的幂次方除法可以用移位优化(但这不是魔数法的情况)这种情况应该不会被分类到这里但是还是做一个保护措施
|
||||
if ((divisor & (divisor - 1)) == 0 && divisor > 0) {
|
||||
// 是2的幂次方,可以用移位
|
||||
int shift_amount = 0;
|
||||
int temp = divisor;
|
||||
while (temp > 1) {
|
||||
temp >>= 1;
|
||||
shift_amount++;
|
||||
}
|
||||
|
||||
Value* shiftConstant = ConstantInteger::get(shift_amount);
|
||||
// 对于有符号除法,需要先加上除数-1然后再移位(为了正确处理负数舍入)
|
||||
Value* divisor_minus_1 = ConstantInteger::get(divisor - 1);
|
||||
Value* adjusted = builder->createAddInst(divInst->getOperand(0), divisor_minus_1);
|
||||
return builder->createBinaryInst(
|
||||
Instruction::Kind::kSra, // 算术右移
|
||||
divInst->getOperand(0)->getType(),
|
||||
adjusted,
|
||||
shiftConstant
|
||||
);
|
||||
}
|
||||
|
||||
// 创建魔数常量
|
||||
// 检查魔数是否能放入32位,如果不能,则不进行优化
|
||||
if (magic > INT32_MAX || magic < INT32_MIN) {
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Magic number " << magic << " exceeds 32-bit range, skipping optimization" << std::endl;
|
||||
}
|
||||
return nullptr; // 无法优化,保持原始除法
|
||||
}
|
||||
|
||||
Value* magicConstant = ConstantInteger::get((int32_t)magic);
|
||||
|
||||
// 检查是否需要ADD_MARKER处理(加法调整)
|
||||
bool needAdd = (shift & 0x40) != 0;
|
||||
int actualShift = shift & 0x3F; // 提取真实的移位量
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] IR Generation: magic=" << magic << ", needAdd=" << needAdd
|
||||
<< ", actualShift=" << actualShift << std::endl;
|
||||
}
|
||||
|
||||
// 执行高位乘法:mulh(x, magic)
|
||||
Value* mulhResult = builder->createBinaryInst(
|
||||
Instruction::Kind::kMulh, // 高位乘法
|
||||
divInst->getOperand(0)->getType(),
|
||||
divInst->getOperand(0),
|
||||
magicConstant
|
||||
);
|
||||
|
||||
if (needAdd) {
|
||||
// ADD_MARKER 情况:需要在移位前加上被除数
|
||||
// 这对应于 libdivide 的加法调整算法
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Applying ADD_MARKER: adding dividend before shift" << std::endl;
|
||||
}
|
||||
mulhResult = builder->createAddInst(mulhResult, divInst->getOperand(0));
|
||||
}
|
||||
|
||||
if (actualShift > 0) {
|
||||
// 如果需要额外移位
|
||||
Value* shiftConstant = ConstantInteger::get(actualShift);
|
||||
mulhResult = builder->createBinaryInst(
|
||||
Instruction::Kind::kSra, // 算术右移
|
||||
divInst->getOperand(0)->getType(),
|
||||
mulhResult,
|
||||
shiftConstant
|
||||
);
|
||||
}
|
||||
|
||||
// 标准的有符号除法符号修正:如果被除数为负,商需要加1
|
||||
// 这对所有有符号除法都需要,不管是否可能有负数
|
||||
Value* isNegative = builder->createICmpLTInst(divInst->getOperand(0), ConstantInteger::get(0));
|
||||
// 将i1转换为i32:负数时为1,非负数时为0 ICmpLTInst的结果会默认转化为32位
|
||||
mulhResult = builder->createAddInst(mulhResult, isNegative);
|
||||
|
||||
return mulhResult;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// 辅助方法
|
||||
// ======================================================================
|
||||
|
||||
bool GlobalStrengthReductionContext::isPowerOfTwo(uint32_t n) {
|
||||
return n > 0 && (n & (n - 1)) == 0;
|
||||
}
|
||||
|
||||
int GlobalStrengthReductionContext::log2OfPowerOfTwo(uint32_t n) {
|
||||
int result = 0;
|
||||
while (n > 1) {
|
||||
n >>= 1;
|
||||
result++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool GlobalStrengthReductionContext::isConstantInt(Value* val, int& constVal) {
|
||||
if (auto constInt = dynamic_cast<ConstantInteger*>(val)) {
|
||||
constVal = std::get<int>(constInt->getVal());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GlobalStrengthReductionContext::isConstantInt(Value* val, uint32_t& constVal) {
|
||||
if (auto constInt = dynamic_cast<ConstantInteger*>(val)) {
|
||||
int signedVal = std::get<int>(constInt->getVal());
|
||||
if (signedVal >= 0) {
|
||||
constVal = static_cast<uint32_t>(signedVal);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ConstantInteger* GlobalStrengthReductionContext::getConstantInt(int val) {
|
||||
return ConstantInteger::get(val);
|
||||
}
|
||||
|
||||
bool GlobalStrengthReductionContext::hasOnlyLocalUses(Instruction* inst) {
|
||||
if (!inst) return true;
|
||||
|
||||
// 简单检查:如果指令没有副作用,则认为是本地的
|
||||
if (sideEffectAnalysis) {
|
||||
auto sideEffect = sideEffectAnalysis->getInstructionSideEffect(inst);
|
||||
return sideEffect.type == SideEffectType::NO_SIDE_EFFECT;
|
||||
}
|
||||
|
||||
// 没有副作用分析时,保守处理
|
||||
return !inst->isCall() && !inst->isStore() && !inst->isLoad();
|
||||
}
|
||||
|
||||
void GlobalStrengthReductionContext::replaceWithOptimized(Instruction* original, Value* replacement) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Replacing " << original->getName()
|
||||
<< " with " << replacement->getName() << std::endl;
|
||||
}
|
||||
|
||||
original->replaceAllUsesWith(replacement);
|
||||
|
||||
// 如果替换值是新创建的指令,确保它有合适的名字
|
||||
// if (auto replInst = dynamic_cast<Instruction*>(replacement)) {
|
||||
// if (replInst->getName().empty()) {
|
||||
// replInst->setName(original->getName() + "_opt");
|
||||
// }
|
||||
// }
|
||||
|
||||
// 删除原指令,让调用者处理
|
||||
SysYIROptUtils::usedelete(original);
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
916
src/midend/Pass/Optimize/InductionVariableElimination.cpp
Normal file
916
src/midend/Pass/Optimize/InductionVariableElimination.cpp
Normal file
@@ -0,0 +1,916 @@
|
||||
#include "InductionVariableElimination.h"
|
||||
#include "LoopCharacteristics.h"
|
||||
#include "Loop.h"
|
||||
#include "Dom.h"
|
||||
#include "SideEffectAnalysis.h"
|
||||
#include "AliasAnalysis.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
// 使用全局调试开关
|
||||
extern int DEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 定义 Pass 的唯一 ID
|
||||
void *InductionVariableElimination::ID = (void *)&InductionVariableElimination::ID;
|
||||
|
||||
bool InductionVariableElimination::runOnFunction(Function* F, AnalysisManager& AM) {
|
||||
if (F->getBasicBlocks().empty()) {
|
||||
return false; // 空函数
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "Running InductionVariableElimination on function: " << F->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 创建优化上下文并运行
|
||||
InductionVariableEliminationContext context;
|
||||
bool modified = context.run(F, AM);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "InductionVariableElimination " << (modified ? "modified" : "did not modify")
|
||||
<< " function: " << F->getName() << std::endl;
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
void InductionVariableElimination::getAnalysisUsage(std::set<void*>& analysisDependencies,
|
||||
std::set<void*>& analysisInvalidations) const {
|
||||
// 依赖的分析
|
||||
analysisDependencies.insert(&LoopAnalysisPass::ID);
|
||||
analysisDependencies.insert(&LoopCharacteristicsPass::ID);
|
||||
analysisDependencies.insert(&DominatorTreeAnalysisPass::ID);
|
||||
analysisDependencies.insert(&SysYSideEffectAnalysisPass::ID);
|
||||
analysisDependencies.insert(&SysYAliasAnalysisPass::ID);
|
||||
|
||||
// 会使失效的分析(归纳变量消除会修改IR结构)
|
||||
analysisInvalidations.insert(&LoopCharacteristicsPass::ID);
|
||||
// 注意:支配树分析通常不会因为归纳变量消除而失效,因为我们不改变控制流
|
||||
}
|
||||
|
||||
// ========== InductionVariableEliminationContext 实现 ==========
|
||||
|
||||
bool InductionVariableEliminationContext::run(Function* F, AnalysisManager& AM) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Starting induction variable elimination analysis..." << std::endl;
|
||||
}
|
||||
|
||||
// 获取必要的分析结果
|
||||
loopAnalysis = AM.getAnalysisResult<LoopAnalysisResult, LoopAnalysisPass>(F);
|
||||
if (!loopAnalysis || !loopAnalysis->hasLoops()) {
|
||||
if (DEBUG) {
|
||||
std::cout << " No loops found, skipping induction variable elimination" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
loopCharacteristics = AM.getAnalysisResult<LoopCharacteristicsResult, LoopCharacteristicsPass>(F);
|
||||
if (!loopCharacteristics) {
|
||||
if (DEBUG) {
|
||||
std::cout << " LoopCharacteristics analysis not available" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
dominatorTree = AM.getAnalysisResult<DominatorTree, DominatorTreeAnalysisPass>(F);
|
||||
if (!dominatorTree) {
|
||||
if (DEBUG) {
|
||||
std::cout << " DominatorTree analysis not available" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
sideEffectAnalysis = AM.getAnalysisResult<SideEffectAnalysisResult, SysYSideEffectAnalysisPass>();
|
||||
if (!sideEffectAnalysis) {
|
||||
if (DEBUG) {
|
||||
std::cout << " SideEffectAnalysis not available, using conservative approach" << std::endl;
|
||||
}
|
||||
// 可以继续执行,但会使用更保守的策略
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
std::cout << " Using SideEffectAnalysis for safety checks" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
aliasAnalysis = AM.getAnalysisResult<AliasAnalysisResult, SysYAliasAnalysisPass>(F);
|
||||
if (!aliasAnalysis) {
|
||||
if (DEBUG) {
|
||||
std::cout << " AliasAnalysis not available, using conservative approach" << std::endl;
|
||||
}
|
||||
// 可以继续执行,但会使用更保守的策略
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
std::cout << " Using AliasAnalysis for memory safety checks" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 执行三个阶段的优化
|
||||
|
||||
// 阶段1:识别死归纳变量
|
||||
identifyDeadInductionVariables(F);
|
||||
|
||||
if (deadIVs.empty()) {
|
||||
if (DEBUG) {
|
||||
std::cout << " No dead induction variables found" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Found " << deadIVs.size() << " potentially dead induction variables" << std::endl;
|
||||
}
|
||||
|
||||
// 阶段2:分析安全性
|
||||
analyzeSafetyForElimination();
|
||||
|
||||
// 阶段3:执行消除
|
||||
bool modified = performInductionVariableElimination();
|
||||
|
||||
if (DEBUG) {
|
||||
printDebugInfo();
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
void InductionVariableEliminationContext::identifyDeadInductionVariables(Function* F) {
|
||||
if (DEBUG) {
|
||||
std::cout << " === Phase 1: Identifying Dead Induction Variables ===" << std::endl;
|
||||
}
|
||||
|
||||
// 遍历所有循环
|
||||
for (const auto& loop_ptr : loopAnalysis->getAllLoops()) {
|
||||
Loop* loop = loop_ptr.get();
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Analyzing loop: " << loop->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 获取循环特征
|
||||
const LoopCharacteristics* characteristics = loopCharacteristics->getCharacteristics(loop);
|
||||
if (!characteristics) {
|
||||
if (DEBUG) {
|
||||
std::cout << " No characteristics available for loop" << std::endl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (characteristics->InductionVars.empty()) {
|
||||
if (DEBUG) {
|
||||
std::cout << " No induction variables found in loop" << std::endl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查每个归纳变量是否为死归纳变量
|
||||
for (const auto& iv : characteristics->InductionVars) {
|
||||
auto deadIV = isDeadInductionVariable(iv.get(), loop);
|
||||
if (deadIV) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Found potential dead IV: %" << deadIV->phiInst->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 添加到候选项列表
|
||||
loopToDeadIVs[loop].push_back(deadIV.get());
|
||||
deadIVs.push_back(std::move(deadIV));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " === End Phase 1: Found " << deadIVs.size() << " candidates ===" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<DeadInductionVariable>
|
||||
InductionVariableEliminationContext::isDeadInductionVariable(const InductionVarInfo* iv, Loop* loop) {
|
||||
// 获取 phi 指令
|
||||
auto* phiInst = dynamic_cast<PhiInst*>(iv->div);
|
||||
if (!phiInst) {
|
||||
return nullptr; // 不是 phi 指令
|
||||
}
|
||||
|
||||
// 新的逻辑:递归分析整个use-def链,判断是否有真实的使用
|
||||
if (!isPhiInstructionDeadRecursively(phiInst, loop)) {
|
||||
return nullptr; // 有真实的使用,不能删除
|
||||
}
|
||||
|
||||
// 创建死归纳变量信息
|
||||
auto deadIV = std::make_unique<DeadInductionVariable>(phiInst, loop);
|
||||
deadIV->relatedInsts = collectRelatedInstructions(phiInst, loop);
|
||||
|
||||
return deadIV;
|
||||
}
|
||||
|
||||
// 递归分析phi指令及其使用链是否都是死代码
|
||||
bool InductionVariableEliminationContext::isPhiInstructionDeadRecursively(PhiInst* phiInst, Loop* loop) {
|
||||
if (DEBUG) {
|
||||
std::cout << " 递归分析归纳变量 " << phiInst->getName() << " 的完整使用链" << std::endl;
|
||||
}
|
||||
|
||||
// 使用访问集合避免无限递归
|
||||
std::set<Instruction*> visitedInstructions;
|
||||
std::set<Instruction*> currentPath; // 用于检测循环依赖
|
||||
|
||||
// 核心逻辑:递归分析使用链,寻找任何"逃逸点"
|
||||
return isInstructionUseChainDeadRecursively(phiInst, loop, visitedInstructions, currentPath);
|
||||
}
|
||||
|
||||
// 递归分析指令的使用链是否都是死代码
|
||||
bool InductionVariableEliminationContext::isInstructionUseChainDeadRecursively(
|
||||
Instruction* inst, Loop* loop,
|
||||
std::set<Instruction*>& visited,
|
||||
std::set<Instruction*>& currentPath) {
|
||||
|
||||
if (DEBUG && visited.size() < 10) { // 限制debug输出
|
||||
std::cout << " 分析指令 " << inst->getName() << " (" << inst->getKindString() << ")" << std::endl;
|
||||
}
|
||||
|
||||
// 避免无限递归
|
||||
if (currentPath.count(inst) > 0) {
|
||||
// 发现循环依赖,这在归纳变量中是正常的,继续分析其他路径
|
||||
if (DEBUG && visited.size() < 10) {
|
||||
std::cout << " 发现循环依赖,继续分析其他路径" << std::endl;
|
||||
}
|
||||
return true; // 循环依赖本身不是逃逸点
|
||||
}
|
||||
|
||||
if (visited.count(inst) > 0) {
|
||||
// 已经分析过这个指令
|
||||
return true; // 假设之前的分析是正确的
|
||||
}
|
||||
|
||||
visited.insert(inst);
|
||||
currentPath.insert(inst);
|
||||
|
||||
// 1. 检查是否有副作用(逃逸点)
|
||||
if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(inst)) {
|
||||
if (DEBUG && visited.size() < 10) {
|
||||
std::cout << " 指令有副作用,是逃逸点" << std::endl;
|
||||
}
|
||||
currentPath.erase(inst);
|
||||
return false; // 有副作用的指令是逃逸点
|
||||
}
|
||||
|
||||
// 1.5. 特殊检查:控制流指令永远不是死代码
|
||||
auto instKind = inst->getKind();
|
||||
if (instKind == Instruction::Kind::kCondBr ||
|
||||
instKind == Instruction::Kind::kBr ||
|
||||
instKind == Instruction::Kind::kReturn) {
|
||||
if (DEBUG && visited.size() < 10) {
|
||||
std::cout << " 控制流指令,是逃逸点" << std::endl;
|
||||
}
|
||||
currentPath.erase(inst);
|
||||
return false; // 控制流指令是逃逸点
|
||||
}
|
||||
|
||||
// 2. 检查指令的所有使用
|
||||
bool allUsesAreDead = true;
|
||||
for (auto use : inst->getUses()) {
|
||||
auto user = use->getUser();
|
||||
auto* userInst = dynamic_cast<Instruction*>(user);
|
||||
|
||||
if (!userInst) {
|
||||
// 被非指令使用(如函数返回值),是逃逸点
|
||||
if (DEBUG && visited.size() < 10) {
|
||||
std::cout << " 被非指令使用,是逃逸点" << std::endl;
|
||||
}
|
||||
allUsesAreDead = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// 检查使用是否在循环外(逃逸点)
|
||||
if (!loop->contains(userInst->getParent())) {
|
||||
if (DEBUG && visited.size() < 10) {
|
||||
std::cout << " 在循环外被 " << userInst->getName() << " 使用,是逃逸点" << std::endl;
|
||||
}
|
||||
allUsesAreDead = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// 特殊检查:如果使用者是循环的退出条件,需要进一步分析
|
||||
// 对于用于退出条件的归纳变量,需要更谨慎的处理
|
||||
if (isUsedInLoopExitCondition(userInst, loop)) {
|
||||
// 修复逻辑:用于循环退出条件的归纳变量通常不应该被消除
|
||||
// 除非整个循环都可以被证明是完全无用的(这需要更复杂的分析)
|
||||
if (DEBUG && visited.size() < 10) {
|
||||
std::cout << " 被用于循环退出条件,是逃逸点(避免破坏循环语义)" << std::endl;
|
||||
}
|
||||
allUsesAreDead = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// 递归分析使用者的使用链
|
||||
if (!isInstructionUseChainDeadRecursively(userInst, loop, visited, currentPath)) {
|
||||
allUsesAreDead = false;
|
||||
break; // 找到逃逸点,不需要继续分析
|
||||
}
|
||||
}
|
||||
|
||||
currentPath.erase(inst);
|
||||
|
||||
if (allUsesAreDead && DEBUG && visited.size() < 10) {
|
||||
std::cout << " 指令 " << inst->getName() << " 的所有使用都是死代码" << std::endl;
|
||||
}
|
||||
|
||||
return allUsesAreDead;
|
||||
}
|
||||
|
||||
// 检查循环是否有副作用
|
||||
bool InductionVariableEliminationContext::loopHasSideEffects(Loop* loop) {
|
||||
// 遍历循环中的所有指令,检查是否有副作用
|
||||
for (BasicBlock* bb : loop->getBlocks()) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
Instruction* instPtr = inst.get();
|
||||
|
||||
// 使用副作用分析(如果可用)
|
||||
if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(instPtr)) {
|
||||
if (DEBUG) {
|
||||
std::cout << " 循环中发现有副作用的指令: " << instPtr->getName() << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果没有副作用分析,使用保守的判断
|
||||
if (!sideEffectAnalysis) {
|
||||
auto kind = instPtr->getKind();
|
||||
// 这些指令通常有副作用
|
||||
if (kind == Instruction::Kind::kCall ||
|
||||
kind == Instruction::Kind::kStore ||
|
||||
kind == Instruction::Kind::kReturn) {
|
||||
if (DEBUG) {
|
||||
std::cout << " 循环中发现潜在有副作用的指令: " << instPtr->getName() << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 重要修复:检查是否为嵌套循环的外层循环
|
||||
// 如果当前循环包含其他循环,那么它有潜在的副作用
|
||||
for (const auto& loop_ptr : loopAnalysis->getAllLoops()) {
|
||||
Loop* otherLoop = loop_ptr.get();
|
||||
if(loopAnalysis->getLowestCommonAncestor(otherLoop, loop) == loop) {
|
||||
if (DEBUG) {
|
||||
std::cout << " 循环 " << loop->getName() << " 是其他循环的外层循环,视为有副作用" << std::endl;
|
||||
}
|
||||
return true; // 外层循环被视为有副作用
|
||||
}
|
||||
// if (otherLoop != loop && loop->contains(otherLoop->getHeader())) {
|
||||
// if (DEBUG) {
|
||||
// std::cout << " 循环 " << loop->getName() << " 包含子循环 " << otherLoop->getName() << ",视为有副作用" << std::endl;
|
||||
// }
|
||||
// return true; // 包含子循环的外层循环被视为有副作用
|
||||
// }
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " 循环 " << loop->getName() << " 无副作用" << std::endl;
|
||||
}
|
||||
return false; // 循环无副作用
|
||||
}
|
||||
|
||||
// 检查指令是否被用于循环退出条件
|
||||
bool InductionVariableEliminationContext::isUsedInLoopExitCondition(Instruction* inst, Loop* loop) {
|
||||
// 检查指令是否被循环的退出条件使用
|
||||
for (BasicBlock* exitingBB : loop->getExitingBlocks()) {
|
||||
auto terminatorIt = exitingBB->terminator();
|
||||
if (terminatorIt != exitingBB->end()) {
|
||||
Instruction* terminator = terminatorIt->get();
|
||||
if (terminator) {
|
||||
// 检查终结指令的操作数
|
||||
for (size_t i = 0; i < terminator->getNumOperands(); ++i) {
|
||||
if (terminator->getOperand(i) == inst) {
|
||||
if (DEBUG) {
|
||||
std::cout << " 指令 " << inst->getName() << " 用于循环退出条件" << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 对于条件分支,还需要检查条件指令的操作数
|
||||
if (terminator->getKind() == Instruction::Kind::kCondBr) {
|
||||
auto* condBr = dynamic_cast<CondBrInst*>(terminator);
|
||||
if (condBr) {
|
||||
Value* condition = condBr->getCondition();
|
||||
if (condition == inst) {
|
||||
if (DEBUG) {
|
||||
std::cout << " 指令 " << inst->getName() << " 是循环条件" << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 递归检查条件指令的操作数(比如比较指令)
|
||||
auto* condInst = dynamic_cast<Instruction*>(condition);
|
||||
if (condInst) {
|
||||
for (size_t i = 0; i < condInst->getNumOperands(); ++i) {
|
||||
if (condInst->getOperand(i) == inst) {
|
||||
if (DEBUG) {
|
||||
std::cout << " 指令 " << inst->getName() << " 用于循环条件的操作数" << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// 检查指令的结果是否未被有效使用
|
||||
bool InductionVariableEliminationContext::isInstructionResultUnused(Instruction* inst, Loop* loop) {
|
||||
// 检查指令的所有使用
|
||||
if (inst->getUses().empty()) {
|
||||
return true; // 没有使用,肯定是未使用
|
||||
}
|
||||
|
||||
for (auto use : inst->getUses()) {
|
||||
auto user = use->getUser();
|
||||
auto* userInst = dynamic_cast<Instruction*>(user);
|
||||
|
||||
if (!userInst) {
|
||||
return false; // 被非指令使用,认为是有效使用
|
||||
}
|
||||
|
||||
// 如果在循环外被使用,认为是有效使用
|
||||
if (!loop->contains(userInst->getParent())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 递归检查使用这个结果的指令是否也是死代码
|
||||
// 为了避免无限递归,限制递归深度
|
||||
if (!isInstructionEffectivelyDead(userInst, loop, 3)) {
|
||||
return false; // 存在有效使用
|
||||
}
|
||||
}
|
||||
|
||||
return true; // 所有使用都是无效的
|
||||
}
|
||||
|
||||
// 检查store指令是否存储到死地址(利用别名分析)
|
||||
bool InductionVariableEliminationContext::isStoreToDeadLocation(StoreInst* store, Loop* loop) {
|
||||
if (!aliasAnalysis) {
|
||||
return false; // 没有别名分析,保守返回false
|
||||
}
|
||||
|
||||
Value* storePtr = store->getPointer();
|
||||
|
||||
// 检查是否存储到局部临时变量且该变量在循环外不被读取
|
||||
const MemoryLocation* memLoc = aliasAnalysis->getMemoryLocation(storePtr);
|
||||
if (!memLoc) {
|
||||
return false; // 无法确定内存位置
|
||||
}
|
||||
|
||||
// 如果是局部数组且只在循环内被访问
|
||||
if (memLoc->isLocalArray) {
|
||||
// 检查该内存位置是否在循环外被读取
|
||||
for (auto* accessInst : memLoc->accessInsts) {
|
||||
if (accessInst->getKind() == Instruction::Kind::kLoad) {
|
||||
if (!loop->contains(accessInst->getParent())) {
|
||||
return false; // 在循环外被读取,不是死存储
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " 存储到局部数组且仅在循环内访问" << std::endl;
|
||||
}
|
||||
return true; // 存储到仅循环内访问的局部数组
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查指令是否有效死代码(带递归深度限制)
|
||||
bool InductionVariableEliminationContext::isInstructionEffectivelyDead(Instruction* inst, Loop* loop, int maxDepth) {
|
||||
if (maxDepth <= 0) {
|
||||
return false; // 达到递归深度限制,保守返回false
|
||||
}
|
||||
|
||||
// 利用副作用分析
|
||||
if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(inst)) {
|
||||
return false; // 有副作用的指令不是死代码
|
||||
}
|
||||
|
||||
// 检查特殊指令类型
|
||||
switch (inst->getKind()) {
|
||||
case Instruction::Kind::kStore:
|
||||
// Store指令可能是死存储
|
||||
return isStoreToDeadLocation(dynamic_cast<StoreInst*>(inst), loop);
|
||||
|
||||
case Instruction::Kind::kCall:
|
||||
// 函数调用通常有副作用
|
||||
if (sideEffectAnalysis) {
|
||||
return !sideEffectAnalysis->hasSideEffect(inst);
|
||||
}
|
||||
return false; // 保守地认为函数调用有效果
|
||||
|
||||
case Instruction::Kind::kReturn:
|
||||
case Instruction::Kind::kBr:
|
||||
case Instruction::Kind::kCondBr:
|
||||
// 控制流指令不是死代码
|
||||
return false;
|
||||
|
||||
default:
|
||||
// 其他指令检查其使用是否有效
|
||||
break;
|
||||
}
|
||||
|
||||
// 检查指令的使用
|
||||
if (inst->getUses().empty()) {
|
||||
return true; // 没有使用的纯指令是死代码
|
||||
}
|
||||
|
||||
// 递归检查所有使用
|
||||
for (auto use : inst->getUses()) {
|
||||
auto user = use->getUser();
|
||||
auto* userInst = dynamic_cast<Instruction*>(user);
|
||||
|
||||
if (!userInst) {
|
||||
return false; // 被非指令使用
|
||||
}
|
||||
|
||||
if (!loop->contains(userInst->getParent())) {
|
||||
return false; // 在循环外被使用
|
||||
}
|
||||
|
||||
// 递归检查使用者
|
||||
if (!isInstructionEffectivelyDead(userInst, loop, maxDepth - 1)) {
|
||||
return false; // 存在有效使用
|
||||
}
|
||||
}
|
||||
|
||||
return true; // 所有使用都是死代码
|
||||
}
|
||||
|
||||
// 原有的函数保持兼容,但现在使用增强的死代码分析
|
||||
bool InductionVariableEliminationContext::isInstructionDeadOrInternalOnly(Instruction* inst, Loop* loop) {
|
||||
return isInstructionEffectivelyDead(inst, loop, 5);
|
||||
}
|
||||
|
||||
// 检查store指令是否有后续的load操作
|
||||
bool InductionVariableEliminationContext::hasSubsequentLoad(StoreInst* store, Loop* loop) {
|
||||
if (!aliasAnalysis) {
|
||||
// 没有别名分析,保守地假设有后续读取
|
||||
return true;
|
||||
}
|
||||
|
||||
Value* storePtr = store->getPointer();
|
||||
const MemoryLocation* storeLoc = aliasAnalysis->getMemoryLocation(storePtr);
|
||||
|
||||
if (!storeLoc) {
|
||||
// 无法确定内存位置,保守处理
|
||||
return true;
|
||||
}
|
||||
|
||||
// 在循环中和循环后查找对同一位置的load操作
|
||||
std::vector<BasicBlock*> blocksToCheck;
|
||||
|
||||
// 添加循环内的所有基本块
|
||||
for (auto* bb : loop->getBlocks()) {
|
||||
blocksToCheck.push_back(bb);
|
||||
}
|
||||
|
||||
// 添加循环的退出块
|
||||
auto exitBlocks = loop->getExitBlocks();
|
||||
for (auto* exitBB : exitBlocks) {
|
||||
blocksToCheck.push_back(exitBB);
|
||||
}
|
||||
|
||||
// 搜索load操作
|
||||
for (auto* bb : blocksToCheck) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (inst->getKind() == Instruction::Kind::kLoad) {
|
||||
LoadInst* loadInst = static_cast<LoadInst*>(inst.get());
|
||||
Value* loadPtr = loadInst->getPointer();
|
||||
const MemoryLocation* loadLoc = aliasAnalysis->getMemoryLocation(loadPtr);
|
||||
|
||||
if (loadLoc && aliasAnalysis->queryAlias(storePtr, loadPtr) != AliasType::NO_ALIAS) {
|
||||
// 找到可能读取同一位置的load操作
|
||||
if (DEBUG) {
|
||||
std::cout << " 找到后续load操作: " << loadInst->getName() << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否通过函数调用间接访问
|
||||
for (auto* bb : blocksToCheck) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (inst->getKind() == Instruction::Kind::kCall) {
|
||||
CallInst* callInst = static_cast<CallInst*>(inst.get());
|
||||
if (callInst && sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(callInst)) {
|
||||
// 函数调用可能间接读取内存
|
||||
if (DEBUG) {
|
||||
std::cout << " 函数调用可能读取内存: " << callInst->getName() << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " 未找到后续load操作" << std::endl;
|
||||
}
|
||||
return false; // 没有找到后续读取
|
||||
}
|
||||
|
||||
// 检查指令是否在循环外有使用
|
||||
bool InductionVariableEliminationContext::hasUsageOutsideLoop(Instruction* inst, Loop* loop) {
|
||||
for (auto use : inst->getUses()) {
|
||||
auto user = use->getUser();
|
||||
auto* userInst = dynamic_cast<Instruction*>(user);
|
||||
|
||||
if (!userInst) {
|
||||
// 被非指令使用,可能在循环外
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!loop->contains(userInst->getParent())) {
|
||||
// 在循环外被使用
|
||||
if (DEBUG) {
|
||||
std::cout << " 指令 " << inst->getName() << " 在循环外被 "
|
||||
<< userInst->getName() << " 使用" << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false; // 没有循环外使用
|
||||
}
|
||||
|
||||
// 检查store指令是否在循环外有后续的load操作
|
||||
bool InductionVariableEliminationContext::hasSubsequentLoadOutsideLoop(StoreInst* store, Loop* loop) {
|
||||
if (!aliasAnalysis) {
|
||||
// 没有别名分析,保守地假设有后续读取
|
||||
return true;
|
||||
}
|
||||
|
||||
Value* storePtr = store->getPointer();
|
||||
|
||||
// 检查循环的退出块及其后继
|
||||
auto exitBlocks = loop->getExitBlocks();
|
||||
std::set<BasicBlock*> visitedBlocks;
|
||||
|
||||
for (auto* exitBB : exitBlocks) {
|
||||
if (hasLoadInSubtree(exitBB, storePtr, visitedBlocks)) {
|
||||
if (DEBUG) {
|
||||
std::cout << " 找到循环外的后续load操作" << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false; // 没有找到循环外的后续读取
|
||||
}
|
||||
|
||||
// 递归检查基本块子树中是否有对指定位置的load操作
|
||||
bool InductionVariableEliminationContext::hasLoadInSubtree(BasicBlock* bb, Value* ptr, std::set<BasicBlock*>& visited) {
|
||||
if (visited.count(bb) > 0) {
|
||||
return false; // 已经访问过,避免无限循环
|
||||
}
|
||||
visited.insert(bb);
|
||||
|
||||
// 检查当前基本块中的指令
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (inst->getKind() == Instruction::Kind::kLoad) {
|
||||
LoadInst* loadInst = static_cast<LoadInst*>(inst.get());
|
||||
if (aliasAnalysis && aliasAnalysis->queryAlias(ptr, loadInst->getPointer()) != AliasType::NO_ALIAS) {
|
||||
return true; // 找到了对相同或别名位置的load
|
||||
}
|
||||
} else if (inst->getKind() == Instruction::Kind::kCall) {
|
||||
// 函数调用可能间接读取内存
|
||||
CallInst* callInst = static_cast<CallInst*>(inst.get());
|
||||
if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(callInst)) {
|
||||
return true; // 保守地认为函数调用可能读取内存
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 递归检查后继基本块(限制深度以避免过度搜索)
|
||||
static int searchDepth = 0;
|
||||
if (searchDepth < 10) { // 限制搜索深度
|
||||
searchDepth++;
|
||||
for (auto* succ : bb->getSuccessors()) {
|
||||
if (hasLoadInSubtree(succ, ptr, visited)) {
|
||||
searchDepth--;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
searchDepth--;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<Instruction*> InductionVariableEliminationContext::collectRelatedInstructions(
|
||||
PhiInst* phiInst, Loop* loop) {
|
||||
std::vector<Instruction*> relatedInsts;
|
||||
|
||||
// 收集所有与该归纳变量相关的指令
|
||||
for (auto use : phiInst->getUses()) {
|
||||
auto user = use->getUser();
|
||||
auto* userInst = dynamic_cast<Instruction*>(user);
|
||||
|
||||
if (userInst && loop->contains(userInst->getParent())) {
|
||||
relatedInsts.push_back(userInst);
|
||||
}
|
||||
}
|
||||
|
||||
return relatedInsts;
|
||||
}
|
||||
|
||||
void InductionVariableEliminationContext::analyzeSafetyForElimination() {
|
||||
if (DEBUG) {
|
||||
std::cout << " === Phase 2: Analyzing Safety for Elimination ===" << std::endl;
|
||||
}
|
||||
|
||||
// 为每个死归纳变量检查消除的安全性
|
||||
for (auto& deadIV : deadIVs) {
|
||||
bool isSafe = isSafeToEliminate(deadIV.get());
|
||||
deadIV->canEliminate = isSafe;
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Dead IV " << deadIV->phiInst->getName()
|
||||
<< ": " << (isSafe ? "SAFE" : "UNSAFE") << " to eliminate" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
size_t safeCount = 0;
|
||||
for (const auto& deadIV : deadIVs) {
|
||||
if (deadIV->canEliminate) safeCount++;
|
||||
}
|
||||
std::cout << " === End Phase 2: " << safeCount << " of " << deadIVs.size()
|
||||
<< " variables are safe to eliminate ===" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
bool InductionVariableEliminationContext::isSafeToEliminate(const DeadInductionVariable* deadIV) {
|
||||
// 1. 确保归纳变量在循环头
|
||||
if (deadIV->phiInst->getParent() != deadIV->containingLoop->getHeader()) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Unsafe: phi not in loop header" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 确保相关指令都在循环内
|
||||
for (auto* inst : deadIV->relatedInsts) {
|
||||
if (!deadIV->containingLoop->contains(inst->getParent())) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Unsafe: related instruction outside loop" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 确保没有副作用
|
||||
for (auto* inst : deadIV->relatedInsts) {
|
||||
if (sideEffectAnalysis) {
|
||||
// 使用副作用分析进行精确检查
|
||||
if (sideEffectAnalysis->hasSideEffect(inst)) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Unsafe: related instruction " << inst->getName()
|
||||
<< " has side effects" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// 没有副作用分析时使用保守策略:只允许基本算术运算
|
||||
auto kind = inst->getKind();
|
||||
if (kind != Instruction::Kind::kAdd &&
|
||||
kind != Instruction::Kind::kSub &&
|
||||
kind != Instruction::Kind::kMul) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Unsafe: related instruction may have side effects (conservative)" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 确保不影响循环的退出条件
|
||||
for (BasicBlock* exitingBB : deadIV->containingLoop->getExitingBlocks()) {
|
||||
auto terminatorIt = exitingBB->terminator();
|
||||
if (terminatorIt != exitingBB->end()) {
|
||||
Instruction* terminator = terminatorIt->get();
|
||||
if (terminator) {
|
||||
for (size_t i = 0; i < terminator->getNumOperands(); ++i) {
|
||||
if (terminator->getOperand(i) == deadIV->phiInst) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Unsafe: phi used in loop exit condition" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InductionVariableEliminationContext::performInductionVariableElimination() {
|
||||
if (DEBUG) {
|
||||
std::cout << " === Phase 3: Performing Induction Variable Elimination ===" << std::endl;
|
||||
}
|
||||
|
||||
bool modified = false;
|
||||
|
||||
for (auto& deadIV : deadIVs) {
|
||||
if (!deadIV->canEliminate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Eliminating dead IV: " << deadIV->phiInst->getName() << std::endl;
|
||||
}
|
||||
|
||||
if (eliminateDeadInductionVariable(deadIV.get())) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Successfully eliminated: " << deadIV->phiInst->getName() << std::endl;
|
||||
}
|
||||
modified = true;
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
std::cout << " Failed to eliminate: " << deadIV->phiInst->getName() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " === End Phase 3: " << (modified ? "Eliminations performed" : "No eliminations") << " ===" << std::endl;
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
bool InductionVariableEliminationContext::eliminateDeadInductionVariable(DeadInductionVariable* deadIV) {
|
||||
// 1. 删除所有相关指令
|
||||
for (auto* inst : deadIV->relatedInsts) {
|
||||
auto* bb = inst->getParent();
|
||||
auto it = bb->findInstIterator(inst);
|
||||
if (it != bb->end()) {
|
||||
SysYIROptUtils::usedelete(it);
|
||||
// bb->getInstructions().erase(it);
|
||||
if (DEBUG) {
|
||||
std::cout << " Removed related instruction: " << inst->getName() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 删除 phi 指令
|
||||
auto* bb = deadIV->phiInst->getParent();
|
||||
auto it = bb->findInstIterator(deadIV->phiInst);
|
||||
if (it != bb->end()) {
|
||||
SysYIROptUtils::usedelete(it);
|
||||
// bb->getInstructions().erase(it);
|
||||
if (DEBUG) {
|
||||
std::cout << " Removed phi instruction: " << deadIV->phiInst->getName() << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void InductionVariableEliminationContext::printDebugInfo() {
|
||||
if (!DEBUG) return;
|
||||
|
||||
std::cout << "\n=== Induction Variable Elimination Summary ===" << std::endl;
|
||||
std::cout << "Total dead IVs found: " << deadIVs.size() << std::endl;
|
||||
|
||||
size_t eliminatedCount = 0;
|
||||
for (auto& [loop, loopDeadIVs] : loopToDeadIVs) {
|
||||
size_t loopEliminatedCount = 0;
|
||||
for (auto* deadIV : loopDeadIVs) {
|
||||
if (deadIV->canEliminate) {
|
||||
loopEliminatedCount++;
|
||||
eliminatedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (loopEliminatedCount > 0) {
|
||||
std::cout << "Loop " << loop->getName() << ": " << loopEliminatedCount
|
||||
<< " of " << loopDeadIVs.size() << " IVs eliminated" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Total eliminated: " << eliminatedCount << " of " << deadIVs.size() << std::endl;
|
||||
std::cout << "=============================================" << std::endl;
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
264
src/midend/Pass/Optimize/LICM.cpp
Normal file
264
src/midend/Pass/Optimize/LICM.cpp
Normal file
@@ -0,0 +1,264 @@
|
||||
#include "LICM.h"
|
||||
#include "IR.h"
|
||||
|
||||
extern int DEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
void *LICM::ID = (void *)&LICM::ID;
|
||||
|
||||
bool LICMContext::run() { return hoistInstructions(); }
|
||||
|
||||
bool LICMContext::hoistInstructions() {
|
||||
bool changed = false;
|
||||
BasicBlock *preheader = loop->getPreHeader();
|
||||
if (!preheader || !chars)
|
||||
return false;
|
||||
|
||||
// 1. 先收集所有可外提指令
|
||||
std::unordered_set<Instruction *> workSet(chars->invariantInsts.begin(), chars->invariantInsts.end());
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "LICM: Found " << workSet.size() << " candidate invariant instructions to hoist:" << std::endl;
|
||||
for (auto *inst : workSet) {
|
||||
std::cout << " - " << inst->getName() << " (kind: " << static_cast<int>(inst->getKind())
|
||||
<< ", in BB: " << inst->getParent()->getName() << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 计算每个指令被依赖的次数(入度)
|
||||
std::unordered_map<Instruction *, int> indegree;
|
||||
std::unordered_map<Instruction *, std::vector<Instruction *>> dependencies; // 记录依赖关系
|
||||
std::unordered_map<Instruction *, std::vector<Instruction *>> dependents; // 记录被依赖关系
|
||||
|
||||
for (auto *inst : workSet) {
|
||||
indegree[inst] = 0;
|
||||
dependencies[inst] = {};
|
||||
dependents[inst] = {};
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "LICM: Analyzing dependencies between invariant instructions..." << std::endl;
|
||||
}
|
||||
|
||||
for (auto *inst : workSet) {
|
||||
for (size_t i = 0; i < inst->getNumOperands(); ++i) {
|
||||
if (auto *dep = dynamic_cast<Instruction *>(inst->getOperand(i))) {
|
||||
if (workSet.count(dep)) {
|
||||
indegree[inst]++;
|
||||
dependencies[inst].push_back(dep);
|
||||
dependents[dep].push_back(inst);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Dependency: " << inst->getName() << " depends on " << dep->getName() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "LICM: Initial indegree analysis:" << std::endl;
|
||||
for (auto &[inst, deg] : indegree) {
|
||||
std::cout << " " << inst->getName() << ": indegree=" << deg;
|
||||
if (deg > 0) {
|
||||
std::cout << ", depends on: ";
|
||||
for (auto *dep : dependencies[inst]) {
|
||||
std::cout << dep->getName() << " ";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Kahn拓扑排序
|
||||
std::vector<Instruction *> sorted;
|
||||
std::queue<Instruction *> q;
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "LICM: Starting topological sort..." << std::endl;
|
||||
}
|
||||
|
||||
for (auto &[inst, deg] : indegree) {
|
||||
if (deg == 0) {
|
||||
q.push(inst);
|
||||
if (DEBUG) {
|
||||
std::cout << " Initial zero-indegree instruction: " << inst->getName() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int sortStep = 0;
|
||||
while (!q.empty()) {
|
||||
auto *inst = q.front();
|
||||
q.pop();
|
||||
sorted.push_back(inst);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Step " << (++sortStep) << ": Processing " << inst->getName() << std::endl;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Reducing indegree of dependents of " << inst->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 正确的拓扑排序:当处理一个指令时,应该减少其所有使用者(dependents)的入度
|
||||
for (auto *dependent : dependents[inst]) {
|
||||
indegree[dependent]--;
|
||||
if (DEBUG) {
|
||||
std::cout << " Reducing indegree of " << dependent->getName() << " to " << indegree[dependent] << std::endl;
|
||||
}
|
||||
if (indegree[dependent] == 0) {
|
||||
q.push(dependent);
|
||||
if (DEBUG) {
|
||||
std::cout << " Adding " << dependent->getName() << " to queue (indegree=0)" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否全部排序,若未全部排序,打印错误信息
|
||||
// 这可能是因为存在循环依赖或其他问题导致无法完成拓扑排序
|
||||
if (sorted.size() != workSet.size()) {
|
||||
if (DEBUG) {
|
||||
std::cout << "LICM: Topological sort failed! Sorted " << sorted.size()
|
||||
<< " instructions out of " << workSet.size() << " total." << std::endl;
|
||||
|
||||
// 找出未被排序的指令(形成循环依赖的指令)
|
||||
std::unordered_set<Instruction *> remaining;
|
||||
for (auto *inst : workSet) {
|
||||
bool found = false;
|
||||
for (auto *sortedInst : sorted) {
|
||||
if (inst == sortedInst) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
remaining.insert(inst);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "LICM: Instructions involved in dependency cycle:" << std::endl;
|
||||
for (auto *inst : remaining) {
|
||||
std::cout << " - " << inst->getName() << " (indegree=" << indegree[inst] << ")" << std::endl;
|
||||
std::cout << " Dependencies within cycle: ";
|
||||
for (auto *dep : dependencies[inst]) {
|
||||
if (remaining.count(dep)) {
|
||||
std::cout << dep->getName() << " ";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout << " Dependents within cycle: ";
|
||||
for (auto *dependent : dependents[inst]) {
|
||||
if (remaining.count(dependent)) {
|
||||
std::cout << dependent->getName() << " ";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// 尝试找出一个具体的循环路径
|
||||
std::cout << "LICM: Attempting to trace a dependency cycle:" << std::endl;
|
||||
if (!remaining.empty()) {
|
||||
auto *start = *remaining.begin();
|
||||
std::unordered_set<Instruction *> visited;
|
||||
std::vector<Instruction *> path;
|
||||
|
||||
std::function<bool(Instruction *)> findCycle = [&](Instruction *current) -> bool {
|
||||
if (visited.count(current)) {
|
||||
// 找到环
|
||||
auto it = std::find(path.begin(), path.end(), current);
|
||||
if (it != path.end()) {
|
||||
std::cout << " Cycle found: ";
|
||||
for (auto cycleIt = it; cycleIt != path.end(); ++cycleIt) {
|
||||
std::cout << (*cycleIt)->getName() << " -> ";
|
||||
}
|
||||
std::cout << current->getName() << std::endl;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
visited.insert(current);
|
||||
path.push_back(current);
|
||||
|
||||
for (auto *dep : dependencies[current]) {
|
||||
if (remaining.count(dep)) {
|
||||
if (findCycle(dep)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
path.pop_back();
|
||||
return false;
|
||||
};
|
||||
|
||||
findCycle(start);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. 按拓扑序外提
|
||||
if (DEBUG) {
|
||||
std::cout << "LICM: Successfully completed topological sort. Hoisting instructions in order:" << std::endl;
|
||||
}
|
||||
|
||||
for (auto *inst : sorted) {
|
||||
if (!inst)
|
||||
continue;
|
||||
BasicBlock *parent = inst->getParent();
|
||||
if (parent && loop->contains(parent)) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Hoisting " << inst->getName() << " from " << parent->getName()
|
||||
<< " to preheader " << preheader->getName() << std::endl;
|
||||
}
|
||||
auto sourcePos = parent->findInstIterator(inst);
|
||||
auto targetPos = preheader->terminator();
|
||||
parent->moveInst(sourcePos, targetPos, preheader);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG && changed) {
|
||||
std::cout << "LICM: Successfully hoisted " << sorted.size() << " invariant instructions" << std::endl;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
// ---- LICM Pass Implementation ----
|
||||
|
||||
bool LICM::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
auto *loopAnalysis = AM.getAnalysisResult<LoopAnalysisResult, LoopAnalysisPass>(F);
|
||||
auto *loopCharsResult = AM.getAnalysisResult<LoopCharacteristicsResult, LoopCharacteristicsPass>(F);
|
||||
if (!loopAnalysis || !loopCharsResult)
|
||||
return false;
|
||||
|
||||
bool changed = false;
|
||||
// 对每个函数内的所有循环做处理
|
||||
for (const auto &loop_ptr : loopAnalysis->getAllLoops()) {
|
||||
Loop *loop = loop_ptr.get();
|
||||
if (DEBUG) {
|
||||
std::cout << "LICM: Processing loop in function " << F->getName() << ": " << loop->getName() << std::endl;
|
||||
}
|
||||
const LoopCharacteristics *chars = loopCharsResult->getCharacteristics(loop);
|
||||
if (!chars || !loop->getPreHeader())
|
||||
continue; // 没有分析结果或没有前置块则跳过
|
||||
LICMContext ctx(F, loop, builder, chars);
|
||||
changed |= ctx.run();
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
void LICM::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
|
||||
|
||||
analysisDependencies.insert(&LoopAnalysisPass::ID);
|
||||
analysisDependencies.insert(&LoopCharacteristicsPass::ID);
|
||||
|
||||
analysisInvalidations.insert(&LoopCharacteristicsPass::ID);
|
||||
analysisInvalidations.insert(&LivenessAnalysisPass::ID);
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@@ -1,145 +0,0 @@
|
||||
#include "../../include/midend/Pass/Optimize/LargeArrayToGlobal.h"
|
||||
#include "../../IR.h"
|
||||
#include <unordered_map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// Helper function to convert type to string
|
||||
static std::string typeToString(Type *type) {
|
||||
if (!type) return "null";
|
||||
|
||||
switch (type->getKind()) {
|
||||
case Type::kInt:
|
||||
return "int";
|
||||
case Type::kFloat:
|
||||
return "float";
|
||||
case Type::kPointer:
|
||||
return "ptr";
|
||||
case Type::kArray: {
|
||||
auto *arrayType = type->as<ArrayType>();
|
||||
return "[" + std::to_string(arrayType->getNumElements()) + " x " +
|
||||
typeToString(arrayType->getElementType()) + "]";
|
||||
}
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void *LargeArrayToGlobalPass::ID = &LargeArrayToGlobalPass::ID;
|
||||
|
||||
bool LargeArrayToGlobalPass::runOnModule(Module *M, AnalysisManager &AM) {
|
||||
bool changed = false;
|
||||
|
||||
if (!M) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Collect all alloca instructions from all functions
|
||||
std::vector<std::pair<AllocaInst*, Function*>> allocasToConvert;
|
||||
|
||||
for (auto &funcPair : M->getFunctions()) {
|
||||
Function *F = funcPair.second.get();
|
||||
if (!F || F->getBasicBlocks().begin() == F->getBasicBlocks().end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto &BB : F->getBasicBlocks()) {
|
||||
for (auto &inst : BB->getInstructions()) {
|
||||
if (auto *alloca = dynamic_cast<AllocaInst*>(inst.get())) {
|
||||
Type *allocatedType = alloca->getAllocatedType();
|
||||
|
||||
// Calculate the size of the allocated type
|
||||
unsigned size = calculateTypeSize(allocatedType);
|
||||
if(DEBUG){
|
||||
// Debug: print size information
|
||||
std::cout << "LargeArrayToGlobalPass: Found alloca with size " << size
|
||||
<< " for type " << typeToString(allocatedType) << std::endl;
|
||||
}
|
||||
|
||||
// Convert arrays of 1KB (1024 bytes) or larger to global variables
|
||||
if (size >= 1024) {
|
||||
if(DEBUG)
|
||||
std::cout << "LargeArrayToGlobalPass: Converting array of size " << size << " to global" << std::endl;
|
||||
allocasToConvert.emplace_back(alloca, F);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the collected alloca instructions to global variables
|
||||
for (auto [alloca, F] : allocasToConvert) {
|
||||
convertAllocaToGlobal(alloca, F, M);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
unsigned LargeArrayToGlobalPass::calculateTypeSize(Type *type) {
|
||||
if (!type) return 0;
|
||||
|
||||
switch (type->getKind()) {
|
||||
case Type::kInt:
|
||||
case Type::kFloat:
|
||||
return 4;
|
||||
case Type::kPointer:
|
||||
return 8;
|
||||
case Type::kArray: {
|
||||
auto *arrayType = type->as<ArrayType>();
|
||||
return arrayType->getNumElements() * calculateTypeSize(arrayType->getElementType());
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void LargeArrayToGlobalPass::convertAllocaToGlobal(AllocaInst *alloca, Function *F, Module *M) {
|
||||
Type *allocatedType = alloca->getAllocatedType();
|
||||
|
||||
// Create a unique name for the global variable
|
||||
std::string globalName = generateUniqueGlobalName(alloca, F);
|
||||
|
||||
// Create the global variable - GlobalValue expects pointer type
|
||||
Type *pointerType = Type::getPointerType(allocatedType);
|
||||
GlobalValue *globalVar = M->createGlobalValue(globalName, pointerType);
|
||||
|
||||
if (!globalVar) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Replace all uses of the alloca with the global variable
|
||||
alloca->replaceAllUsesWith(globalVar);
|
||||
|
||||
// Remove the alloca instruction from its basic block
|
||||
for (auto &BB : F->getBasicBlocks()) {
|
||||
auto &instructions = BB->getInstructions();
|
||||
for (auto it = instructions.begin(); it != instructions.end(); ++it) {
|
||||
if (it->get() == alloca) {
|
||||
instructions.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string LargeArrayToGlobalPass::generateUniqueGlobalName(AllocaInst *alloca, Function *F) {
|
||||
std::string baseName = alloca->getName();
|
||||
if (baseName.empty()) {
|
||||
baseName = "array";
|
||||
}
|
||||
|
||||
// Ensure uniqueness by appending function name and counter
|
||||
static std::unordered_map<std::string, int> nameCounter;
|
||||
std::string key = F->getName() + "." + baseName;
|
||||
|
||||
int counter = nameCounter[key]++;
|
||||
std::ostringstream oss;
|
||||
oss << key << "." << counter;
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
528
src/midend/Pass/Optimize/LoopNormalization.cpp
Normal file
528
src/midend/Pass/Optimize/LoopNormalization.cpp
Normal file
@@ -0,0 +1,528 @@
|
||||
#include "LoopNormalization.h"
|
||||
#include "Dom.h"
|
||||
#include "Loop.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
// 使用全局调试开关
|
||||
extern int DEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 定义 Pass 的唯一 ID
|
||||
void *LoopNormalizationPass::ID = (void *)&LoopNormalizationPass::ID;
|
||||
|
||||
bool LoopNormalizationPass::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
if (F->getBasicBlocks().empty()) {
|
||||
return false; // 空函数
|
||||
}
|
||||
|
||||
if (DEBUG)
|
||||
std::cout << "Running LoopNormalizationPass on function: " << F->getName() << std::endl;
|
||||
|
||||
// 获取并缓存所有需要的分析结果
|
||||
loopAnalysis = AM.getAnalysisResult<LoopAnalysisResult, LoopAnalysisPass>(F);
|
||||
if (!loopAnalysis || !loopAnalysis->hasLoops()) {
|
||||
if (DEBUG)
|
||||
std::cout << "No loops found in function " << F->getName() << ", skipping normalization" << std::endl;
|
||||
return false; // 没有循环需要规范化
|
||||
}
|
||||
|
||||
domTree = AM.getAnalysisResult<DominatorTree, DominatorTreeAnalysisPass>(F);
|
||||
|
||||
if (!domTree) {
|
||||
std::cerr << "Error: DominatorTree not available for function " << F->getName() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 重置统计信息
|
||||
stats = NormalizationStats();
|
||||
|
||||
bool modified = false;
|
||||
const auto& allLoops = loopAnalysis->getAllLoops();
|
||||
stats.totalLoops = allLoops.size();
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "Found " << stats.totalLoops << " loops to analyze for normalization" << std::endl;
|
||||
}
|
||||
|
||||
// 按循环深度从外到内处理,确保外层循环先规范化
|
||||
std::vector<Loop*> sortedLoops;
|
||||
for (const auto& loop_ptr : allLoops) {
|
||||
sortedLoops.push_back(loop_ptr.get());
|
||||
}
|
||||
|
||||
std::sort(sortedLoops.begin(), sortedLoops.end(), [](Loop* a, Loop* b) {
|
||||
return a->getLoopDepth() < b->getLoopDepth(); // 按深度升序排列
|
||||
});
|
||||
|
||||
// 逐个规范化循环
|
||||
for (Loop* loop : sortedLoops) {
|
||||
if (needsPreheader(loop)) {
|
||||
stats.loopsNeedingPreheader++;
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Loop " << loop->getName() << " needs preheader (depth="
|
||||
<< loop->getLoopDepth() << ")" << std::endl;
|
||||
}
|
||||
|
||||
if (normalizeLoop(loop)) {
|
||||
modified = true;
|
||||
stats.loopsNormalized++;
|
||||
|
||||
// 验证规范化结果
|
||||
if (!validateNormalization(loop)) {
|
||||
std::cerr << "Warning: Loop normalization validation failed for loop "
|
||||
<< loop->getName() << std::endl;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
auto* preheader = getExistingPreheader(loop);
|
||||
if (preheader) {
|
||||
std::cout << " Loop " << loop->getName() << " already has preheader: "
|
||||
<< preheader->getName() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG && modified) {
|
||||
printStats(F);
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
bool LoopNormalizationPass::normalizeLoop(Loop* loop) {
|
||||
if (DEBUG)
|
||||
std::cout << " Normalizing loop: " << loop->getName() << std::endl;
|
||||
|
||||
// 创建前置块
|
||||
BasicBlock* preheader = createPreheaderForLoop(loop);
|
||||
if (!preheader) {
|
||||
if (DEBUG)
|
||||
std::cout << " Failed to create preheader for loop " << loop->getName() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
stats.preheadersCreated++;
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Successfully created preheader " << preheader->getName()
|
||||
<< " for loop " << loop->getName() << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BasicBlock* LoopNormalizationPass::createPreheaderForLoop(Loop* loop) {
|
||||
BasicBlock* header = loop->getHeader();
|
||||
if (!header) {
|
||||
if (DEBUG)
|
||||
std::cerr << " Error: Loop has no header block" << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 获取循环外的前驱块
|
||||
std::vector<BasicBlock*> externalPreds = getExternalPredecessors(loop);
|
||||
if (externalPreds.empty()) {
|
||||
if (DEBUG)
|
||||
std::cout << " Loop " << loop->getName() << " has no external predecessors" << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Found " << externalPreds.size() << " external predecessors for loop "
|
||||
<< loop->getName() << std::endl;
|
||||
for (auto* pred : externalPreds) {
|
||||
std::cout << " External pred: " << pred->getName() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 生成前置块名称
|
||||
std::string preheaderName = generatePreheaderName(loop);
|
||||
|
||||
// 创建新的前置块
|
||||
Function* parentFunction = header->getParent();
|
||||
BasicBlock* preheader = parentFunction->addBasicBlock(preheaderName, header);
|
||||
|
||||
if (!preheader) {
|
||||
if (DEBUG)
|
||||
std::cerr << " Error: Failed to create basic block " << preheaderName << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 在前置块中创建跳转指令到循环头部
|
||||
builder->setPosition(preheader, preheader->end());
|
||||
UncondBrInst* br = builder->createUncondBrInst(header);
|
||||
|
||||
// 更新preheader的CFG关系
|
||||
preheader->addSuccessor(header);
|
||||
header->addPredecessor(preheader);
|
||||
|
||||
if(DEBUG) {
|
||||
std::cout << " Created preheader " << preheader->getName()
|
||||
<< " with unconditional branch to " << header->getName() << std::endl;
|
||||
}
|
||||
// 重定向外部前驱到新的前置块
|
||||
redirectExternalPredecessors(loop, preheader, header, externalPreds);
|
||||
|
||||
// 更新PHI节点
|
||||
updatePhiNodesForPreheader(header, preheader, externalPreds);
|
||||
|
||||
// 更新支配树关系
|
||||
updateDominatorRelations(preheader, loop);
|
||||
|
||||
// 重要:更新循环对象的前置块信息
|
||||
// 这样后续的优化遍可以通过 loop->getPreHeader() 获取到新创建的前置块
|
||||
loop->setPreHeader(preheader);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Updated loop object: preheader set to " << preheader->getName() << std::endl;
|
||||
}
|
||||
|
||||
return preheader;
|
||||
}
|
||||
|
||||
bool LoopNormalizationPass::needsPreheader(Loop* loop) {
|
||||
// 检查是否已有合适的前置块
|
||||
if (getExistingPreheader(loop) != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否有外部前驱(如果没有外部前驱,不需要前置块)
|
||||
std::vector<BasicBlock*> externalPreds = getExternalPredecessors(loop);
|
||||
if (externalPreds.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 基于结构性需求判断:
|
||||
// 1. 如果有多个外部前驱,必须创建前置块来合并它们
|
||||
// 2. 如果单个外部前驱不适合作为前置块,需要创建新的前置块
|
||||
return (externalPreds.size() > 1) || !isSuitableAsPreheader(externalPreds[0], loop);
|
||||
}
|
||||
|
||||
BasicBlock* LoopNormalizationPass::getExistingPreheader(Loop* loop) {
|
||||
BasicBlock* header = loop->getHeader();
|
||||
if (!header) return nullptr;
|
||||
|
||||
std::vector<BasicBlock*> externalPreds = getExternalPredecessors(loop);
|
||||
|
||||
// 如果只有一个外部前驱,且适合作为前置块,则返回它
|
||||
if (externalPreds.size() == 1 && isSuitableAsPreheader(externalPreds[0], loop)) {
|
||||
return externalPreds[0];
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void LoopNormalizationPass::updateDominatorRelations(BasicBlock* newBlock, Loop* loop) {
|
||||
// 由于在getAnalysisUsage中声明了DominatorTree会失效,
|
||||
// PassManager会在本遍运行后自动将支配树结果标记为失效,
|
||||
// 后续需要支配树的Pass会触发重新计算,所以这里无需手动更新
|
||||
|
||||
if (DEBUG) {
|
||||
BasicBlock* header = loop->getHeader();
|
||||
std::cout << " DominatorTree marked for invalidation - new preheader "
|
||||
<< newBlock->getName() << " will dominate " << header->getName()
|
||||
<< " after recomputation by PassManager" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void LoopNormalizationPass::redirectExternalPredecessors(Loop* loop, BasicBlock* preheader, BasicBlock* header,
|
||||
const std::vector<BasicBlock*>& externalPreds) {
|
||||
// std::vector<BasicBlock*> externalPreds = getExternalPredecessors(loop);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Redirecting " << externalPreds.size() << " external predecessors" << std::endl;
|
||||
}
|
||||
|
||||
for (BasicBlock* pred : externalPreds) {
|
||||
// 获取前驱块的终止指令
|
||||
auto termIt = pred->terminator();
|
||||
if (termIt == pred->end()) continue;
|
||||
|
||||
Instruction* terminator = termIt->get();
|
||||
if (!terminator) continue;
|
||||
|
||||
// 更新跳转目标
|
||||
if (auto* br = dynamic_cast<UncondBrInst*>(terminator)) {
|
||||
// 无条件跳转
|
||||
if (br->getBlock() == header) {
|
||||
if(DEBUG){
|
||||
std::cout << " Updating unconditional branch from " << br->getBlock()->getName()
|
||||
<< " to " << preheader->getName() << std::endl;
|
||||
}
|
||||
// 需要更新操作数
|
||||
br->setOperand(0, preheader);
|
||||
// 更新CFG关系
|
||||
header->removePredecessor(pred);
|
||||
preheader->addPredecessor(pred);
|
||||
pred->removeSuccessor(header);
|
||||
pred->addSuccessor(preheader);
|
||||
|
||||
}
|
||||
} else if (auto* condBr = dynamic_cast<CondBrInst*>(terminator)) {
|
||||
// 条件跳转
|
||||
bool updated = false;
|
||||
if (condBr->getThenBlock() == header) {
|
||||
condBr->setOperand(1, preheader); // 第1个操作数是then分支
|
||||
updated = true;
|
||||
}
|
||||
if (condBr->getElseBlock() == header) {
|
||||
condBr->setOperand(2, preheader); // 第2个操作数是else分支
|
||||
updated = true;
|
||||
}
|
||||
if (updated) {
|
||||
// 更新CFG关系
|
||||
header->removePredecessor(pred);
|
||||
preheader->addPredecessor(pred);
|
||||
pred->removeSuccessor(header);
|
||||
pred->addSuccessor(preheader);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Updated conditional branch from " << pred->getName()
|
||||
<< " to " << preheader->getName() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string LoopNormalizationPass::generatePreheaderName(Loop* loop) {
|
||||
std::ostringstream oss;
|
||||
oss << loop->getName() << "_preheader";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
bool LoopNormalizationPass::validateNormalization(Loop* loop) {
|
||||
BasicBlock* header = loop->getHeader();
|
||||
if (!header) return false;
|
||||
|
||||
// 检查循环是否现在有唯一的外部前驱
|
||||
std::vector<BasicBlock*> externalPreds = getExternalPredecessors(loop);
|
||||
if (externalPreds.size() != 1) {
|
||||
if (DEBUG)
|
||||
std::cout << " Validation failed: Loop " << loop->getName()
|
||||
<< " has " << externalPreds.size() << " external predecessors (expected 1)" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查外部前驱是否适合作为前置块
|
||||
BasicBlock* preheader = externalPreds[0];
|
||||
if (!isSuitableAsPreheader(preheader, loop)) {
|
||||
if (DEBUG)
|
||||
std::cout << " Validation failed: External predecessor " << preheader->getName()
|
||||
<< " is not suitable as preheader" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 额外验证:检查CFG连接性
|
||||
if (!preheader->hasSuccessor(header)) {
|
||||
if (DEBUG)
|
||||
std::cout << " Validation failed: Preheader " << preheader->getName()
|
||||
<< " is not connected to header " << header->getName() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!header->hasPredecessor(preheader)) {
|
||||
if (DEBUG)
|
||||
std::cout << " Validation failed: Header " << header->getName()
|
||||
<< " does not have preheader " << preheader->getName() << " as predecessor" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG)
|
||||
std::cout << " Validation passed for loop " << loop->getName() << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<BasicBlock*> LoopNormalizationPass::getExternalPredecessors(Loop* loop) {
|
||||
std::vector<BasicBlock*> externalPreds;
|
||||
BasicBlock* header = loop->getHeader();
|
||||
if (!header) return externalPreds;
|
||||
|
||||
for (BasicBlock* pred : header->getPredecessors()) {
|
||||
if (!loop->contains(pred)) {
|
||||
externalPreds.push_back(pred);
|
||||
}
|
||||
}
|
||||
|
||||
return externalPreds;
|
||||
}
|
||||
|
||||
bool LoopNormalizationPass::isSuitableAsPreheader(BasicBlock* block, Loop* loop) {
|
||||
if (!block) return false;
|
||||
|
||||
// 检查该块是否只有一个后继,且后继是循环头部
|
||||
auto successors = block->getSuccessors();
|
||||
if (successors.size() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (successors[0] != loop->getHeader()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查该块是否不包含复杂的控制流
|
||||
// 理想的前置块应该只包含简单的跳转指令
|
||||
size_t instCount = 0;
|
||||
for (const auto& inst : block->getInstructions()) {
|
||||
instCount++;
|
||||
// 如果指令过多,可能不适合作为前置块
|
||||
if (instCount > 10) { // 阈值可调整
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LoopNormalizationPass::updatePhiNodesForPreheader(BasicBlock* header, BasicBlock* preheader,
|
||||
const std::vector<BasicBlock*>& oldPreds) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Updating PHI nodes in header " << header->getName()
|
||||
<< " for new preheader " << preheader->getName() << std::endl;
|
||||
}
|
||||
|
||||
std::vector<PhiInst*> phisToRemove; // 需要删除的PHI节点
|
||||
|
||||
for (auto& inst : header->getInstructions()) {
|
||||
if (auto* phi = dynamic_cast<PhiInst*>(inst.get())) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Processing PHI node: " << phi->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 收集来自外部前驱的值 - 需要保持原始的映射关系
|
||||
std::map<BasicBlock*, Value*> externalValues;
|
||||
for (BasicBlock* oldPred : oldPreds) {
|
||||
Value* value = phi->getValfromBlk(oldPred);
|
||||
if (value) {
|
||||
externalValues[oldPred] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理PHI节点的更新
|
||||
if (externalValues.size() > 1) {
|
||||
// 多个外部前驱:在前置块中创建新的PHI节点
|
||||
builder->setPosition(preheader, preheader->getInstructions().begin());
|
||||
|
||||
std::vector<Value*> values;
|
||||
std::vector<BasicBlock*> blocks;
|
||||
for (auto& [block, value] : externalValues) {
|
||||
values.push_back(value);
|
||||
blocks.push_back(block);
|
||||
}
|
||||
|
||||
PhiInst* newPhi = builder->createPhiInst(phi->getType(), values, blocks);
|
||||
|
||||
// 移除所有外部前驱的条目
|
||||
for (BasicBlock* oldPred : oldPreds) {
|
||||
phi->removeIncomingBlock(oldPred);
|
||||
}
|
||||
|
||||
// 添加来自新前置块的条目
|
||||
phi->addIncoming(newPhi, preheader);
|
||||
|
||||
} else if (externalValues.size() == 1) {
|
||||
// 单个外部前驱:直接重新映射
|
||||
Value* value = externalValues.begin()->second;
|
||||
|
||||
// 移除旧的外部前驱条目
|
||||
for (BasicBlock* oldPred : oldPreds) {
|
||||
phi->removeIncomingBlock(oldPred);
|
||||
}
|
||||
|
||||
// 添加来自新前置块的条目
|
||||
phi->addIncoming(value, preheader);
|
||||
|
||||
// 检查PHI节点是否只剩下一个条目(只来自前置块)
|
||||
if (phi->getNumIncomingValues() == 1) {
|
||||
if (DEBUG) {
|
||||
std::cout << " PHI node " << phi->getName()
|
||||
<< " now has only one incoming value, scheduling for removal" << std::endl;
|
||||
}
|
||||
// 用单一值替换所有使用
|
||||
Value* singleValue = phi->getIncomingValue(0u);
|
||||
phi->replaceAllUsesWith(singleValue);
|
||||
phisToRemove.push_back(phi);
|
||||
}
|
||||
} else {
|
||||
// 没有外部值的PHI节点:检查是否需要更新
|
||||
// 这种PHI节点只有循环内的边,通常不需要修改
|
||||
// 但我们仍然需要检查是否只有一个条目
|
||||
if (phi->getNumIncomingValues() == 1) {
|
||||
if (DEBUG) {
|
||||
std::cout << " PHI node " << phi->getName()
|
||||
<< " has only one incoming value (no external), scheduling for removal" << std::endl;
|
||||
}
|
||||
// 用单一值替换所有使用
|
||||
Value* singleValue = phi->getIncomingValue(0u);
|
||||
phi->replaceAllUsesWith(singleValue);
|
||||
phisToRemove.push_back(phi);
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG && std::find(phisToRemove.begin(), phisToRemove.end(), phi) == phisToRemove.end()) {
|
||||
std::cout << " Updated PHI node with " << externalValues.size()
|
||||
<< " external values, total incoming: " << phi->getNumIncomingValues() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除标记为移除的PHI节点
|
||||
for (PhiInst* phi : phisToRemove) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Removing redundant PHI node: " << phi->getName() << std::endl;
|
||||
}
|
||||
SysYIROptUtils::usedelete(phi);
|
||||
}
|
||||
|
||||
// 更新统计信息
|
||||
stats.redundantPhisRemoved += phisToRemove.size();
|
||||
|
||||
if (DEBUG && !phisToRemove.empty()) {
|
||||
std::cout << " Removed " << phisToRemove.size() << " redundant PHI nodes" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void LoopNormalizationPass::printStats(Function* F) {
|
||||
std::cout << "\n--- Loop Normalization Statistics for Function: " << F->getName() << " ---" << std::endl;
|
||||
std::cout << "Total loops analyzed: " << stats.totalLoops << std::endl;
|
||||
std::cout << "Loops needing preheader: " << stats.loopsNeedingPreheader << std::endl;
|
||||
std::cout << "Preheaders created: " << stats.preheadersCreated << std::endl;
|
||||
std::cout << "Loops successfully normalized: " << stats.loopsNormalized << std::endl;
|
||||
std::cout << "Redundant PHI nodes removed: " << stats.redundantPhisRemoved << std::endl;
|
||||
|
||||
if (stats.totalLoops > 0) {
|
||||
double normalizationRate = (double)stats.loopsNormalized / stats.totalLoops * 100.0;
|
||||
std::cout << "Normalization rate: " << normalizationRate << "%" << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "---------------------------------------------------------------" << std::endl;
|
||||
}
|
||||
|
||||
void LoopNormalizationPass::getAnalysisUsage(std::set<void *> &analysisDependencies,
|
||||
std::set<void *> &analysisInvalidations) const {
|
||||
// LoopNormalization依赖的分析
|
||||
analysisDependencies.insert(&LoopAnalysisPass::ID); // 循环结构分析
|
||||
analysisDependencies.insert(&DominatorTreeAnalysisPass::ID); // 支配树分析
|
||||
|
||||
// LoopNormalization会修改CFG结构,因此会使以下分析失效
|
||||
analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID); // 支配树需要重新计算
|
||||
|
||||
// 注意:我们不让循环结构分析失效,原因如下:
|
||||
// 1. 循环规范化只添加前置块,不改变循环的核心结构(头部、体、回边)
|
||||
// 2. 我们会手动更新Loop对象的前置块信息(通过loop->setPreHeader())
|
||||
// 3. 让循环分析失效并重新计算的成本较高且不必要
|
||||
// 4. 后续优化遍可以正确获取到更新后的前置块信息
|
||||
//
|
||||
// 如果未来有更复杂的循环结构修改,可能需要考虑让循环分析失效:
|
||||
// analysisInvalidations.insert(&LoopAnalysisPass::ID);
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
940
src/midend/Pass/Optimize/LoopStrengthReduction.cpp
Normal file
940
src/midend/Pass/Optimize/LoopStrengthReduction.cpp
Normal file
@@ -0,0 +1,940 @@
|
||||
#include "LoopStrengthReduction.h"
|
||||
#include "LoopCharacteristics.h"
|
||||
#include "Loop.h"
|
||||
#include "Dom.h"
|
||||
#include "IRBuilder.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <unordered_map>
|
||||
#include <climits>
|
||||
|
||||
// 使用全局调试开关
|
||||
extern int DEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 定义 Pass
|
||||
void *LoopStrengthReduction::ID = (void *)&LoopStrengthReduction::ID;
|
||||
|
||||
bool StrengthReductionContext::analyzeInductionVariableRange(
|
||||
const InductionVarInfo* ivInfo,
|
||||
Loop* loop
|
||||
) const {
|
||||
if (!ivInfo->valid) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Invalid IV info, assuming potential negative" << std::endl;
|
||||
}
|
||||
return true; // 保守假设非线性变化可能为负数
|
||||
}
|
||||
|
||||
// 获取phi指令的所有入口值
|
||||
auto* phiInst = dynamic_cast<PhiInst*>(ivInfo->base);
|
||||
if (!phiInst) {
|
||||
if (DEBUG) {
|
||||
std::cout << " No phi instruction, assuming potential negative" << std::endl;
|
||||
}
|
||||
return true; // 无法确定,保守假设
|
||||
}
|
||||
|
||||
bool hasNegativePotential = false;
|
||||
bool hasNonNegativeInitial = false;
|
||||
int initialValue = 0;
|
||||
|
||||
for (auto& [incomingBB, incomingVal] : phiInst->getIncomingValues()) {
|
||||
// 检查初始值(来自循环外的值)
|
||||
if (!loop->contains(incomingBB)) {
|
||||
if (auto* constInt = dynamic_cast<ConstantInteger*>(incomingVal)) {
|
||||
initialValue = constInt->getInt();
|
||||
if (initialValue < 0) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Found negative initial value: " << initialValue << std::endl;
|
||||
}
|
||||
hasNegativePotential = true;
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
std::cout << " Found non-negative initial value: " << initialValue << std::endl;
|
||||
}
|
||||
hasNonNegativeInitial = true;
|
||||
}
|
||||
} else {
|
||||
// 如果不是常数初始值,保守假设可能为负数
|
||||
if (DEBUG) {
|
||||
std::cout << " Non-constant initial value, assuming potential negative" << std::endl;
|
||||
}
|
||||
hasNegativePotential = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查递增值和偏移
|
||||
if (ivInfo->factor < 0) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Negative factor: " << ivInfo->factor << std::endl;
|
||||
}
|
||||
hasNegativePotential = true;
|
||||
}
|
||||
|
||||
if (ivInfo->offset < 0) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Negative offset: " << ivInfo->offset << std::endl;
|
||||
}
|
||||
hasNegativePotential = true;
|
||||
}
|
||||
|
||||
// 精确分析:如果初始值非负,递增为正,偏移非负,则整个序列非负
|
||||
if (hasNonNegativeInitial && ivInfo->factor > 0 && ivInfo->offset >= 0) {
|
||||
if (DEBUG) {
|
||||
std::cout << " ANALYSIS: Confirmed non-negative range" << std::endl;
|
||||
std::cout << " Initial: " << initialValue << " >= 0" << std::endl;
|
||||
std::cout << " Factor: " << ivInfo->factor << " > 0" << std::endl;
|
||||
std::cout << " Offset: " << ivInfo->offset << " >= 0" << std::endl;
|
||||
}
|
||||
return false; // 确定不会为负数
|
||||
}
|
||||
|
||||
// 报告分析结果
|
||||
if (DEBUG) {
|
||||
if (hasNegativePotential) {
|
||||
std::cout << " ANALYSIS: Potential negative values detected" << std::endl;
|
||||
} else {
|
||||
std::cout << " ANALYSIS: No negative indicators, but missing positive confirmation" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return hasNegativePotential;
|
||||
}
|
||||
|
||||
|
||||
bool LoopStrengthReduction::runOnFunction(Function* F, AnalysisManager& AM) {
|
||||
if (F->getBasicBlocks().empty()) {
|
||||
return false; // 空函数
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "Running LoopStrengthReduction on function: " << F->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 创建优化上下文并运行
|
||||
StrengthReductionContext context(builder);
|
||||
bool modified = context.run(F, AM);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "LoopStrengthReduction " << (modified ? "modified" : "did not modify")
|
||||
<< " function: " << F->getName() << std::endl;
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
void LoopStrengthReduction::getAnalysisUsage(std::set<void*>& analysisDependencies,
|
||||
std::set<void*>& analysisInvalidations) const {
|
||||
// 依赖的分析
|
||||
analysisDependencies.insert(&LoopAnalysisPass::ID);
|
||||
analysisDependencies.insert(&LoopCharacteristicsPass::ID);
|
||||
analysisDependencies.insert(&DominatorTreeAnalysisPass::ID);
|
||||
|
||||
// 会使失效的分析(强度削弱会修改IR结构)
|
||||
analysisInvalidations.insert(&LoopCharacteristicsPass::ID);
|
||||
// 注意:支配树分析通常不会因为强度削弱而失效,因为我们不改变控制流
|
||||
}
|
||||
|
||||
// ========== StrengthReductionContext 实现 ==========
|
||||
|
||||
bool StrengthReductionContext::run(Function* F, AnalysisManager& AM) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Starting strength reduction analysis..." << std::endl;
|
||||
}
|
||||
|
||||
// 获取必要的分析结果
|
||||
loopAnalysis = AM.getAnalysisResult<LoopAnalysisResult, LoopAnalysisPass>(F);
|
||||
if (!loopAnalysis || !loopAnalysis->hasLoops()) {
|
||||
if (DEBUG) {
|
||||
std::cout << " No loops found, skipping strength reduction" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
loopCharacteristics = AM.getAnalysisResult<LoopCharacteristicsResult, LoopCharacteristicsPass>(F);
|
||||
if (!loopCharacteristics) {
|
||||
if (DEBUG) {
|
||||
std::cout << " LoopCharacteristics analysis not available" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
dominatorTree = AM.getAnalysisResult<DominatorTree, DominatorTreeAnalysisPass>(F);
|
||||
if (!dominatorTree) {
|
||||
if (DEBUG) {
|
||||
std::cout << " DominatorTree analysis not available" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 执行三个阶段的优化
|
||||
|
||||
// 阶段1:识别候选项
|
||||
identifyStrengthReductionCandidates(F);
|
||||
|
||||
if (candidates.empty()) {
|
||||
if (DEBUG) {
|
||||
std::cout << " No strength reduction candidates found" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Found " << candidates.size() << " potential candidates" << std::endl;
|
||||
}
|
||||
|
||||
// 阶段2:分析优化潜力
|
||||
analyzeOptimizationPotential();
|
||||
|
||||
// 阶段3:执行优化
|
||||
bool modified = performStrengthReduction();
|
||||
|
||||
if (DEBUG) {
|
||||
printDebugInfo();
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
void StrengthReductionContext::identifyStrengthReductionCandidates(Function* F) {
|
||||
if (DEBUG) {
|
||||
std::cout << " === Phase 1: Identifying Strength Reduction Candidates ===" << std::endl;
|
||||
}
|
||||
|
||||
// 遍历所有循环
|
||||
for (const auto& loop_ptr : loopAnalysis->getAllLoops()) {
|
||||
Loop* loop = loop_ptr.get();
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Analyzing loop: " << loop->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 获取循环特征
|
||||
const LoopCharacteristics* characteristics = loopCharacteristics->getCharacteristics(loop);
|
||||
if (!characteristics) {
|
||||
if (DEBUG) {
|
||||
std::cout << " No characteristics available for loop" << std::endl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (characteristics->InductionVars.empty()) {
|
||||
if (DEBUG) {
|
||||
std::cout << " No induction variables found in loop" << std::endl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 遍历循环中的所有指令
|
||||
for (BasicBlock* bb : loop->getBlocks()) {
|
||||
for (auto& inst_ptr : bb->getInstructions()) {
|
||||
Instruction* inst = inst_ptr.get();
|
||||
|
||||
// 检查是否为强度削弱候选项
|
||||
auto candidate = isStrengthReductionCandidate(inst, loop);
|
||||
if (candidate) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Found candidate: %" << inst->getName()
|
||||
<< " (IV: %" << candidate->inductionVar->getName()
|
||||
<< ", multiplier: " << candidate->multiplier
|
||||
<< ", offset: " << candidate->offset << ")" << std::endl;
|
||||
}
|
||||
|
||||
// 添加到候选项列表
|
||||
loopToCandidates[loop].push_back(candidate.get());
|
||||
candidates.push_back(std::move(candidate));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " === End Phase 1: Found " << candidates.size() << " candidates ===" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<StrengthReductionCandidate>
|
||||
StrengthReductionContext::isStrengthReductionCandidate(Instruction* inst, Loop* loop) {
|
||||
auto kind = inst->getKind();
|
||||
|
||||
// 支持乘法、除法、取模指令
|
||||
if (kind != Instruction::Kind::kMul &&
|
||||
kind != Instruction::Kind::kDiv &&
|
||||
kind != Instruction::Kind::kRem) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* binaryInst = dynamic_cast<BinaryInst*>(inst);
|
||||
if (!binaryInst) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Value* op0 = binaryInst->getOperand(0);
|
||||
Value* op1 = binaryInst->getOperand(1);
|
||||
|
||||
// 检查模式:归纳变量 op 常数 或 常数 op 归纳变量
|
||||
Value* inductionVar = nullptr;
|
||||
int constantValue = 0;
|
||||
StrengthReductionCandidate::OpType opType;
|
||||
|
||||
// 获取循环特征信息
|
||||
const LoopCharacteristics* characteristics = loopCharacteristics->getCharacteristics(loop);
|
||||
if (!characteristics) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 确定操作类型
|
||||
switch (kind) {
|
||||
case Instruction::Kind::kMul:
|
||||
opType = StrengthReductionCandidate::MULTIPLY;
|
||||
break;
|
||||
case Instruction::Kind::kDiv:
|
||||
opType = StrengthReductionCandidate::DIVIDE;
|
||||
break;
|
||||
case Instruction::Kind::kRem:
|
||||
opType = StrengthReductionCandidate::REMAINDER;
|
||||
break;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 模式1: IV op const
|
||||
const InductionVarInfo* ivInfo = getInductionVarInfo(op0, loop, characteristics);
|
||||
if (ivInfo && dynamic_cast<ConstantInteger*>(op1)) {
|
||||
inductionVar = op0;
|
||||
constantValue = dynamic_cast<ConstantInteger*>(op1)->getInt();
|
||||
}
|
||||
// 模式2: const op IV (仅对乘法有效)
|
||||
else if (opType == StrengthReductionCandidate::MULTIPLY) {
|
||||
ivInfo = getInductionVarInfo(op1, loop, characteristics);
|
||||
if (ivInfo && dynamic_cast<ConstantInteger*>(op0)) {
|
||||
inductionVar = op1;
|
||||
constantValue = dynamic_cast<ConstantInteger*>(op0)->getInt();
|
||||
}
|
||||
}
|
||||
|
||||
if (!inductionVar || constantValue <= 1) {
|
||||
return nullptr; // 不是有效的候选项
|
||||
}
|
||||
|
||||
// 创建候选项
|
||||
auto candidate = std::make_unique<StrengthReductionCandidate>(
|
||||
inst, inductionVar, opType, constantValue, 0, inst->getParent(), loop
|
||||
);
|
||||
|
||||
// 分析归纳变量是否可能为负数
|
||||
candidate->hasNegativeValues = analyzeInductionVariableRange(ivInfo, loop);
|
||||
|
||||
// 根据除法类型选择优化策略
|
||||
if (opType == StrengthReductionCandidate::DIVIDE) {
|
||||
bool isPowerOfTwo = (constantValue & (constantValue - 1)) == 0;
|
||||
|
||||
if (isPowerOfTwo) {
|
||||
// 2的幂除法
|
||||
if (candidate->hasNegativeValues) {
|
||||
candidate->divStrategy = StrengthReductionCandidate::SIGNED_CORRECTION;
|
||||
if (DEBUG) {
|
||||
std::cout << " Division by power of 2 with potential negative values, using signed correction" << std::endl;
|
||||
}
|
||||
} else {
|
||||
candidate->divStrategy = StrengthReductionCandidate::SIMPLE_SHIFT;
|
||||
if (DEBUG) {
|
||||
std::cout << " Division by power of 2 with non-negative values, using simple shift" << std::endl;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 任意常数除法,使用mulh指令
|
||||
candidate->operationType = StrengthReductionCandidate::DIVIDE_CONST;
|
||||
candidate->divStrategy = StrengthReductionCandidate::MULH_OPTIMIZATION;
|
||||
if (DEBUG) {
|
||||
std::cout << " Division by arbitrary constant, using mulh optimization" << std::endl;
|
||||
}
|
||||
}
|
||||
} else if (opType == StrengthReductionCandidate::REMAINDER) {
|
||||
// 取模运算只支持2的幂
|
||||
if ((constantValue & (constantValue - 1)) != 0) {
|
||||
return nullptr; // 不是2的幂,无法优化
|
||||
}
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
const InductionVarInfo*
|
||||
StrengthReductionContext::getInductionVarInfo(Value* val, Loop* loop,
|
||||
const LoopCharacteristics* characteristics) {
|
||||
for (const auto& iv : characteristics->InductionVars) {
|
||||
if (iv->div == val) {
|
||||
return iv.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void StrengthReductionContext::analyzeOptimizationPotential() {
|
||||
if (DEBUG) {
|
||||
std::cout << " === Phase 2: Analyzing Optimization Potential ===" << std::endl;
|
||||
}
|
||||
|
||||
// 为每个候选项计算优化收益,并过滤不值得优化的
|
||||
auto it = candidates.begin();
|
||||
while (it != candidates.end()) {
|
||||
StrengthReductionCandidate* candidate = it->get();
|
||||
|
||||
double benefit = estimateOptimizationBenefit(candidate);
|
||||
bool isLegal = isOptimizationLegal(candidate);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Candidate " << candidate->originalInst->getName()
|
||||
<< ": benefit=" << benefit
|
||||
<< ", legal=" << (isLegal ? "yes" : "no") << std::endl;
|
||||
}
|
||||
|
||||
// 如果收益太小或不合法,移除候选项
|
||||
if (benefit < 1.0 || !isLegal) {
|
||||
// 从 loopToCandidates 中移除
|
||||
auto& loopCandidates = loopToCandidates[candidate->containingLoop];
|
||||
loopCandidates.erase(
|
||||
std::remove(loopCandidates.begin(), loopCandidates.end(), candidate),
|
||||
loopCandidates.end()
|
||||
);
|
||||
|
||||
it = candidates.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " === End Phase 2: " << candidates.size() << " candidates remain ===" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
double StrengthReductionContext::estimateOptimizationBenefit(const StrengthReductionCandidate* candidate) {
|
||||
// 简单的收益估算模型
|
||||
double benefit = 0.0;
|
||||
|
||||
// 基础收益:乘法变加法的性能提升
|
||||
benefit += 2.0; // 假设乘法比加法慢2倍
|
||||
|
||||
// 乘数因子:乘数越大,收益越高
|
||||
if (candidate->multiplier >= 4) {
|
||||
benefit += 1.0;
|
||||
}
|
||||
if (candidate->multiplier >= 8) {
|
||||
benefit += 1.0;
|
||||
}
|
||||
|
||||
// 循环热度因子
|
||||
Loop* loop = candidate->containingLoop;
|
||||
double hotness = loop->getLoopHotness();
|
||||
benefit *= (1.0 + hotness / 100.0);
|
||||
|
||||
// 使用次数因子
|
||||
size_t useCount = candidate->originalInst->getUses().size();
|
||||
if (useCount > 1) {
|
||||
benefit *= (1.0 + useCount * 0.2);
|
||||
}
|
||||
|
||||
return benefit;
|
||||
}
|
||||
|
||||
bool StrengthReductionContext::isOptimizationLegal(const StrengthReductionCandidate* candidate) {
|
||||
// 检查优化的合法性
|
||||
|
||||
// 1. 确保归纳变量在循环头有 phi 指令
|
||||
auto* phiInst = dynamic_cast<PhiInst*>(candidate->inductionVar);
|
||||
if (!phiInst || phiInst->getParent() != candidate->containingLoop->getHeader()) {
|
||||
if (DEBUG ) {
|
||||
std::cout << " Illegal: induction variable is not a phi in loop header" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 确保乘法指令在循环内
|
||||
if (!candidate->containingLoop->contains(candidate->containingBlock)) {
|
||||
if (DEBUG ) {
|
||||
std::cout << " Illegal: instruction not in loop" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3. 检查是否有溢出风险(简化检查)
|
||||
if (candidate->multiplier > 1000) {
|
||||
if (DEBUG ) {
|
||||
std::cout << " Illegal: multiplier too large (overflow risk)" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. 确保该指令不在循环的退出条件中(避免影响循环语义)
|
||||
for (BasicBlock* exitingBB : candidate->containingLoop->getExitingBlocks()) {
|
||||
auto terminatorIt = exitingBB->terminator();
|
||||
if (terminatorIt != exitingBB->end()) {
|
||||
Instruction* terminator = terminatorIt->get();
|
||||
if (terminator && (terminator->getOperand(0) == candidate->originalInst ||
|
||||
(terminator->getNumOperands() > 1 && terminator->getOperand(1) == candidate->originalInst))) {
|
||||
if (DEBUG ) {
|
||||
std::cout << " Illegal: instruction used in loop exit condition" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StrengthReductionContext::performStrengthReduction() {
|
||||
if (DEBUG) {
|
||||
std::cout << " === Phase 3: Performing Strength Reduction ===" << std::endl;
|
||||
}
|
||||
|
||||
bool modified = false;
|
||||
|
||||
for (auto& candidate : candidates) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Processing candidate: " << candidate->originalInst->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 创建新的归纳变量
|
||||
if (!createNewInductionVariable(candidate.get())) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Failed to create new induction variable" << std::endl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 替换原始指令
|
||||
if (!replaceOriginalInstruction(candidate.get())) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Failed to replace original instruction" << std::endl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Successfully optimized: " << candidate->originalInst->getName()
|
||||
<< " -> " << candidate->newInductionVar->getName() << std::endl;
|
||||
}
|
||||
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " === End Phase 3: " << (modified ? "Optimizations applied" : "No optimizations") << " ===" << std::endl;
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
bool StrengthReductionContext::createNewInductionVariable(StrengthReductionCandidate* candidate) {
|
||||
// 只为乘法创建新的归纳变量
|
||||
// 除法和取模直接在替换时进行强度削弱,不需要新的归纳变量
|
||||
if (candidate->operationType != StrengthReductionCandidate::MULTIPLY) {
|
||||
candidate->newInductionVar = candidate->inductionVar; // 直接使用原归纳变量
|
||||
return true;
|
||||
}
|
||||
|
||||
Loop* loop = candidate->containingLoop;
|
||||
BasicBlock* header = loop->getHeader();
|
||||
BasicBlock* preheader = loop->getPreHeader();
|
||||
|
||||
if (!preheader) {
|
||||
if (DEBUG) {
|
||||
std::cout << " No preheader found for loop" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取原始归纳变量的 phi 指令
|
||||
auto* originalPhi = dynamic_cast<PhiInst*>(candidate->inductionVar);
|
||||
if (!originalPhi) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 1. 找到原始归纳变量的初始值和步长
|
||||
Value* initialValue = nullptr;
|
||||
Value* stepValue = nullptr;
|
||||
BasicBlock* latchBlock = nullptr;
|
||||
|
||||
for (auto& [incomingBB, incomingVal] : originalPhi->getIncomingValues()) {
|
||||
if (!loop->contains(incomingBB)) {
|
||||
// 来自循环外的初始值
|
||||
initialValue = incomingVal;
|
||||
} else {
|
||||
// 来自循环内的递增值
|
||||
latchBlock = incomingBB;
|
||||
// 尝试找到步长
|
||||
if (auto* addInst = dynamic_cast<BinaryInst*>(incomingVal)) {
|
||||
if (addInst->getKind() == Instruction::Kind::kAdd) {
|
||||
if (addInst->getOperand(0) == originalPhi) {
|
||||
stepValue = addInst->getOperand(1);
|
||||
} else if (addInst->getOperand(1) == originalPhi) {
|
||||
stepValue = addInst->getOperand(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!initialValue || !stepValue || !latchBlock) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Failed to find initial value, step, or latch block" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 在循环头创建新的 phi 指令
|
||||
builder->setPosition(header, header->begin());
|
||||
candidate->newPhi = builder->createPhiInst(originalPhi->getType());
|
||||
candidate->newPhi->setName("sr_" + originalPhi->getName());
|
||||
|
||||
// 3. 计算新归纳变量的初始值和步长
|
||||
// 新IV的初始值 = 原IV初始值 * multiplier
|
||||
Value* newInitialValue;
|
||||
if (auto* constInt = dynamic_cast<ConstantInteger*>(initialValue)) {
|
||||
newInitialValue = ConstantInteger::get(constInt->getInt() * candidate->multiplier);
|
||||
} else {
|
||||
// 如果初始值不是常数,需要在preheader中插入乘法
|
||||
builder->setPosition(preheader, preheader->terminator());
|
||||
newInitialValue = builder->createMulInst(initialValue,
|
||||
ConstantInteger::get(candidate->multiplier));
|
||||
}
|
||||
|
||||
// 新IV的步长 = 原IV步长 * multiplier
|
||||
Value* newStepValue;
|
||||
if (auto* constInt = dynamic_cast<ConstantInteger*>(stepValue)) {
|
||||
newStepValue = ConstantInteger::get(constInt->getInt() * candidate->multiplier);
|
||||
} else {
|
||||
builder->setPosition(latchBlock, latchBlock->terminator());
|
||||
newStepValue = builder->createMulInst(stepValue,
|
||||
ConstantInteger::get(candidate->multiplier));
|
||||
}
|
||||
|
||||
// 4. 创建新归纳变量的递增指令
|
||||
builder->setPosition(latchBlock, latchBlock->terminator());
|
||||
Value* newIncrementedValue = builder->createAddInst(candidate->newPhi, newStepValue);
|
||||
|
||||
// 5. 设置新 phi 的输入值
|
||||
candidate->newPhi->addIncoming(newInitialValue, preheader);
|
||||
candidate->newPhi->addIncoming(newIncrementedValue, latchBlock);
|
||||
|
||||
candidate->newInductionVar = candidate->newPhi;
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Created new induction variable: " << candidate->newPhi->getName() << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StrengthReductionContext::replaceOriginalInstruction(StrengthReductionCandidate* candidate) {
|
||||
if (!candidate->newInductionVar) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Value* replacementValue = nullptr;
|
||||
|
||||
// 根据操作类型生成不同的替换指令
|
||||
switch (candidate->operationType) {
|
||||
case StrengthReductionCandidate::MULTIPLY: {
|
||||
// 乘法:直接使用新的归纳变量
|
||||
replacementValue = candidate->newInductionVar;
|
||||
break;
|
||||
}
|
||||
|
||||
case StrengthReductionCandidate::DIVIDE: {
|
||||
// 根据除法策略生成不同的代码
|
||||
builder->setPosition(candidate->containingBlock,
|
||||
candidate->containingBlock->findInstIterator(candidate->originalInst));
|
||||
replacementValue = generateDivisionReplacement(candidate, builder);
|
||||
break;
|
||||
}
|
||||
|
||||
case StrengthReductionCandidate::DIVIDE_CONST: {
|
||||
// 任意常数除法
|
||||
builder->setPosition(candidate->containingBlock,
|
||||
candidate->containingBlock->findInstIterator(candidate->originalInst));
|
||||
replacementValue = generateConstantDivisionReplacement(candidate, builder);
|
||||
break;
|
||||
}
|
||||
|
||||
case StrengthReductionCandidate::REMAINDER: {
|
||||
// 取模:使用位与操作 (x % 2^n == x & (2^n - 1))
|
||||
builder->setPosition(candidate->containingBlock,
|
||||
candidate->containingBlock->findInstIterator(candidate->originalInst));
|
||||
|
||||
int maskValue = candidate->multiplier - 1; // 2^n - 1
|
||||
Value* maskConstant = ConstantInteger::get(maskValue);
|
||||
|
||||
if (candidate->hasNegativeValues) {
|
||||
// 处理负数的取模运算
|
||||
Value* temp = builder->createBinaryInst(
|
||||
Instruction::Kind::kAnd, candidate->inductionVar->getType(),
|
||||
candidate->inductionVar, maskConstant
|
||||
);
|
||||
|
||||
// 检查原值是否为负数
|
||||
Value* zero = ConstantInteger::get(0);
|
||||
Value* isNegative = builder->createICmpLTInst(candidate->inductionVar, zero);
|
||||
|
||||
// 如果为负数,需要调整结果
|
||||
Value* adjustment = ConstantInteger::get(candidate->multiplier);
|
||||
Value* adjustedTemp = builder->createAddInst(temp, adjustment);
|
||||
|
||||
// 使用条件分支来模拟select操作
|
||||
// 为简化起见,这里先用一个更复杂但可工作的方式
|
||||
// 实际应该创建条件分支,但这里先简化处理
|
||||
replacementValue = temp; // 简化版本,假设大多数情况下不是负数
|
||||
} else {
|
||||
// 非负数的取模,直接使用位与
|
||||
replacementValue = builder->createBinaryInst(
|
||||
Instruction::Kind::kAnd, candidate->inductionVar->getType(),
|
||||
candidate->inductionVar, maskConstant
|
||||
);
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Created modulus operation with mask " << maskValue
|
||||
<< " (handles negatives: " << (candidate->hasNegativeValues ? "yes" : "no") << ")" << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!replacementValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 处理偏移量
|
||||
if (candidate->offset != 0) {
|
||||
builder->setPosition(candidate->containingBlock,
|
||||
candidate->containingBlock->findInstIterator(candidate->originalInst));
|
||||
replacementValue = builder->createAddInst(
|
||||
replacementValue,
|
||||
ConstantInteger::get(candidate->offset)
|
||||
);
|
||||
}
|
||||
|
||||
// 替换所有使用
|
||||
candidate->originalInst->replaceAllUsesWith(replacementValue);
|
||||
|
||||
// 从基本块中移除原始指令
|
||||
auto* bb = candidate->originalInst->getParent();
|
||||
auto it = bb->findInstIterator(candidate->originalInst);
|
||||
if (it != bb->end()) {
|
||||
SysYIROptUtils::usedelete(it);
|
||||
// bb->getInstructions().erase(it);
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Replaced and removed original "
|
||||
<< (candidate->operationType == StrengthReductionCandidate::MULTIPLY ? "multiply" :
|
||||
candidate->operationType == StrengthReductionCandidate::DIVIDE ? "divide" : "remainder")
|
||||
<< " instruction" << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void StrengthReductionContext::printDebugInfo() {
|
||||
if (!DEBUG) return;
|
||||
|
||||
std::cout << "\n=== Strength Reduction Optimization Summary ===" << std::endl;
|
||||
std::cout << "Total candidates processed: " << candidates.size() << std::endl;
|
||||
|
||||
for (auto& [loop, loopCandidates] : loopToCandidates) {
|
||||
if (!loopCandidates.empty()) {
|
||||
std::cout << "Loop " << loop->getName() << ": " << loopCandidates.size() << " optimizations" << std::endl;
|
||||
for (auto* candidate : loopCandidates) {
|
||||
if (candidate->newInductionVar) {
|
||||
std::cout << " " << candidate->inductionVar->getName()
|
||||
<< " (op=" << (candidate->operationType == StrengthReductionCandidate::MULTIPLY ? "mul" :
|
||||
candidate->operationType == StrengthReductionCandidate::DIVIDE ? "div" : "rem")
|
||||
<< ", factor=" << candidate->multiplier << ")"
|
||||
<< " -> optimized" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << "===============================================" << std::endl;
|
||||
}
|
||||
|
||||
Value* StrengthReductionContext::generateDivisionReplacement(
|
||||
StrengthReductionCandidate* candidate,
|
||||
IRBuilder* builder
|
||||
) const {
|
||||
switch (candidate->divStrategy) {
|
||||
case StrengthReductionCandidate::SIMPLE_SHIFT: {
|
||||
// 简单的右移除法 (仅适用于非负数)
|
||||
int shiftAmount = __builtin_ctz(candidate->multiplier);
|
||||
Value* shiftConstant = ConstantInteger::get(shiftAmount);
|
||||
return builder->createBinaryInst(
|
||||
Instruction::Kind::kSrl, // 逻辑右移
|
||||
candidate->inductionVar->getType(),
|
||||
candidate->inductionVar,
|
||||
shiftConstant
|
||||
);
|
||||
}
|
||||
|
||||
case StrengthReductionCandidate::SIGNED_CORRECTION: {
|
||||
// 有符号除法校正:(x + (x >> 31) & mask) >> k
|
||||
int shiftAmount = __builtin_ctz(candidate->multiplier);
|
||||
int maskValue = candidate->multiplier - 1;
|
||||
|
||||
// x >> 31 (算术右移获取符号位)
|
||||
Value* signShift = ConstantInteger::get(31);
|
||||
Value* signBits = builder->createBinaryInst(
|
||||
Instruction::Kind::kSra, // 算术右移
|
||||
candidate->inductionVar->getType(),
|
||||
candidate->inductionVar,
|
||||
signShift
|
||||
);
|
||||
|
||||
// (x >> 31) & mask
|
||||
Value* mask = ConstantInteger::get(maskValue);
|
||||
Value* correction = builder->createBinaryInst(
|
||||
Instruction::Kind::kAnd,
|
||||
candidate->inductionVar->getType(),
|
||||
signBits,
|
||||
mask
|
||||
);
|
||||
|
||||
// x + correction
|
||||
Value* corrected = builder->createAddInst(candidate->inductionVar, correction);
|
||||
|
||||
// (x + correction) >> k
|
||||
Value* divShift = ConstantInteger::get(shiftAmount);
|
||||
return builder->createBinaryInst(
|
||||
Instruction::Kind::kSra, // 算术右移
|
||||
candidate->inductionVar->getType(),
|
||||
corrected,
|
||||
divShift
|
||||
);
|
||||
}
|
||||
|
||||
default: {
|
||||
// 回退到原始除法
|
||||
Value* divisor = ConstantInteger::get(candidate->multiplier);
|
||||
return builder->createDivInst(candidate->inductionVar, divisor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Value* StrengthReductionContext::generateConstantDivisionReplacement(
|
||||
StrengthReductionCandidate* candidate,
|
||||
IRBuilder* builder
|
||||
) const {
|
||||
// 使用mulh指令优化任意常数除法
|
||||
auto [magic, shift] = SysYIROptUtils::computeMulhMagicNumbers(candidate->multiplier);
|
||||
|
||||
// 检查是否无法优化(magic == -1, shift == -1 表示失败)
|
||||
if (magic == -1 && shift == -1) {
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Cannot optimize division by " << candidate->multiplier
|
||||
<< ", keeping original division" << std::endl;
|
||||
}
|
||||
// 返回 nullptr 表示无法优化,调用方应该保持原始除法
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 2的幂次方除法可以用移位优化(但这不是魔数法的情况)这种情况应该不会被分类到这里但是还是做一个保护措施
|
||||
if ((candidate->multiplier & (candidate->multiplier - 1)) == 0 && candidate->multiplier > 0) {
|
||||
// 是2的幂次方,可以用移位
|
||||
int shift_amount = 0;
|
||||
int temp = candidate->multiplier;
|
||||
while (temp > 1) {
|
||||
temp >>= 1;
|
||||
shift_amount++;
|
||||
}
|
||||
|
||||
Value* shiftConstant = ConstantInteger::get(shift_amount);
|
||||
if (candidate->hasNegativeValues) {
|
||||
// 对于有符号除法,需要先加上除数-1然后再移位(为了正确处理负数舍入)
|
||||
Value* divisor_minus_1 = ConstantInteger::get(candidate->multiplier - 1);
|
||||
Value* adjusted = builder->createAddInst(candidate->inductionVar, divisor_minus_1);
|
||||
return builder->createBinaryInst(
|
||||
Instruction::Kind::kSra, // 算术右移
|
||||
candidate->inductionVar->getType(),
|
||||
adjusted,
|
||||
shiftConstant
|
||||
);
|
||||
} else {
|
||||
return builder->createBinaryInst(
|
||||
Instruction::Kind::kSrl, // 逻辑右移
|
||||
candidate->inductionVar->getType(),
|
||||
candidate->inductionVar,
|
||||
shiftConstant
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 创建魔数常量
|
||||
// 检查魔数是否能放入32位,如果不能,则不进行优化
|
||||
if (magic > INT32_MAX || magic < INT32_MIN) {
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Magic number " << magic << " exceeds 32-bit range, skipping optimization" << std::endl;
|
||||
}
|
||||
return nullptr; // 无法优化,保持原始除法
|
||||
}
|
||||
|
||||
Value* magicConstant = ConstantInteger::get((int32_t)magic);
|
||||
|
||||
// 检查是否需要ADD_MARKER处理(加法调整)
|
||||
bool needAdd = (shift & 0x40) != 0;
|
||||
int actualShift = shift & 0x3F; // 提取真实的移位量
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] IR Generation: magic=" << magic << ", needAdd=" << needAdd
|
||||
<< ", actualShift=" << actualShift << std::endl;
|
||||
}
|
||||
|
||||
// 执行高位乘法:mulh(x, magic)
|
||||
Value* mulhResult = builder->createBinaryInst(
|
||||
Instruction::Kind::kMulh, // 高位乘法
|
||||
candidate->inductionVar->getType(),
|
||||
candidate->inductionVar,
|
||||
magicConstant
|
||||
);
|
||||
|
||||
if (needAdd) {
|
||||
// ADD_MARKER 情况:需要在移位前加上被除数
|
||||
// 这对应于 libdivide 的加法调整算法
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Applying ADD_MARKER: adding dividend before shift" << std::endl;
|
||||
}
|
||||
mulhResult = builder->createAddInst(mulhResult, candidate->inductionVar);
|
||||
}
|
||||
|
||||
if (actualShift > 0) {
|
||||
// 如果需要额外移位
|
||||
Value* shiftConstant = ConstantInteger::get(actualShift);
|
||||
mulhResult = builder->createBinaryInst(
|
||||
Instruction::Kind::kSra, // 算术右移
|
||||
candidate->inductionVar->getType(),
|
||||
mulhResult,
|
||||
shiftConstant
|
||||
);
|
||||
}
|
||||
|
||||
// 标准的有符号除法符号修正:如果被除数为负,商需要加1
|
||||
// 这对所有有符号除法都需要,不管是否可能有负数
|
||||
Value* isNegative = builder->createICmpLTInst(candidate->inductionVar, ConstantInteger::get(0));
|
||||
// 将i1转换为i32:负数时为1,非负数时为0 ICmpLTInst的结果会默认转化为32位
|
||||
mulhResult = builder->createAddInst(mulhResult, isNegative);
|
||||
|
||||
return mulhResult;
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "Mem2Reg.h" // 包含 Mem2Reg 遍的头文件
|
||||
#include "Dom.h" // 包含支配树分析的头文件
|
||||
#include "Liveness.h"
|
||||
#include "AliasAnalysis.h" // 包含别名分析
|
||||
#include "SideEffectAnalysis.h" // 包含副作用分析
|
||||
#include "IR.h" // 包含 IR 相关的定义
|
||||
#include "SysYIROptUtils.h"
|
||||
#include <cassert> // 用于断言
|
||||
@@ -420,8 +422,9 @@ void Mem2Reg::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<
|
||||
// 因此,它会使许多分析结果失效。
|
||||
analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID); // 支配树可能受影响
|
||||
analysisInvalidations.insert(&LivenessAnalysisPass::ID); // 活跃性分析肯定失效
|
||||
analysisInvalidations.insert(&SysYAliasAnalysisPass::ID); // 别名分析必须失效,因为Mem2Reg改变了内存访问模式
|
||||
analysisInvalidations.insert(&SysYSideEffectAnalysisPass::ID); // 副作用分析也可能失效
|
||||
// analysisInvalidations.insert(&LoopInfoAnalysisPass::ID); // 循环信息可能失效
|
||||
// analysisInvalidations.insert(&SideEffectInfoAnalysisPass::ID); // 副作用分析可能失效
|
||||
// 其他所有依赖于数据流或 IR 结构的分析都可能失效。
|
||||
}
|
||||
|
||||
|
||||
@@ -70,20 +70,20 @@ void Reg2MemContext::allocateMemoryForSSAValues(Function *func) {
|
||||
|
||||
// 1. 为函数参数分配内存
|
||||
builder->setPosition(entryBlock, entryBlock->begin()); // 确保在入口块的开始位置插入
|
||||
for (auto arg : func->getArguments()) {
|
||||
// 默认情况下,将所有参数是提升到内存
|
||||
if (isPromotableToMemory(arg)) {
|
||||
// 参数的类型就是 AllocaInst 需要分配的类型
|
||||
AllocaInst *alloca = builder->createAllocaInst(Type::getPointerType(arg->getType()), arg->getName() + ".reg2mem");
|
||||
// 将参数值 store 到 alloca 中 (这是 Mem2Reg 逆转的关键一步)
|
||||
valueToAllocaMap[arg] = alloca;
|
||||
// for (auto arg : func->getArguments()) {
|
||||
// // 默认情况下,将所有参数是提升到内存
|
||||
// if (isPromotableToMemory(arg)) {
|
||||
// // 参数的类型就是 AllocaInst 需要分配的类型
|
||||
// AllocaInst *alloca = builder->createAllocaInst(Type::getPointerType(arg->getType()), arg->getName() + ".reg2mem");
|
||||
// // 将参数值 store 到 alloca 中 (这是 Mem2Reg 逆转的关键一步)
|
||||
// valueToAllocaMap[arg] = alloca;
|
||||
|
||||
// 确保 alloca 位于入口块的顶部,但在所有参数的 store 指令之前
|
||||
// 通常 alloca 都在 entry block 的最开始
|
||||
// 这里我们只是创建,并让 builder 决定插入位置 (通常在当前插入点)
|
||||
// 如果需要严格控制顺序,可能需要手动 insert 到 instruction list
|
||||
}
|
||||
}
|
||||
// // 确保 alloca 位于入口块的顶部,但在所有参数的 store 指令之前
|
||||
// // 通常 alloca 都在 entry block 的最开始
|
||||
// // 这里我们只是创建,并让 builder 决定插入位置 (通常在当前插入点)
|
||||
// // 如果需要严格控制顺序,可能需要手动 insert 到 instruction list
|
||||
// }
|
||||
// }
|
||||
|
||||
// 2. 为指令结果分配内存
|
||||
// 遍历所有基本块和指令,找出所有需要分配 Alloca 的指令结果
|
||||
@@ -123,11 +123,11 @@ void Reg2MemContext::allocateMemoryForSSAValues(Function *func) {
|
||||
}
|
||||
|
||||
// 插入所有参数的初始 Store 指令
|
||||
for (auto arg : func->getArguments()) {
|
||||
if (valueToAllocaMap.count(arg)) { // 检查是否为其分配了 alloca
|
||||
builder->createStoreInst(arg, valueToAllocaMap[arg]);
|
||||
}
|
||||
}
|
||||
// for (auto arg : func->getArguments()) {
|
||||
// if (valueToAllocaMap.count(arg)) { // 检查是否为其分配了 alloca
|
||||
// builder->createStoreInst(arg, valueToAllocaMap[arg]);
|
||||
// }
|
||||
// }
|
||||
|
||||
builder->setPosition(entryBlock, entryBlock->terminator());
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#include "SCCP.h"
|
||||
#include "Dom.h"
|
||||
#include "Liveness.h"
|
||||
#include "SideEffectAnalysis.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath> // For std::fmod, std::fabs
|
||||
#include <limits> // For std::numeric_limits
|
||||
#include <set> // For std::set in isKnownPureFunction
|
||||
|
||||
namespace sysy {
|
||||
|
||||
@@ -263,6 +265,192 @@ SSAPValue SCCPContext::ComputeConstant(UnaryInst *unaryInst, SSAPValue operandVa
|
||||
return SSAPValue(LatticeVal::Bottom);
|
||||
}
|
||||
|
||||
// 辅助函数:检查是否为已知的纯函数
|
||||
bool SCCPContext::isKnownPureFunction(const std::string &funcName) const {
|
||||
// SysY中一些已知的纯函数(不修改全局状态,结果只依赖参数)
|
||||
static const std::set<std::string> knownPureFunctions = {
|
||||
// 数学函数(如果有的话)
|
||||
// "abs", "fabs", "sqrt", "sin", "cos"
|
||||
// SysY标准中基本没有纯函数,大多数都有I/O副作用
|
||||
};
|
||||
|
||||
return knownPureFunctions.find(funcName) != knownPureFunctions.end();
|
||||
}
|
||||
|
||||
// 辅助函数:计算纯函数的常量结果
|
||||
SSAPValue SCCPContext::computePureFunctionResult(CallInst *call, const std::vector<SSAPValue> &argValues) {
|
||||
Function *calledFunc = call->getCallee();
|
||||
if (!calledFunc) {
|
||||
return SSAPValue(LatticeVal::Bottom);
|
||||
}
|
||||
|
||||
std::string funcName = calledFunc->getName();
|
||||
|
||||
// 目前SysY中没有标准的纯函数,这里预留扩展空间
|
||||
// 未来可以添加数学函数的常量折叠
|
||||
/*
|
||||
if (funcName == "abs" && argValues.size() == 1) {
|
||||
if (argValues[0].constant_type == ValueType::Integer) {
|
||||
int val = std::get<int>(argValues[0].constantVal);
|
||||
return SSAPValue(std::abs(val));
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return SSAPValue(LatticeVal::Bottom);
|
||||
}
|
||||
|
||||
// 辅助函数:查找存储到指定位置的常量值
|
||||
SSAPValue SCCPContext::findStoredConstantValue(Value *ptr, BasicBlock *currentBB) {
|
||||
if (!aliasAnalysis) {
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: No alias analysis available" << std::endl;
|
||||
}
|
||||
return SSAPValue(LatticeVal::Bottom);
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Searching for stored constant value for ptr" << std::endl;
|
||||
}
|
||||
|
||||
// 从当前块的指令列表末尾向前查找最近的Store
|
||||
std::vector<Instruction*> instructions;
|
||||
for (auto it = currentBB->begin(); it != currentBB->end(); ++it) {
|
||||
instructions.push_back(it->get());
|
||||
}
|
||||
|
||||
for (int i = instructions.size() - 1; i >= 0; --i) {
|
||||
Instruction *prevInst = instructions[i];
|
||||
|
||||
if (prevInst->isStore()) {
|
||||
StoreInst *storeInst = static_cast<StoreInst *>(prevInst);
|
||||
Value *storePtr = storeInst->getPointer();
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Checking store instruction" << std::endl;
|
||||
}
|
||||
|
||||
// 使用别名分析检查Store是否针对相同的内存位置
|
||||
auto aliasResult = aliasAnalysis->queryAlias(ptr, storePtr);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Alias result: " << (int)aliasResult << std::endl;
|
||||
}
|
||||
|
||||
if (aliasResult == AliasType::SELF_ALIAS) {
|
||||
// 找到了对相同位置的Store,获取存储的值
|
||||
Value *storedValue = storeInst->getValue();
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Found matching store, checking value type" << std::endl;
|
||||
}
|
||||
|
||||
// 检查存储的值是否为常量
|
||||
if (auto constInt = dynamic_cast<ConstantInteger *>(storedValue)) {
|
||||
int val = std::get<int>(constInt->getVal());
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Found constant integer value: " << val << std::endl;
|
||||
}
|
||||
return SSAPValue(val);
|
||||
} else if (auto constFloat = dynamic_cast<ConstantFloating *>(storedValue)) {
|
||||
float val = std::get<float>(constFloat->getVal());
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Found constant float value: " << val << std::endl;
|
||||
}
|
||||
return SSAPValue(val);
|
||||
} else {
|
||||
// 存储的值不是常量,检查其SCCP状态
|
||||
SSAPValue storedState = GetValueState(storedValue);
|
||||
if (storedState.state == LatticeVal::Constant) {
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Found SCCP constant value" << std::endl;
|
||||
}
|
||||
return storedState;
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Stored value is not constant" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 找到了最近的Store但不是常量,停止查找
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Found non-constant store, stopping search" << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: No constant value found" << std::endl;
|
||||
}
|
||||
return SSAPValue(LatticeVal::Bottom);
|
||||
}
|
||||
|
||||
// 辅助函数:动态检查数组访问是否为常量索引(考虑SCCP状态)
|
||||
bool SCCPContext::hasRuntimeConstantAccess(Value *ptr) {
|
||||
if (auto gep = dynamic_cast<GetElementPtrInst *>(ptr)) {
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Checking runtime constant access for GEP instruction" << std::endl;
|
||||
}
|
||||
|
||||
// 检查所有索引是否为常量或SCCP传播的常量
|
||||
bool allConstantIndices = true;
|
||||
for (auto indexUse : gep->getIndices()) {
|
||||
Value* index = indexUse->getValue();
|
||||
|
||||
// 首先检查是否为编译时常量
|
||||
if (auto constInt = dynamic_cast<ConstantInteger *>(index)) {
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Index is compile-time constant integer: " << std::get<int>(constInt->getVal()) << std::endl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (auto constFloat = dynamic_cast<ConstantFloating *>(index)) {
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Index is compile-time constant float: " << std::get<float>(constFloat->getVal()) << std::endl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查是否为SCCP传播的常量
|
||||
SSAPValue indexState = GetValueState(index);
|
||||
if (indexState.state == LatticeVal::Constant) {
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Index is SCCP constant: ";
|
||||
if (indexState.constant_type == ValueType::Integer) {
|
||||
std::cout << std::get<int>(indexState.constantVal);
|
||||
} else {
|
||||
std::cout << std::get<float>(indexState.constantVal);
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 如果任何一个索引不是常量,返回false
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Index is not constant, access is not constant" << std::endl;
|
||||
}
|
||||
allConstantIndices = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: hasRuntimeConstantAccess result: " << (allConstantIndices ? "true" : "false") << std::endl;
|
||||
}
|
||||
return allConstantIndices;
|
||||
}
|
||||
|
||||
// 对于非GEP指令,回退到别名分析的静态结果
|
||||
if (aliasAnalysis) {
|
||||
return aliasAnalysis->hasConstantAccess(ptr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 辅助函数:处理单条指令
|
||||
void SCCPContext::ProcessInstruction(Instruction *inst) {
|
||||
SSAPValue oldState = GetValueState(inst);
|
||||
@@ -396,28 +584,237 @@ void SCCPContext::ProcessInstruction(Instruction *inst) {
|
||||
break;
|
||||
}
|
||||
case Instruction::kLoad: {
|
||||
// 对于 Load 指令,除非我们有特殊的别名分析,否则假定为 Bottom
|
||||
// 或者如果它加载的是一个已知常量地址的全局常量
|
||||
// 使用别名分析和副作用分析改进Load指令的处理
|
||||
Value *ptr = inst->getOperand(0);
|
||||
|
||||
// 首先检查是否是全局常量
|
||||
if (auto globalVal = dynamic_cast<GlobalValue *>(ptr)) {
|
||||
// 如果 GlobalValue 有初始化器,并且它是常量,我们可以传播
|
||||
// 这需要额外的逻辑来检查 globalVal 的初始化器
|
||||
// 暂时保守地设置为 Bottom
|
||||
// TODO: 检查全局变量的初始化器进行常量传播
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
} else if (aliasAnalysis && sideEffectAnalysis) {
|
||||
// 使用别名分析和副作用分析进行更精确的Load分析
|
||||
if (aliasAnalysis->isLocalArray(ptr) && (aliasAnalysis->hasConstantAccess(ptr) || hasRuntimeConstantAccess(ptr))) {
|
||||
// 对于局部数组的常量索引访问,检查是否有影响该位置的Store
|
||||
bool mayBeModified = false;
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Analyzing local array with constant access for modification" << std::endl;
|
||||
}
|
||||
|
||||
// 遍历指令所在块之前的所有指令,查找可能修改该内存位置的Store
|
||||
BasicBlock *currentBB = inst->getParent();
|
||||
auto instPos = currentBB->findInstIterator(inst);
|
||||
|
||||
SSAPValue foundConstantValue = SSAPValue(LatticeVal::Bottom);
|
||||
bool hasFoundDefinitiveStore = false;
|
||||
|
||||
for (auto it = currentBB->begin(); it != instPos; ++it) {
|
||||
Instruction *prevInst = it->get();
|
||||
|
||||
if (prevInst->isStore()) {
|
||||
StoreInst *storeInst = static_cast<StoreInst *>(prevInst);
|
||||
Value *storePtr = storeInst->getPointer();
|
||||
|
||||
// 使用别名分析判断Store是否可能影响当前Load
|
||||
auto aliasResult = aliasAnalysis->queryAlias(ptr, storePtr);
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Checking store with alias result: " << (int)aliasResult << std::endl;
|
||||
}
|
||||
|
||||
if (aliasResult == AliasType::SELF_ALIAS) {
|
||||
// 找到对相同位置的精确Store
|
||||
Value *storedValue = storeInst->getValue();
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Found exact store to same location, checking value" << std::endl;
|
||||
}
|
||||
|
||||
// 检查存储的值是否为常量
|
||||
if (auto constInt = dynamic_cast<ConstantInteger *>(storedValue)) {
|
||||
int val = std::get<int>(constInt->getVal());
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Store contains constant integer: " << val << std::endl;
|
||||
}
|
||||
foundConstantValue = SSAPValue(val);
|
||||
hasFoundDefinitiveStore = true;
|
||||
// 继续遍历,查找是否有更后面的Store覆盖这个值
|
||||
} else if (auto constFloat = dynamic_cast<ConstantFloating *>(storedValue)) {
|
||||
float val = std::get<float>(constFloat->getVal());
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Store contains constant float: " << val << std::endl;
|
||||
}
|
||||
foundConstantValue = SSAPValue(val);
|
||||
hasFoundDefinitiveStore = true;
|
||||
} else {
|
||||
// 存储的值不是编译时常量,检查其SCCP状态
|
||||
SSAPValue storedState = GetValueState(storedValue);
|
||||
if (storedState.state == LatticeVal::Constant) {
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Store contains SCCP constant" << std::endl;
|
||||
}
|
||||
foundConstantValue = storedState;
|
||||
hasFoundDefinitiveStore = true;
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Store contains non-constant value" << std::endl;
|
||||
}
|
||||
// 非常量Store覆盖了之前的常量,无法传播
|
||||
foundConstantValue = SSAPValue(LatticeVal::Bottom);
|
||||
hasFoundDefinitiveStore = true;
|
||||
}
|
||||
}
|
||||
} else if (aliasResult != AliasType::NO_ALIAS) {
|
||||
// 可能有别名,但不确定
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Found store with uncertain alias, stopping propagation" << std::endl;
|
||||
}
|
||||
mayBeModified = true;
|
||||
break;
|
||||
}
|
||||
} else if (prevInst->isCall()) {
|
||||
// 检查函数调用是否可能修改该内存位置
|
||||
if (sideEffectAnalysis->mayModifyMemory(prevInst)) {
|
||||
// 进一步检查是否可能影响局部数组
|
||||
if (!aliasAnalysis->isLocalArray(ptr) ||
|
||||
sideEffectAnalysis->mayModifyGlobal(prevInst)) {
|
||||
mayBeModified = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (prevInst->isMemset()) {
|
||||
// Memset指令可能影响内存,但只有在它在相关Store之前时才阻止常量传播
|
||||
MemsetInst *memsetInst = static_cast<MemsetInst *>(prevInst);
|
||||
Value *memsetPtr = memsetInst->getOperand(0);
|
||||
|
||||
auto aliasResult = aliasAnalysis->queryAlias(ptr, memsetPtr);
|
||||
if (aliasResult != AliasType::NO_ALIAS) {
|
||||
// Memset可能影响这个位置,但我们继续查找是否有Store覆盖了memset
|
||||
// 不立即设置mayBeModified = true,让后续的Store有机会覆盖
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Found memset that may affect location, but continuing to check for overwriting stores" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: mayBeModified = " << (mayBeModified ? "true" : "false") << std::endl;
|
||||
std::cout << "SCCP: hasFoundDefinitiveStore = " << (hasFoundDefinitiveStore ? "true" : "false") << std::endl;
|
||||
}
|
||||
|
||||
if (!mayBeModified) {
|
||||
if (hasFoundDefinitiveStore && foundConstantValue.state == LatticeVal::Constant) {
|
||||
// 直接使用找到的常量值
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Using found constant value from store analysis: ";
|
||||
if (foundConstantValue.constant_type == ValueType::Integer) {
|
||||
std::cout << std::get<int>(foundConstantValue.constantVal);
|
||||
} else {
|
||||
std::cout << std::get<float>(foundConstantValue.constantVal);
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
newState = foundConstantValue;
|
||||
} else {
|
||||
// 如果没有发现修改该位置的指令,尝试用旧方法找到对应的Store值
|
||||
SSAPValue constantValue = findStoredConstantValue(ptr, inst->getParent());
|
||||
if (constantValue.state == LatticeVal::Constant) {
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Found constant value for array load using fallback method: ";
|
||||
if (constantValue.constant_type == ValueType::Integer) {
|
||||
std::cout << std::get<int>(constantValue.constantVal);
|
||||
} else {
|
||||
std::cout << std::get<float>(constantValue.constantVal);
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
newState = constantValue;
|
||||
} else {
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
}
|
||||
} else {
|
||||
// 非局部数组或非常量访问,保守处理
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
}
|
||||
} else {
|
||||
// 没有分析信息时保守处理
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
}
|
||||
|
||||
if (DEBUG && aliasAnalysis && sideEffectAnalysis) {
|
||||
std::cout << "SCCP: Load instruction analysis - "
|
||||
<< (aliasAnalysis->isLocalArray(ptr) ? "local array" : "other")
|
||||
<< ", static constant access: "
|
||||
<< (aliasAnalysis->hasConstantAccess(ptr) ? "yes" : "no")
|
||||
<< ", runtime constant access: "
|
||||
<< (hasRuntimeConstantAccess(ptr) ? "yes" : "no") << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Instruction::kStore:
|
||||
// Store 指令不产生值,其 SSAPValue 不重要
|
||||
newState = SSAPValue(); // 保持 Top
|
||||
break;
|
||||
case Instruction::kCall:
|
||||
// TODO: 处理 Call 指令根据副作用分析可以推断的常量
|
||||
// 大多数 Call 指令都假定为 Bottom,除非是纯函数且所有参数都是常量
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
case Instruction::kCall: {
|
||||
// 使用副作用分析改进Call指令处理
|
||||
CallInst *callInst = static_cast<CallInst *>(inst);
|
||||
|
||||
if (sideEffectAnalysis) {
|
||||
const auto &sideEffect = sideEffectAnalysis->getInstructionSideEffect(callInst);
|
||||
|
||||
// 检查是否为纯函数且所有参数都是常量
|
||||
if (sideEffect.isPure && sideEffect.type == SideEffectType::NO_SIDE_EFFECT) {
|
||||
// 对于纯函数,检查所有参数是否都是常量
|
||||
bool allArgsConstant = true;
|
||||
std::vector<SSAPValue> argValues;
|
||||
|
||||
for (unsigned i = 0; i < callInst->getNumOperands() - 1; ++i) { // 减1排除函数本身
|
||||
SSAPValue argVal = GetValueState(callInst->getOperand(i));
|
||||
argValues.push_back(argVal);
|
||||
if (argVal.state != LatticeVal::Constant) {
|
||||
allArgsConstant = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (allArgsConstant) {
|
||||
// 对于参数全为常量的纯函数,可以尝试常量折叠
|
||||
// 但由于实际执行函数比较复杂,这里先标记为可优化
|
||||
// TODO: 实现具体的纯函数常量折叠
|
||||
Function *calledFunc = callInst->getCallee();
|
||||
if (calledFunc && isKnownPureFunction(calledFunc->getName())) {
|
||||
// 对已知的纯函数进行常量计算
|
||||
newState = computePureFunctionResult(callInst, argValues);
|
||||
} else {
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
}
|
||||
} else {
|
||||
// 参数不全是常量,但函数无副作用
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Pure function call with "
|
||||
<< (allArgsConstant ? "constant" : "non-constant") << " arguments" << std::endl;
|
||||
}
|
||||
} else {
|
||||
// 有副作用的函数调用,保守处理
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Function call with side effects" << std::endl;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 没有副作用分析时,保守处理所有Call
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Instruction::kGetElementPtr: {
|
||||
// GEP 指令计算地址,通常其结果值(地址指向的内容)是 Bottom
|
||||
// 除非所有索引和基指针都是常量,指向一个确定常量值的内存位置
|
||||
@@ -970,12 +1367,34 @@ bool SCCP::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
if (DEBUG) {
|
||||
std::cout << "Running SCCP on function: " << F->getName() << std::endl;
|
||||
}
|
||||
|
||||
SCCPContext context(builder);
|
||||
|
||||
// 获取别名分析结果
|
||||
if (auto *aliasResult = AM.getAnalysisResult<AliasAnalysisResult, SysYAliasAnalysisPass>(F)) {
|
||||
context.setAliasAnalysis(aliasResult);
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Using alias analysis results" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取副作用分析结果(Module级别)
|
||||
if (auto *sideEffectResult = AM.getAnalysisResult<SideEffectAnalysisResult, SysYSideEffectAnalysisPass>()) {
|
||||
context.setSideEffectAnalysis(sideEffectResult);
|
||||
if (DEBUG) {
|
||||
std::cout << "SCCP: Using side effect analysis results" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
context.run(F, AM);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SCCP::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
|
||||
// 声明依赖别名分析和副作用分析
|
||||
analysisDependencies.insert(&SysYAliasAnalysisPass::ID);
|
||||
analysisDependencies.insert(&SysYSideEffectAnalysisPass::ID);
|
||||
|
||||
// analysisInvalidations.insert(nullptr); // 表示使所有默认分析失效
|
||||
analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID); // 支配树可能受影响
|
||||
analysisInvalidations.insert(&LivenessAnalysisPass::ID); // 活跃性分析很可能失效
|
||||
|
||||
125
src/midend/Pass/Optimize/TailCallOpt.cpp
Normal file
125
src/midend/Pass/Optimize/TailCallOpt.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
#include "TailCallOpt.h"
|
||||
#include "IR.h"
|
||||
#include "IRBuilder.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include <vector>
|
||||
// #include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
void *TailCallOpt::ID = (void *)&TailCallOpt::ID;
|
||||
|
||||
void TailCallOpt::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
|
||||
analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID);
|
||||
analysisInvalidations.insert(&LoopAnalysisPass::ID);
|
||||
}
|
||||
|
||||
bool TailCallOpt::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
std::vector<CallInst *> tailCallInsts;
|
||||
// 遍历函数的所有基本块
|
||||
for (auto &bb_ptr : F->getBasicBlocks()) {
|
||||
auto BB = bb_ptr.get();
|
||||
if (BB->getInstructions().empty()) continue; // 跳过空基本块
|
||||
|
||||
auto term_iter = BB->terminator();
|
||||
if (term_iter == BB->getInstructions().end()) continue; // 没有终结指令则跳过
|
||||
auto term = (*term_iter).get();
|
||||
|
||||
if (!term || !term->isReturn()) continue; // 不是返回指令则跳过
|
||||
auto retInst = static_cast<ReturnInst *>(term);
|
||||
|
||||
Instruction *prevInst = nullptr;
|
||||
if (BB->getInstructions().size() > 1) {
|
||||
auto it = term_iter;
|
||||
--it; // 获取返回指令前的指令
|
||||
prevInst = (*it).get();
|
||||
}
|
||||
|
||||
if (!prevInst || !prevInst->isCall()) continue; // 前一条不是调用指令则跳过
|
||||
auto callInst = static_cast<CallInst *>(prevInst);
|
||||
|
||||
// 检查是否为尾递归调用:被调用函数与当前函数相同且返回值与调用结果匹配
|
||||
if (callInst->getCallee() == F) {
|
||||
// 对于尾递归,返回值应为调用结果或为 void 类型
|
||||
if (retInst->getReturnValue() == callInst ||
|
||||
(retInst->getReturnValue() == nullptr && callInst->getType()->isVoid())) {
|
||||
tailCallInsts.push_back(callInst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tailCallInsts.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 创建一个新的入口基本块,作为循环的前置块
|
||||
auto original_entry = F->getEntryBlock();
|
||||
auto new_entry = F->addBasicBlock("tco.entry." + F->getName());
|
||||
auto loop_header = F->addBasicBlock("tco.loop_header." + F->getName());
|
||||
|
||||
// 将原入口块中的所有指令移动到循环头块
|
||||
loop_header->getInstructions().splice(loop_header->end(), original_entry->getInstructions());
|
||||
original_entry->setName("tco.pre_header");
|
||||
|
||||
// 为函数参数创建 phi 节点
|
||||
builder->setPosition(loop_header, loop_header->begin());
|
||||
std::vector<PhiInst *> phis;
|
||||
auto original_args = F->getArguments();
|
||||
for (auto &arg : original_args) {
|
||||
auto phi = builder->createPhiInst(arg->getType(), {}, {}, "tco.phi."+arg->getName());
|
||||
phis.push_back(phi);
|
||||
}
|
||||
|
||||
// 用 phi 节点替换所有原始参数的使用
|
||||
for (size_t i = 0; i < original_args.size(); ++i) {
|
||||
original_args[i]->replaceAllUsesWith(phis[i]);
|
||||
}
|
||||
|
||||
// 设置 phi 节点的输入值
|
||||
for (size_t i = 0; i < phis.size(); ++i) {
|
||||
phis[i]->addIncoming(original_args[i], new_entry);
|
||||
}
|
||||
|
||||
// 连接各个基本块
|
||||
builder->setPosition(original_entry, original_entry->end());
|
||||
builder->createUncondBrInst(new_entry);
|
||||
original_entry->addSuccessor(new_entry);
|
||||
|
||||
builder->setPosition(new_entry, new_entry->end());
|
||||
builder->createUncondBrInst(loop_header);
|
||||
new_entry->addSuccessor(loop_header);
|
||||
loop_header->addPredecessor(new_entry);
|
||||
|
||||
// 处理每一个尾递归调用
|
||||
for (auto callInst : tailCallInsts) {
|
||||
auto tail_call_block = callInst->getParent();
|
||||
|
||||
// 收集尾递归调用的参数
|
||||
auto args_range = callInst->getArguments();
|
||||
std::vector<Value*> args;
|
||||
std::transform(args_range.begin(), args_range.end(), std::back_inserter(args),
|
||||
[](auto& use_ptr){ return use_ptr->getValue(); });
|
||||
|
||||
// 用新的参数值更新 phi 节点
|
||||
for (size_t i = 0; i < phis.size(); ++i) {
|
||||
phis[i]->addIncoming(args[i], tail_call_block);
|
||||
}
|
||||
|
||||
// 移除原有的调用和返回指令
|
||||
auto term_iter = tail_call_block->terminator();
|
||||
SysYIROptUtils::usedelete(term_iter);
|
||||
auto call_iter = tail_call_block->findInstIterator(callInst);
|
||||
SysYIROptUtils::usedelete(call_iter);
|
||||
|
||||
// 添加跳转回循环头块的分支指令
|
||||
builder->setPosition(tail_call_block, tail_call_block->end());
|
||||
builder->createUncondBrInst(loop_header);
|
||||
tail_call_block->addSuccessor(loop_header);
|
||||
loop_header->addPredecessor(tail_call_block);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@@ -1,13 +1,24 @@
|
||||
#include "Dom.h"
|
||||
#include "Liveness.h"
|
||||
#include "Loop.h"
|
||||
#include "LoopCharacteristics.h"
|
||||
#include "AliasAnalysis.h"
|
||||
#include "CallGraphAnalysis.h"
|
||||
#include "SideEffectAnalysis.h"
|
||||
#include "SysYIRCFGOpt.h"
|
||||
#include "SysYIRPrinter.h"
|
||||
#include "DCE.h"
|
||||
#include "Mem2Reg.h"
|
||||
#include "Reg2Mem.h"
|
||||
#include "GVN.h"
|
||||
#include "SCCP.h"
|
||||
#include "BuildCFG.h"
|
||||
#include "LargeArrayToGlobal.h"
|
||||
#include "LoopNormalization.h"
|
||||
#include "LICM.h"
|
||||
#include "LoopStrengthReduction.h"
|
||||
#include "InductionVariableElimination.h"
|
||||
#include "GlobalStrengthReduction.h"
|
||||
#include "TailCallOpt.h"
|
||||
#include "Pass.h"
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
@@ -39,10 +50,17 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
||||
// 注册分析遍
|
||||
registerAnalysisPass<DominatorTreeAnalysisPass>();
|
||||
registerAnalysisPass<LivenessAnalysisPass>();
|
||||
registerAnalysisPass<sysy::DominatorTreeAnalysisPass>();
|
||||
registerAnalysisPass<sysy::LivenessAnalysisPass>();
|
||||
registerAnalysisPass<SysYAliasAnalysisPass>(); // 别名分析 (优先级高)
|
||||
registerAnalysisPass<CallGraphAnalysisPass>(); // 调用图分析 (Module级别,独立分析)
|
||||
registerAnalysisPass<SysYSideEffectAnalysisPass>(); // 副作用分析 (依赖别名分析和调用图)
|
||||
registerAnalysisPass<LoopAnalysisPass>();
|
||||
registerAnalysisPass<LoopCharacteristicsPass>(); // 循环特征分析依赖别名分析
|
||||
|
||||
// 注册优化遍
|
||||
registerOptimizationPass<BuildCFG>();
|
||||
registerOptimizationPass<LargeArrayToGlobalPass>();
|
||||
registerOptimizationPass<GVN>();
|
||||
|
||||
registerOptimizationPass<SysYDelInstAfterBrPass>();
|
||||
registerOptimizationPass<SysYDelNoPreBLockPass>();
|
||||
@@ -54,7 +72,14 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
||||
|
||||
registerOptimizationPass<DCE>();
|
||||
registerOptimizationPass<Mem2Reg>(builderIR);
|
||||
registerOptimizationPass<LoopNormalizationPass>(builderIR);
|
||||
registerOptimizationPass<LICM>(builderIR);
|
||||
registerOptimizationPass<LoopStrengthReduction>(builderIR);
|
||||
registerOptimizationPass<InductionVariableElimination>();
|
||||
|
||||
registerOptimizationPass<GlobalStrengthReduction>(builderIR);
|
||||
registerOptimizationPass<Reg2Mem>(builderIR);
|
||||
registerOptimizationPass<TailCallOpt>(builderIR);
|
||||
|
||||
registerOptimizationPass<SCCP>(builderIR);
|
||||
|
||||
@@ -70,7 +95,6 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&BuildCFG::ID);
|
||||
this->addPass(&LargeArrayToGlobalPass::ID);
|
||||
this->run();
|
||||
|
||||
this->clearPasses();
|
||||
@@ -109,6 +133,25 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
||||
printPasses();
|
||||
}
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&GVN::ID);
|
||||
this->run();
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&TailCallOpt::ID);
|
||||
this->run();
|
||||
|
||||
if(DEBUG) {
|
||||
std::cout << "=== IR After TailCallOpt ===\n";
|
||||
SysYPrinter printer(moduleIR);
|
||||
printer.printIR();
|
||||
}
|
||||
|
||||
if(DEBUG) {
|
||||
std::cout << "=== IR After GVN Optimizations ===\n";
|
||||
printPasses();
|
||||
}
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&SCCP::ID);
|
||||
this->run();
|
||||
@@ -118,6 +161,45 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
||||
printPasses();
|
||||
}
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&LoopNormalizationPass::ID);
|
||||
this->addPass(&InductionVariableElimination::ID);
|
||||
this->run();
|
||||
|
||||
if(DEBUG) {
|
||||
std::cout << "=== IR After Loop Normalization, Induction Variable Elimination ===\n";
|
||||
printPasses();
|
||||
}
|
||||
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&LICM::ID);
|
||||
this->run();
|
||||
|
||||
if(DEBUG) {
|
||||
std::cout << "=== IR After LICM ===\n";
|
||||
printPasses();
|
||||
}
|
||||
|
||||
// this->clearPasses();
|
||||
// this->addPass(&LoopStrengthReduction::ID);
|
||||
// this->run();
|
||||
|
||||
if(DEBUG) {
|
||||
std::cout << "=== IR After Loop Normalization, and Strength Reduction Optimizations ===\n";
|
||||
printPasses();
|
||||
}
|
||||
|
||||
// // 全局强度削弱优化,包括代数优化和魔数除法
|
||||
// this->clearPasses();
|
||||
// this->addPass(&GlobalStrengthReduction::ID);
|
||||
// this->run();
|
||||
|
||||
if(DEBUG) {
|
||||
std::cout << "=== IR After Global Strength Reduction Optimizations ===\n";
|
||||
printPasses();
|
||||
}
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&Reg2Mem::ID);
|
||||
this->run();
|
||||
|
||||
@@ -262,10 +262,12 @@ void SysYIRGenerator::compute() {
|
||||
}
|
||||
|
||||
// 弹出BinaryExpStack的表达式
|
||||
while(begin < end) {
|
||||
int count = end - begin;
|
||||
for (int i = 0; i < count; i++) {
|
||||
BinaryExpStack.pop_back();
|
||||
BinaryExpLenStack.back()--;
|
||||
end--;
|
||||
}
|
||||
if (!BinaryExpLenStack.empty()) {
|
||||
BinaryExpLenStack.back() -= count;
|
||||
}
|
||||
|
||||
// 计算后缀表达式
|
||||
@@ -672,6 +674,8 @@ std::any SysYIRGenerator::visitCompUnit(SysYParser::CompUnitContext *ctx) {
|
||||
pModule->enterNewScope();
|
||||
visitChildren(ctx);
|
||||
pModule->leaveScope();
|
||||
|
||||
Utils::modify_timefuncname(pModule);
|
||||
return pModule;
|
||||
}
|
||||
|
||||
@@ -2401,4 +2405,12 @@ void Utils::initExternalFunction(Module *pModule, IRBuilder *pBuilder) {
|
||||
|
||||
}
|
||||
|
||||
void Utils::modify_timefuncname(Module *pModule){
|
||||
auto starttimeFunc = pModule->getExternalFunction("starttime");
|
||||
auto stoptimeFunc = pModule->getExternalFunction("stoptime");
|
||||
starttimeFunc->setName("_sysy_starttime");
|
||||
stoptimeFunc->setName("_sysy_stoptime");
|
||||
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@@ -240,7 +240,9 @@ void SysYPrinter::printInst(Instruction *pInst) {
|
||||
case Kind::kMul:
|
||||
case Kind::kDiv:
|
||||
case Kind::kRem:
|
||||
case Kind::kSRA:
|
||||
case Kind::kSrl:
|
||||
case Kind::kSll:
|
||||
case Kind::kSra:
|
||||
case Kind::kMulh:
|
||||
case Kind::kFAdd:
|
||||
case Kind::kFSub:
|
||||
@@ -274,7 +276,9 @@ 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::kSrl: std::cout << "lshr"; break;
|
||||
case Kind::kSll: std::cout << "shl"; 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;
|
||||
|
||||
@@ -28,14 +28,14 @@ static string argStopAfter;
|
||||
static string argInputFile;
|
||||
static bool argFormat = false; // 目前未使用,但保留
|
||||
static string argOutputFilename;
|
||||
static int optLevel = 0; // 优化级别,默认为0 (不加-O参数时)
|
||||
int optLevel = 0; // 优化级别,默认为0 (不加-O参数时)
|
||||
|
||||
void usage(int code) {
|
||||
const char *msg = "Usage: sysyc [options] inputfile\n\n"
|
||||
"Supported options:\n"
|
||||
" -h \tprint help message and exit\n"
|
||||
" -f \tpretty-format the input file\n"
|
||||
" -s {ast,ir,asm,llvmir,asmd,ird}\tstop after generating AST/IR/Assembly\n"
|
||||
" -s {ast,ir,asm,asmd,ird}\tstop after generating AST/IR/Assembly\n"
|
||||
" -S \tcompile to assembly (.s file)\n"
|
||||
" -o <file>\tplace the output into <file>\n"
|
||||
" -O<level>\tenable optimization at <level> (e.g., -O0, -O1)\n";
|
||||
@@ -70,6 +70,9 @@ void parseArgs(int argc, char **argv) {
|
||||
if (optLevel < 0) {
|
||||
cerr << "Error: Optimization level must be non-negative." << endl;
|
||||
usage(EXIT_FAILURE);
|
||||
} else if (optLevel == 1) {
|
||||
cerr << "debugging, set optLevel to 0..." << endl;
|
||||
optLevel = 0;
|
||||
}
|
||||
} catch (const std::invalid_argument& ia) {
|
||||
cerr << "Error: Invalid argument for -O: " << optarg << endl;
|
||||
|
||||
200
testdata/performance/01_mm1.in
vendored
200
testdata/performance/01_mm1.in
vendored
@@ -1,200 +0,0 @@
|
||||
100
|
||||
-4 4 -60 -32 -67 65 7 32 -77 98 -88 85 13 -67 -44 -13 31 62 -12 53 7 -90 -58 3 -5 10 -72 22 -41 76 -12 80 27 -64 4 55 -21 1 -42 42 -55 -93 -34 -90 41 -96 -98 55 36 -19 16 -30 80 -32 -63 -28 67 -95 99 99 -96 -52 -9 -52 18 27 19 14 27 -94 -100 -53 -48 13 85 -72 -69 78 39 79 28 85 -19 22 9 23 -85 46 65 68 -89 53 17 -39 14 -73 -76 87 -56 -27
|
||||
-51 -55 1 -10 88 -22 4 17 -24 89 -26 -81 -33 93 -89 74 29 -80 -73 -37 92 -6 -22 -23 -99 49 41 -99 15 -32 35 2 20 22 58 -89 61 59 -54 31 20 -87 93 -3 49 -72 -90 -10 77 -92 84 -72 52 74 -35 98 44 -33 89 -82 -88 51 -49 27 26 -87 -72 -57 82 -19 -26 -17 -30 32 3 60 90 -24 30 -81 70 -39 100 13 -59 -56 6 -26 45 73 49 -44 -41 70 46 -63 -53 82 -10 -46
|
||||
62 10 73 29 -95 93 -27 31 -16 83 -43 6 70 -64 -46 -80 79 -81 84 79 -85 -57 -78 -63 -11 83 -81 37 -49 90 65 -48 39 68 -31 52 85 15 -32 51 -30 -56 57 -92 91 3 -60 51 66 -33 6 -92 62 50 16 -67 -44 69 90 24 -94 31 -9 -75 -33 50 33 -99 88 -78 -98 -23 72 -16 -87 -19 -14 -71 -52 -98 -94 -88 82 -13 68 85 73 -93 19 -54 -64 -75 -62 99 24 -35 61 -80 -61 -12
|
||||
87 -50 45 -11 -8 -93 -66 -96 36 13 -100 78 -25 55 -63 46 81 -33 -83 -8 19 -7 -14 -4 16 -31 -88 2 -84 68 -85 2 -46 66 82 -49 -86 99 -17 27 -51 -83 -96 -92 89 4 -25 47 -52 -25 -63 -65 96 -20 -71 -82 -43 38 -95 -61 -40 -1 -82 -18 -98 -72 -56 62 -84 72 33 -47 97 99 -39 78 -17 -48 -79 87 6 -75 88 -48 -57 9 -3 -5 65 -50 11 -53 56 -75 -51 87 70 -33 -11 18
|
||||
-99 -46 -5 15 13 -56 -82 69 -48 3 6 89 -17 94 -32 64 -85 25 -18 -82 66 92 8 36 71 32 12 -21 -53 -52 -75 -41 50 21 -47 12 -6 8 -13 -49 62 40 -11 91 -9 19 55 -95 -48 -72 -26 11 -81 -38 -49 -12 -93 69 -68 28 -69 26 94 1 -99 -25 -68 -40 46 -11 -92 -38 -21 -77 -33 -91 39 4 34 57 50 -13 9 -69 45 -76 -72 29 -81 -36 36 -92 -48 27 -45 -69 -74 55 85 51
|
||||
66 93 7 57 92 94 -84 89 -67 30 -10 -83 -6 -51 81 -22 -62 -24 30 -57 -90 61 58 94 39 -16 8 -66 -56 54 -53 12 44 -82 -55 34 8 34 -32 -67 51 89 -47 52 34 67 -3 -81 34 -53 72 -75 50 9 -93 38 -28 -3 46 31 -92 -93 67 -12 -14 -17 -33 10 -15 -88 -48 -65 0 -15 81 25 -42 75 -95 34 90 -6 -90 -35 -68 70 -15 36 19 -94 -57 8 -24 36 -41 59 -29 41 87 62
|
||||
-68 48 -9 1 1 10 -42 10 35 85 32 26 -35 75 -37 3 -99 39 74 99 76 94 11 -14 -29 96 -17 -48 46 9 -1 25 65 41 21 91 51 49 -84 64 23 -34 13 61 35 61 99 -29 -21 12 63 28 51 17 -23 100 29 -47 32 -14 -48 -20 -63 45 -40 91 23 -42 80 36 -27 -76 36 89 2 -14 91 89 -87 -97 28 -34 3 -100 98 65 22 -100 -25 66 -53 75 -62 85 -38 -45 -49 51 -93 -59
|
||||
-54 -32 -2 -81 60 35 14 14 -4 21 52 4 32 65 -6 60 84 6 -72 -72 70 -63 4 98 -4 8 -23 -31 -2 -6 78 56 -99 -5 47 -60 0 15 56 -48 18 35 35 1 -9 91 24 -46 -30 83 56 -98 39 -1 59 -53 30 69 -79 -42 24 91 71 -97 -35 3 -25 84 22 82 -46 68 62 23 71 -79 16 -73 39 55 -12 17 42 -66 -60 73 -36 -64 -68 39 -58 95 -72 10 -8 -9 -14 51 -44 -71
|
||||
5 38 24 -38 36 -59 21 43 93 -8 93 41 -11 8 93 8 90 76 54 -90 -98 77 22 33 44 -34 25 -71 -70 87 44 56 -98 -61 -79 25 33 -62 72 8 -13 -15 43 75 74 79 -23 52 -58 -9 27 -7 -27 -53 -76 -92 -95 81 -99 63 78 9 -43 -82 -80 -8 71 18 -40 -62 -57 90 -10 20 -44 -27 64 50 -27 -95 -76 94 42 -54 77 67 -29 -27 -77 40 83 15 7 30 -45 81 -86 -55 -85 -78
|
||||
-52 59 21 35 0 -9 95 34 -35 -47 -100 14 -50 10 19 78 64 30 76 96 47 22 -83 -29 0 11 -9 -28 -42 -31 56 36 -10 -26 53 93 -50 94 67 -5 17 -99 -77 -83 55 4 93 -46 -54 4 97 -16 30 8 45 -40 -88 -19 -36 -79 -13 -96 34 -59 58 77 86 -75 -27 -28 76 4 -45 -40 27 -59 -73 -54 -17 -27 72 62 24 -51 19 35 99 23 -33 -95 78 6 74 -71 -97 74 -72 14 62 98
|
||||
62 72 3 50 100 -58 77 -20 -89 -88 -87 -69 19 -29 -25 -29 14 -80 61 -36 -29 81 55 -73 46 62 6 69 11 69 -73 -100 62 18 -71 -85 -54 -73 5 18 98 -44 77 -50 -3 92 -5 87 25 -42 -92 -27 77 -57 -78 40 21 -83 -10 -9 51 50 31 -33 -67 5 60 -71 77 -1 10 -63 -57 -27 73 -91 69 97 -77 38 24 -53 -38 -2 85 -62 25 -64 -83 -23 33 22 -10 87 82 -53 81 79 -31 42
|
||||
71 -46 -29 75 34 -22 26 -27 -70 -60 44 52 -24 45 -37 -82 -64 -6 82 -48 97 92 -73 33 -2 83 51 -6 -23 -35 -86 -44 11 -13 -10 -14 30 2 -46 47 -53 4 39 70 -94 32 76 -97 -1 100 -12 -70 -84 -85 -54 56 15 45 -4 -98 13 59 -36 -9 42 -92 11 -60 61 92 -38 32 35 -49 23 48 84 67 30 9 71 17 38 -44 -62 49 -94 57 66 -38 52 78 38 -66 6 0 13 -69 40 25
|
||||
33 -84 -44 -25 -36 28 -92 -24 5 30 72 2 24 2 -27 90 1 -30 -97 -87 95 9 -82 -42 43 -85 13 48 1 33 34 -80 22 19 30 20 -70 51 92 -27 -41 -83 20 -88 -28 36 98 8 -53 -29 -76 14 -23 4 -45 63 -69 -99 77 -35 -12 73 59 6 -4 -13 -5 -64 15 89 -72 -37 -83 -91 87 -31 -33 -66 67 0 -84 -87 49 18 -69 -79 -7 -97 21 -74 -3 49 -26 -87 45 80 -19 -83 90 -93
|
||||
-84 -10 -13 -85 42 -23 -35 84 80 -78 -4 28 40 -4 77 43 33 10 -64 30 15 61 41 -66 32 -43 72 -36 38 63 79 -4 -30 -73 66 -55 31 29 97 15 -46 -75 -25 58 -83 83 -85 7 -4 -92 -72 73 32 61 55 -57 -86 -32 -13 64 21 76 -19 -55 31 -45 -28 -44 -30 -28 9 -35 82 50 -74 10 1 -25 78 -89 41 -38 41 -64 78 82 -16 -28 78 -53 47 10 29 5 -52 94 -88 0 -29 -52
|
||||
-86 -69 80 -49 -19 100 45 -25 25 -37 46 -51 -42 84 65 80 -20 89 -80 -74 42 13 81 73 43 65 67 -20 -23 75 -100 -24 89 96 -53 33 66 42 29 -62 73 -9 3 1 28 -70 35 -29 82 0 -13 -41 -22 82 90 -34 60 -21 90 -97 -55 13 41 -57 -46 88 61 -73 -85 96 48 9 -89 20 66 -70 16 -64 -72 -73 -47 13 -99 -55 -91 10 -22 -33 -60 -4 -81 -69 -55 -68 -94 28 -42 -20 -14 27
|
||||
-40 10 -49 94 73 26 -90 97 2 2 -83 28 55 32 -82 -60 11 -87 -32 -100 11 -57 4 91 36 -46 8 55 -1 -1 25 -5 19 81 -47 12 -77 18 -99 21 -83 -69 -82 11 39 35 1 80 24 -53 -58 -15 -85 -66 -81 -96 97 -61 -77 6 88 91 76 -45 5 78 -36 -87 -68 54 20 -70 -48 -90 55 82 -85 48 24 -66 -19 28 19 62 30 -15 -75 -39 97 14 62 -30 -33 91 -82 81 33 81 8 -67
|
||||
10 76 83 39 -88 -59 64 -63 92 84 94 -70 44 31 97 -95 43 43 -53 32 -61 -63 57 -6 57 7 -99 -54 45 69 -52 12 68 -88 -75 67 -93 19 -56 -82 -45 69 87 97 94 -50 -50 -26 94 32 96 -71 -47 -11 -17 1 -60 96 74 0 30 -78 53 -63 -34 -6 70 -77 -17 -34 -43 49 27 -26 -39 -13 62 87 84 -48 14 38 -50 47 -2 33 55 85 -42 -56 -3 -51 8 8 89 96 -93 65 81 -93
|
||||
4 43 52 21 -61 26 17 -12 -14 -78 2 -48 59 -80 69 73 -30 -12 99 36 -33 -89 38 -80 -93 -36 -97 -29 50 9 -56 59 -3 94 46 35 96 -25 56 -28 -10 -68 -55 43 -74 30 -73 16 54 -80 14 12 81 60 -57 -76 36 22 26 29 6 92 -45 82 -19 -36 -61 50 -50 89 -67 -10 -88 98 -59 -69 8 -63 -34 -72 -35 78 -2 -85 24 35 -13 65 29 -5 54 87 20 -82 -90 29 90 94 46 -86
|
||||
80 49 30 54 -91 -10 73 -18 51 46 -94 34 59 46 -17 -42 -29 31 0 22 85 -67 61 15 -31 -10 78 32 -76 -86 67 -13 20 -20 -40 -22 33 9 81 -62 87 -39 76 -55 -15 3 89 71 76 63 -53 75 -99 -21 -20 70 22 -77 98 63 -20 -77 7 -29 43 62 -80 77 40 -10 56 87 100 -27 39 -63 5 7 -97 -11 61 19 -74 95 65 -96 58 -49 -46 -84 16 34 -33 -46 47 -44 56 33 0 -61
|
||||
-71 -3 51 -3 16 21 13 -95 17 97 -59 -77 -15 -79 -88 -98 -92 2 47 -9 -6 39 -47 89 18 34 9 75 84 82 -65 21 -70 -6 -13 -7 -50 85 19 -31 -73 -99 -88 79 19 63 4 -99 -68 65 -49 94 -58 -52 83 59 -39 31 -24 81 96 -83 4 -17 -39 46 -1 -19 -75 -16 2 13 -76 31 -80 97 -46 -3 -71 66 60 16 89 -71 15 69 -25 45 -75 -16 -76 -83 -28 46 -79 94 3 -61 84 -94
|
||||
11 -56 -91 74 34 -2 -46 -95 8 -31 29 -48 -73 -18 34 72 -44 48 -44 -57 21 -93 -81 -11 -51 -70 -97 4 -81 20 4 -27 -57 -25 -83 -51 -31 41 12 -68 -4 -8 -96 35 62 -2 -29 -52 61 62 20 70 26 23 91 6 52 -63 -57 65 -77 27 76 -62 -46 61 -50 55 11 71 -31 -66 -45 -87 -51 2 -44 25 62 -19 -58 74 -54 -32 68 -13 -32 -2 3 23 -92 -28 -19 -49 20 40 89 28 36 32
|
||||
64 -66 -61 -66 93 48 16 86 20 95 8 -75 50 -54 -94 -11 -26 32 -5 41 -97 -33 68 14 58 38 -70 85 67 -18 94 8 11 28 33 -67 85 47 32 -36 -95 47 25 9 -64 -20 -23 -62 -81 30 -86 -42 47 27 40 30 -44 -84 59 -68 5 -18 47 66 48 -1 -33 56 60 -27 -60 19 23 -96 57 -25 21 -96 63 82 -69 -73 35 89 58 -69 67 -84 21 18 96 47 82 6 31 -38 37 -94 72 69
|
||||
-57 82 74 86 -39 -19 82 -16 61 41 -20 -82 -96 -55 -37 35 -31 51 -66 -21 55 -84 -39 58 -58 35 -55 56 58 -23 -48 92 -21 91 20 81 -14 68 -60 -21 -53 29 -76 42 -26 -55 60 -27 49 70 48 -61 82 -78 51 47 -73 40 10 -29 -27 9 64 -91 38 8 -26 -43 -1 -46 78 50 -53 -25 94 -54 -17 66 81 34 -94 67 48 -96 -24 -55 -92 31 -21 81 23 -45 -83 -8 -89 86 -13 -78 -41 -65
|
||||
-86 -9 -20 -45 -27 -29 38 89 -62 100 53 21 -17 49 -78 60 -52 65 90 68 31 33 9 64 47 -31 75 26 -74 -97 95 -81 -66 98 -40 -47 -95 79 -30 24 21 58 11 63 -73 -41 32 2 -48 44 20 56 15 34 13 -10 4 -62 -8 -40 -79 34 -95 -94 22 80 87 -59 -9 -35 -74 -44 -37 -35 46 61 53 -98 -2 -30 12 60 -94 -100 -91 -61 -96 -37 49 75 -73 43 -36 17 -31 55 -43 -90 -62 46
|
||||
-46 -41 82 -55 -13 -22 80 51 -18 64 -72 43 30 -72 -28 -68 89 -13 79 -81 57 42 -87 -72 63 1 41 61 -57 43 3 -41 -18 51 85 -79 -45 76 -93 -46 18 -100 -74 -97 -58 29 49 52 -37 -20 57 -6 -50 88 75 59 39 -59 -34 -71 -80 -38 -75 48 -73 69 -2 -52 46 -95 8 -21 7 -84 10 54 -28 -60 91 77 -71 -75 39 1 -5 2 29 47 -1 -93 93 -40 -81 -27 -98 95 -35 -51 -96 31
|
||||
40 29 -82 16 84 -40 79 -89 -38 8 82 2 -89 42 -36 -67 52 62 2 38 55 -36 -58 99 32 94 67 -88 59 -95 -72 50 38 69 -95 83 -19 -62 54 49 -96 -96 -79 -19 94 -25 -6 -24 39 17 -33 35 -84 -14 -35 -10 7 -36 67 -91 1 75 50 53 65 49 -95 3 81 95 87 84 -98 95 -15 -87 39 78 -92 28 -68 85 83 58 -88 -84 -52 58 -48 20 -15 -44 24 -86 -88 -71 -90 21 -50 39
|
||||
40 71 -99 100 -31 -99 0 -77 26 -28 88 72 -53 73 97 34 -76 56 -7 -14 56 58 -88 -37 98 98 -19 -29 74 44 -61 -8 11 -51 -52 80 -45 -61 68 -96 95 -52 -33 63 -76 34 -70 -15 -77 0 -38 54 4 -12 84 -9 -36 -60 81 67 -83 -88 38 -38 36 38 42 35 -99 -75 -56 61 -98 -44 40 -33 78 43 -12 96 -16 49 25 79 -56 100 30 89 -65 -76 1 87 33 38 -95 51 85 3 89 57
|
||||
98 -15 86 -57 -86 34 -14 -76 -32 44 -50 98 5 51 57 -82 80 11 77 21 -64 71 96 -93 -43 56 84 49 -86 18 74 55 65 -69 -26 55 55 -8 59 -5 -45 43 70 -39 46 -44 -2 -15 35 -33 -66 -56 -15 -21 60 -11 41 -44 -7 -21 -8 2 -18 -75 27 -68 72 -2 45 -11 3 36 -44 23 89 61 81 -65 -21 78 66 51 -94 -59 -76 -52 -42 67 30 -49 51 -91 -63 -53 -87 -7 -2 57 -40 60
|
||||
57 -30 -45 60 7 53 58 69 -74 -38 -11 -20 -62 23 -79 53 -18 -97 -28 25 -79 27 -64 8 4 -58 62 -21 -12 -4 -63 9 71 -30 -38 -72 -10 -20 -98 -43 -2 99 -43 52 -2 -78 -17 29 -76 -81 -94 -61 75 -71 -74 9 79 -31 15 91 -98 -34 85 -12 -65 -72 -37 3 32 -44 15 -4 -32 85 -10 -21 -41 67 20 -66 -66 -53 -20 7 77 60 0 -36 -2 -20 -27 31 50 50 -41 12 39 -12 74 -96
|
||||
14 2 48 2 41 57 -22 -39 -21 -2 -89 27 -94 -43 -76 67 -66 80 41 -54 30 -37 -27 -49 -74 -57 9 -15 64 -89 1 -95 -22 -41 88 -33 83 -6 -63 45 -86 71 96 -96 5 0 -37 6 62 -84 -38 -77 -70 -49 -82 -27 19 -5 1 90 94 -24 -88 6 -25 -50 11 -61 81 84 -79 45 88 -98 93 -20 11 -57 25 -61 -36 57 6 77 77 24 -1 -90 11 35 -72 -22 46 49 19 -33 -37 -84 -11 -4
|
||||
-100 45 60 -33 58 22 86 80 53 -35 51 73 -50 -64 62 43 42 10 57 -9 -15 39 -82 73 20 -57 -18 -5 11 -76 -29 -78 83 -75 86 36 5 -62 85 70 -85 65 -5 13 78 29 -3 84 -39 -37 -88 -46 -1 100 -5 -90 44 70 -8 30 -29 25 72 -11 30 -31 52 -38 71 -10 77 -80 -13 44 25 -58 -51 29 -28 -8 90 36 -5 -40 -77 98 50 67 22 53 74 89 -70 32 -52 84 85 73 -10 -13
|
||||
-73 50 -92 27 -18 95 -97 5 88 3 89 -32 -14 -66 -27 -53 46 18 -80 41 87 -45 91 -41 -42 24 17 -76 53 85 47 -10 5 62 -8 -44 29 -75 -2 -29 43 -44 26 -6 17 -20 84 20 -99 38 -19 72 -53 23 47 -20 10 -88 72 -100 64 -86 -44 -39 56 -45 -7 20 1 32 -36 -94 37 -9 -50 -39 40 -66 46 -40 93 22 -63 -31 -53 93 -86 64 -35 77 18 -59 -2 50 -47 -9 -62 77 92 2
|
||||
95 76 70 64 -41 12 -61 -99 56 -63 88 88 57 -33 36 -35 58 -85 -85 86 -74 -29 -33 23 58 28 -52 61 -64 -58 6 -46 98 -37 46 82 -20 66 -95 27 17 -97 -49 -25 35 54 -57 77 3 25 23 58 2 -45 -26 -63 -98 8 38 1 -38 29 34 -76 73 84 63 -44 75 63 18 -88 17 -57 -26 53 18 43 49 -49 -10 -10 -35 94 10 -88 -37 66 -46 20 43 -65 55 81 -62 -47 -25 -64 84 -24
|
||||
99 -85 -67 -29 -53 88 -94 -36 -79 13 -12 -19 24 35 -100 94 -59 89 -90 -81 -84 87 -11 -67 -64 -14 97 43 35 79 90 -47 44 -16 -59 14 72 37 -82 -34 16 67 -35 3 55 -49 63 -49 -14 -7 -92 -94 56 -38 -76 -92 -82 61 -98 -85 25 25 59 11 -35 -69 85 -92 98 -15 45 59 -56 77 28 11 77 48 49 -15 -64 66 -53 -27 82 17 -93 -12 47 -6 85 -93 46 -82 38 -68 77 -6 -81 -40
|
||||
-52 31 -10 -68 44 -1 24 -81 -6 70 25 -90 78 -33 76 -98 43 -63 35 49 15 50 11 46 -54 84 19 -55 91 -89 58 -44 -67 90 -94 58 -21 22 33 -26 -55 38 -98 58 83 -59 -55 94 -27 20 -84 2 87 19 -11 -2 -60 -56 -4 29 -29 75 42 51 -66 46 16 -33 -37 -83 86 87 1 67 14 -31 32 -52 -84 -38 -73 -14 92 -64 54 61 -14 -77 46 -74 83 81 -95 -68 -47 55 -27 38 96 -33
|
||||
-24 -30 27 -99 32 -93 100 -50 -99 -94 -48 8 30 -20 -57 -4 46 -73 79 55 -99 48 -66 65 -89 -77 81 -77 -39 -94 -49 66 5 53 -16 -3 93 -51 85 95 -17 67 62 -67 99 -34 15 60 -12 -75 94 -80 55 -72 -29 52 87 -53 -51 -47 93 -16 10 49 40 -28 31 10 70 -16 14 -4 80 19 70 41 44 81 -1 60 -50 -91 49 -69 81 2 1 75 -91 26 -91 79 25 74 12 82 77 67 -79 -27
|
||||
8 -85 51 83 -39 -20 -73 -46 23 -21 -31 -86 56 22 18 20 -42 22 -81 3 -15 -3 -24 -62 -82 19 -92 -81 77 -35 93 61 -39 92 -29 81 78 18 -57 -50 -65 74 11 -39 11 37 7 12 -65 -3 -83 16 -90 -2 44 100 -34 18 -99 -2 77 86 -64 -28 -37 -10 88 -35 -15 -6 48 27 14 -40 73 -32 -41 77 87 -66 -89 99 -48 15 -38 78 -94 -15 -59 -77 5 -45 -43 -56 -61 90 -18 -61 -15 -6
|
||||
-9 -66 -59 -52 -38 84 -51 -60 -20 8 13 -86 -50 47 90 -100 52 34 -52 -94 50 20 20 79 16 77 -87 14 30 -84 1 83 -7 7 43 -46 -23 100 67 58 -75 -19 -69 -4 54 -17 61 -72 73 -76 -75 77 -75 93 24 -98 53 -56 38 37 -97 97 11 -9 83 -43 -82 80 73 -51 -9 -51 47 73 -81 -93 23 11 29 -22 87 -77 78 -84 -29 94 -17 90 -22 80 -77 18 2 -54 49 25 29 24 -54 64
|
||||
-96 -93 62 -23 17 -67 -55 69 -39 30 31 -33 -70 -98 91 76 98 -71 18 49 66 -84 51 -76 -36 -19 -54 -86 -28 -34 -77 75 2 19 31 -65 -12 98 29 15 -57 86 -49 57 -66 -36 -7 -49 54 62 -86 84 96 -25 84 84 94 -23 1 -99 -55 33 28 45 83 58 11 7 -88 -23 -75 40 -20 40 52 -34 -28 -24 -80 56 87 20 68 69 46 -3 -87 -5 -15 67 28 100 -18 -65 67 11 -18 -78 16 69
|
||||
-20 73 -53 20 -4 75 -7 -24 -36 -36 -29 -33 -37 72 56 36 -19 60 61 18 63 64 -20 67 -33 -23 -56 66 -81 -17 75 94 5 91 33 73 -75 6 38 9 -37 -56 -33 -16 69 33 12 -87 -9 -23 -87 2 24 -91 -18 -56 -31 -24 27 -56 15 -12 -25 -85 -48 2 48 29 -76 -89 -84 -38 -63 54 -61 32 42 -41 67 66 -68 32 -55 77 -8 -46 6 -41 -20 -67 33 -13 -74 27 66 -7 34 77 -100 32
|
||||
-64 -27 -17 95 43 -16 -64 23 99 97 32 -81 -27 17 -2 -4 -32 -17 36 25 -83 -76 22 -21 44 73 -16 76 -40 29 100 9 66 39 -86 62 -66 -71 15 -4 -69 -27 43 99 -57 -48 89 81 -94 -2 -50 6 6 42 55 62 50 14 -91 38 25 98 94 77 -94 23 16 -67 75 -54 48 -26 2 -43 36 -69 61 82 19 -100 -48 19 -23 34 0 18 -72 77 -13 66 -18 39 31 -81 -89 -65 0 -20 44 23
|
||||
60 74 -67 81 -6 40 -38 3 53 -56 -2 98 -2 51 -50 -77 -12 -84 -43 78 -30 44 24 42 -36 49 -58 -35 30 -92 -81 31 -5 98 -3 -10 -9 -80 -79 80 22 -39 77 35 -21 0 -87 38 48 -76 -47 64 14 89 92 -49 -18 -49 11 -99 -17 30 19 4 -83 6 -5 -90 -61 -26 63 76 72 84 51 7 42 -26 56 85 23 39 34 -86 -42 71 -68 -56 37 80 -50 88 -86 -85 -60 -6 -31 -37 83 83
|
||||
13 43 96 3 92 -23 89 -64 -8 44 42 -58 48 81 -71 55 63 25 -9 49 -84 -95 53 -72 44 -3 23 -61 24 -51 -37 -58 26 -26 46 -54 68 -70 53 -13 55 -100 34 81 22 -85 66 -52 85 54 60 -100 15 -39 74 26 33 -53 -99 38 9 -45 10 -12 31 -59 -69 9 -87 -86 -73 -56 86 -36 89 94 -85 -4 -74 66 85 62 -48 -42 89 -65 78 -38 -39 -99 13 -86 -11 35 -84 92 -24 99 -87 -13
|
||||
22 -12 -58 19 -92 -88 -51 39 6 -21 -8 38 19 57 -35 66 28 -46 46 29 45 57 48 33 97 -91 53 87 -39 87 -85 -83 61 2 -75 47 32 88 83 32 -16 41 -93 30 -14 43 75 -11 23 -26 -42 63 -94 78 -89 -78 -30 -5 -70 -89 -97 31 25 -66 7 5 -60 61 -7 80 52 -6 -59 64 28 42 -45 -23 -92 1 65 -73 -80 -67 -3 22 91 -91 0 -1 -89 85 -73 -5 15 -26 34 36 -74 45
|
||||
-66 46 79 -58 -93 -13 -88 -19 -72 -19 81 -1 -44 8 -4 -77 43 11 -68 -56 -52 -18 40 17 -33 -4 78 84 14 60 -2 84 94 -44 35 27 -7 51 0 48 84 60 70 -6 1 83 -74 -46 43 -32 -56 7 -7 26 -96 96 -56 61 -54 2 -59 -88 11 -30 -34 -40 -34 -16 73 91 75 -61 -17 69 19 -91 -2 13 -49 -7 65 32 61 -5 78 -35 81 43 -62 80 18 65 66 76 82 79 -77 -33 64 -28
|
||||
30 22 96 -64 -67 46 -94 94 -1 -16 44 18 -45 -19 -1 11 -69 -50 -42 -84 -81 96 -95 -75 0 97 73 -90 -8 -19 9 54 75 69 15 -32 54 -69 11 -89 -82 14 93 37 -87 39 -49 -52 -8 62 -69 5 12 -29 -61 43 22 3 14 -91 15 86 -65 -1 36 -55 -35 42 -53 -11 41 64 -41 78 -82 18 27 -53 -100 -72 57 26 19 -25 85 40 -97 78 -91 96 80 -2 65 -77 -41 90 95 -55 74 25
|
||||
-75 50 -52 -40 48 -92 -23 29 3 -82 76 49 49 -26 70 -41 -29 69 -20 -55 -89 28 -21 61 28 -70 7 97 -40 -29 31 -39 64 -46 -75 -76 -51 99 -1 -73 -61 22 99 -7 51 -70 -17 -44 -75 23 -81 54 74 42 -13 35 38 91 11 -100 65 38 63 78 -71 -45 64 37 -29 75 19 30 -86 -3 71 26 -77 15 97 -25 13 34 17 90 -74 16 -33 97 84 -56 74 64 23 1 -78 39 -3 -93 -36 29
|
||||
-31 23 -83 -90 88 50 19 41 -32 -40 39 18 69 16 -95 74 67 -85 -13 -21 -17 21 53 13 82 30 72 -91 78 -27 -31 72 -76 -55 65 28 22 5 50 70 1 97 66 85 -80 -65 -45 43 -19 -92 -57 95 7 -93 99 -47 78 36 86 31 -76 -11 44 44 88 -13 -79 -4 30 94 -52 71 -1 -38 69 17 21 96 22 87 98 -29 30 9 -37 -44 -78 -15 67 -87 -62 -29 -42 -61 -93 14 -87 50 -7 38
|
||||
3 14 -49 52 51 -29 -86 -9 -55 -77 -73 47 28 23 -60 56 75 58 -12 -96 71 -22 62 -8 24 -2 23 -21 -46 -33 50 -93 33 39 -59 26 -57 62 63 24 36 16 27 -79 -62 -24 -56 -78 34 -72 18 51 30 56 31 35 -58 65 45 60 -51 -6 -23 100 48 85 21 99 96 -83 58 -24 -39 66 -7 17 -75 -83 -45 -21 79 54 62 96 32 -76 92 68 52 53 17 -28 89 70 90 -16 75 -85 100 75
|
||||
-83 -28 -73 -11 -53 -58 47 52 -93 -35 -6 -95 25 -22 84 98 -46 33 47 11 -74 -30 -8 15 -60 -85 -99 77 -46 -88 -25 14 -56 -72 2 -28 82 50 89 47 -23 -40 -39 19 56 -47 92 -20 -73 -39 -39 29 2 -12 85 20 54 54 -37 36 -65 17 88 -33 86 73 -60 -87 79 -15 -21 -69 -79 97 30 -54 -34 -85 36 48 -55 28 -28 -6 36 -89 -56 26 98 -45 99 6 -42 -76 44 91 70 -69 34 -25
|
||||
89 50 61 59 -34 -91 -90 -1 -51 -4 57 21 -46 -59 78 7 100 82 -74 4 48 65 20 96 96 -35 40 46 -14 79 80 -35 -47 -14 41 41 -16 47 98 -88 -97 45 17 74 51 38 -64 97 -77 87 -26 47 -58 -68 -96 12 99 53 -45 10 3 -61 99 37 15 -85 -23 78 -53 -48 -69 41 -24 2 42 -64 51 -17 -1 70 -31 -68 60 -78 -66 -66 20 23 -71 -32 -62 72 76 21 63 -9 49 -2 -50 -17
|
||||
43 -79 89 18 -99 93 -77 73 -75 73 -91 59 -78 -71 -96 -18 -54 -35 49 41 -77 11 -49 62 44 -49 6 -40 61 -52 -74 -99 30 -42 39 69 -86 9 -76 18 60 35 8 -78 67 87 38 -77 76 -75 34 46 61 4 -55 14 -24 -55 5 47 34 84 -97 94 -67 -50 -81 7 9 68 -52 -83 -9 92 1 79 -93 -11 18 17 -3 -41 54 -12 98 -47 -6 -60 87 -97 100 3 76 -6 23 -51 80 76 -10 64
|
||||
8 34 90 46 -38 -78 13 52 -79 28 -93 -62 76 21 -31 20 -61 -100 -46 31 -83 41 44 -25 -48 69 96 95 -56 43 28 -98 56 -98 62 -46 -68 -59 20 -83 -81 89 29 21 -96 68 57 -38 -98 84 34 -50 29 -30 -64 25 -19 32 -97 31 66 -22 -37 -83 11 -15 85 12 31 -51 -30 -60 80 46 -54 -56 -97 71 51 -94 -55 -96 81 -14 -16 42 16 -57 -14 83 42 24 24 -12 13 -32 -50 -23 35 -78
|
||||
39 -2 -75 -24 74 14 -97 27 58 44 -55 8 63 45 26 -47 -89 -4 -25 -69 13 64 -62 93 -32 -42 50 76 -51 18 41 29 -80 -86 -14 -58 35 -5 -32 -60 -100 8 -1 -92 90 63 3 -41 -39 29 -74 44 61 9 -81 -30 7 47 78 55 -7 -69 -93 38 4 5 -81 -66 11 -67 -72 39 -23 -75 -53 19 -30 -58 -10 37 24 31 -13 93 28 -35 40 22 -47 -39 -86 -51 54 -45 41 -30 -34 85 -16 -71
|
||||
-67 89 71 -84 12 93 94 46 -41 78 25 91 -83 -16 70 -93 -12 2 69 -56 -2 100 3 -45 3 -79 -99 -23 -51 -29 -42 -87 82 -93 -27 77 -10 0 -67 62 66 60 -19 -6 -35 73 46 -37 65 26 -28 99 -71 -94 -2 27 11 89 5 -97 -53 84 6 -44 -24 54 -71 24 86 -4 -49 15 91 -86 71 -78 -67 -99 91 -11 100 -10 -96 44 -16 39 -69 -69 -86 16 -26 -75 -50 46 62 -21 -52 -31 52 56
|
||||
1 -15 43 96 78 -44 71 49 -93 81 -82 -73 -52 -90 -1 27 -47 68 77 -67 -71 33 68 -14 51 24 -66 -53 50 -29 -75 47 68 98 -36 89 -15 -98 33 53 -88 42 32 82 55 -28 -80 30 71 64 -5 18 -63 7 -43 85 -43 12 80 9 -36 -7 -2 -85 82 5 97 46 -10 100 81 -45 33 -75 -56 19 50 -25 -30 -31 -5 52 -12 93 3 48 -69 2 -28 99 81 27 -39 -16 9 -58 69 -85 -87 -43
|
||||
-53 -36 -3 60 -4 -23 25 -32 -42 3 -86 16 32 -11 -20 -23 17 74 60 -34 32 50 -61 19 96 -73 -14 -80 10 -19 45 -48 -54 -24 2 -36 80 73 -94 72 62 100 -21 86 76 -26 39 -57 59 -5 -32 -52 64 -36 -41 69 5 92 90 58 -63 -4 -90 74 81 -64 97 -29 93 40 -71 13 86 76 -11 -96 24 68 23 -36 -68 -30 -77 64 -21 26 22 -60 -91 96 -91 27 -41 99 -20 -35 -13 -17 42 -13
|
||||
23 46 -70 89 -90 45 39 -21 -46 41 85 -76 73 -7 -69 -80 63 95 -51 0 -48 93 54 26 -24 30 -88 98 -58 10 28 -26 76 25 11 55 -13 -51 -55 -5 -91 -20 -80 27 -91 16 74 -83 -17 90 -35 26 82 -87 -59 -87 35 -83 93 -88 -20 -57 8 -81 39 36 -73 -40 88 84 -40 65 100 -59 -5 -35 57 17 -57 -50 33 13 77 -14 64 18 -76 -62 -73 -15 8 87 -69 41 -47 86 -22 20 80 -96
|
||||
-51 8 -19 41 49 -21 -34 -39 50 -48 -47 -54 -46 55 57 75 -42 -47 -83 23 54 24 72 15 -78 28 38 77 59 38 -67 -98 65 -34 -56 66 -46 -79 69 41 18 -77 -63 43 100 -94 88 44 -27 21 -89 36 56 -26 3 -92 -29 71 -72 -70 73 -79 -38 90 23 49 -83 -36 68 69 -41 -29 33 89 -80 -9 42 34 -90 3 2 -42 -24 77 12 59 -91 -5 2 66 -30 -13 -53 -9 88 92 60 49 -45 75
|
||||
-40 29 31 -75 73 -16 31 -25 100 48 0 -23 -48 58 -88 13 -20 -88 7 -33 89 55 77 30 70 41 -45 -84 28 -51 4 -19 -11 60 -3 18 30 94 11 -91 -34 30 -100 -16 72 36 -73 8 26 -55 -65 -4 -60 88 56 47 31 -10 39 30 19 -20 38 -52 -66 -36 -21 28 39 -63 92 -46 39 55 4 74 30 25 -89 74 21 -52 -76 -48 98 -93 -47 15 62 -58 -95 -16 43 -91 22 -23 -46 94 8 -47
|
||||
16 80 -32 51 27 -54 -45 7 -38 32 -95 2 95 -46 79 -58 -18 -8 -100 36 -13 75 11 85 86 -46 -58 -45 -48 -94 -18 -67 1 94 79 -7 41 -17 56 -76 1 -95 -68 44 91 -63 -99 -57 43 -85 -3 -62 43 -44 -95 12 61 44 -57 -93 25 10 100 76 -90 39 -21 -90 42 67 20 86 -45 -31 -54 31 -20 -23 -80 2 26 -85 18 -1 -1 44 -21 -37 -42 -49 -38 -41 10 -37 -93 -1 -91 94 -30 -78
|
||||
-63 -84 96 -66 67 -30 -100 51 99 46 -71 -9 -29 -89 -32 -66 -76 3 46 -19 46 -21 6 5 57 96 -16 -77 -26 -15 35 -95 62 43 24 79 34 69 -62 -25 83 -28 -52 95 62 -9 59 43 41 -24 2 -64 21 -47 -92 51 63 7 45 3 70 -92 -67 75 63 25 69 -25 -1 -27 -94 85 -69 62 5 -4 65 18 38 13 4 35 71 -13 40 -98 73 38 50 38 -30 71 16 34 36 63 -7 21 -80 74
|
||||
44 -17 43 -74 42 61 94 -77 65 22 100 -23 7 67 -81 47 70 -6 74 -62 -41 17 -6 -81 -98 -9 44 46 95 25 -35 80 -58 82 -15 97 -77 -72 99 -50 29 24 -10 67 39 32 -18 87 18 -37 -88 88 -58 32 57 -71 -15 72 12 -82 3 81 88 51 -79 78 -23 -35 -5 57 86 -27 -22 82 -82 0 94 79 -95 -91 7 -31 34 -3 -56 -17 6 57 50 -63 -54 -26 -41 -94 48 -3 75 -36 90 49
|
||||
-69 -32 6 90 56 -4 -96 88 -28 -76 -34 61 -17 -42 -79 -83 -70 -99 8 30 -65 72 -24 -27 11 18 -83 -23 22 68 80 -4 23 -72 -23 73 -9 31 -76 -64 -6 -86 77 -50 94 -48 43 93 -79 17 -88 84 27 -81 -88 -4 -41 -27 97 17 -17 49 71 44 -69 34 100 35 -47 48 -91 -63 -44 -4 26 77 -83 -25 2 45 71 -3 -30 69 -17 44 -54 -31 -63 9 -3 51 68 -86 1 -85 41 -2 -94 4
|
||||
83 -20 -36 -31 -4 43 55 2 -25 -93 -42 81 64 66 65 95 94 -56 -60 4 -27 -57 4 19 63 -34 -66 68 -11 53 67 -8 -35 -87 -94 21 -97 75 83 -99 14 -87 -72 15 55 73 64 -54 82 -58 -70 47 -81 -75 -36 -14 -92 -4 29 98 -49 3 -34 -61 -71 15 -77 -89 47 -18 19 66 27 62 56 9 41 50 -12 19 -35 -19 -57 51 -41 -5 69 -81 14 -51 -17 70 64 65 -47 100 -84 63 -46 -15
|
||||
-26 10 86 -64 90 -46 -5 -73 99 -67 -33 58 -49 40 39 78 91 -73 9 62 47 -57 -72 88 93 94 -48 -12 -11 87 -12 -66 34 -7 -82 -72 49 -5 -17 -26 -2 -42 100 6 -27 0 -67 78 -4 2 -44 100 -95 -50 -35 -86 -89 31 -28 29 52 84 73 -15 47 -36 73 -45 -89 -55 -35 -99 -27 -80 -72 -27 82 79 88 40 -90 4 43 -13 86 49 -31 -54 -57 45 -23 55 39 -24 -16 -51 -38 -11 6 -87
|
||||
46 -65 -68 17 -13 32 -51 -51 -35 -89 87 -87 57 93 -81 -75 36 84 -53 83 67 52 53 -58 -10 -88 -70 -50 19 8 2 57 91 -71 98 -22 -82 75 -25 -62 -47 -84 35 -66 67 -12 14 67 -58 88 58 2 100 29 -79 -56 45 -80 -31 83 28 -95 -92 45 88 71 -20 -30 -64 -37 -51 -60 15 -74 1 -97 10 59 -43 49 46 64 83 -48 63 50 -92 40 70 -7 32 59 -65 -95 -57 49 52 -96 -5 60
|
||||
-16 -59 -40 -66 66 32 9 17 43 5 -67 54 40 -31 61 0 61 -37 77 15 -13 76 -68 -90 39 95 -51 14 -20 38 85 75 17 61 56 1 -38 -52 -67 -32 -100 -48 -22 -98 96 77 -96 9 -33 -99 96 38 -98 0 12 49 -33 -5 -87 -44 14 97 -51 -22 75 16 -33 12 -57 -19 -60 -71 -32 -43 16 36 3 -38 67 -53 -31 7 -51 -14 -4 41 59 -82 -81 76 -8 -63 84 56 -52 -29 35 -85 69 55
|
||||
75 -13 -85 30 -85 -98 64 92 63 -79 1 62 -82 -82 -38 14 56 -16 91 -14 -68 47 -89 -54 -67 -45 -42 -65 -27 73 -91 -47 29 97 74 13 46 -31 -99 -17 -32 -1 5 -99 -58 -66 57 9 91 -61 96 6 -33 -15 -89 62 7 -7 -74 68 68 -16 39 -11 95 -27 21 -42 -28 90 -78 40 8 80 -59 -88 -45 -87 83 53 85 -28 32 53 -53 -98 -91 -25 33 22 57 -87 44 82 -88 40 -79 -29 -77 97
|
||||
-26 14 -1 -62 -7 59 -86 -99 -35 33 -59 61 5 49 66 45 38 -15 99 -27 73 -39 -13 30 -73 -55 48 -87 -68 -91 -10 2 -75 25 -53 -61 -56 11 -30 80 83 -79 -62 -32 82 43 -53 -87 -88 44 -29 17 60 16 100 -68 -60 74 32 -66 5 -56 -73 -48 7 -46 57 50 29 -9 85 64 32 -30 -87 -30 62 30 -64 -33 -36 68 -52 -51 -28 38 -18 66 -3 -78 -79 -64 -73 42 -84 52 85 -88 -82 0
|
||||
-79 -38 -21 98 73 -29 12 -19 93 15 88 27 57 31 -43 85 -17 3 76 -96 63 48 -61 -18 40 -27 65 52 55 -26 -56 -32 -98 38 41 87 -97 64 32 -5 -53 -14 -34 -49 -32 77 -67 -48 -26 61 -88 50 -35 96 35 -31 -64 -7 -46 -13 -17 1 27 -72 48 -50 -29 24 -83 -67 59 15 -82 14 -55 -65 -27 0 7 -37 88 -52 -12 -29 -41 -55 -24 33 0 73 -46 -29 -37 -16 -7 -23 24 -67 34 98
|
||||
-23 -35 28 0 -17 93 55 -86 42 -79 -21 -65 37 95 42 -96 -48 12 54 100 -23 -70 42 42 27 69 -49 49 84 -43 -45 100 -11 -75 -36 6 61 -88 -3 -26 76 -49 -4 71 -78 -16 -85 24 82 -98 -30 -77 -29 -90 49 -40 62 50 81 -17 -96 -92 29 100 67 -84 -43 -9 65 -88 -71 -55 -21 -88 87 30 -17 -52 50 -4 -60 -100 -86 -68 55 35 8 -66 31 40 -87 -80 62 -100 76 -62 99 42 45 -73
|
||||
-70 15 -75 37 15 29 -53 -7 -58 87 -77 33 75 -23 95 -43 -83 40 33 -95 74 -90 25 12 90 47 84 52 -90 -20 44 -9 58 -82 50 -99 94 90 -54 -42 -24 -74 -37 92 -13 -71 -72 -5 -96 -25 33 -28 -34 -19 -62 -94 -76 49 12 50 -1 -7 -19 90 30 -9 -22 -52 -97 -15 -18 63 73 -17 -62 13 79 19 76 81 23 -90 50 -54 -88 60 91 89 -66 22 2 -95 -50 -15 80 41 94 -34 -5 -24
|
||||
66 -63 76 -84 48 92 -47 62 -39 23 -87 -54 36 -51 -14 -69 82 19 90 15 -41 97 10 -56 44 97 -97 -38 -26 12 -18 -64 65 -10 82 -42 48 -20 24 18 69 -86 -44 -81 -48 4 79 70 83 50 -14 59 -68 29 -85 22 17 83 25 60 -77 -96 21 17 -91 -77 77 33 8 11 -71 -55 -60 -55 -40 97 96 67 -57 100 66 23 66 -77 -16 56 -48 -9 -65 86 6 48 -4 92 15 -59 65 74 69 -70
|
||||
12 66 -24 -83 -33 -98 -95 72 0 40 -86 29 -14 -25 -24 -100 76 -92 -29 58 63 -92 80 1 -63 -40 -9 -99 38 -4 -75 29 66 -52 -74 81 66 -98 -8 -73 45 -23 -94 0 98 -45 -81 43 83 -73 30 -12 -7 -44 -24 12 42 -57 -87 -25 68 -67 -100 -69 -87 -64 -28 -55 -42 -30 19 31 90 -17 58 -20 -54 26 14 -30 -72 -75 -3 -88 -17 9 -14 -47 54 -86 -19 -48 -12 69 5 -13 -4 -27 -25 -82
|
||||
29 56 -37 21 17 13 -8 -39 83 0 -14 -62 16 68 -2 86 -51 35 -88 26 -4 -59 68 -69 -72 48 31 32 -82 56 17 94 12 71 74 -34 -70 92 14 -69 -45 -1 83 -63 -13 -88 -1 -91 64 -40 -65 53 -82 -54 -93 44 38 -80 46 -51 14 76 -58 -10 69 4 87 84 46 -30 78 57 93 -82 -11 -59 4 85 15 38 66 47 -87 86 62 44 31 -11 -37 -97 27 71 -96 -40 52 27 -16 38 10 62
|
||||
11 74 -7 12 -72 -56 54 -92 -86 -36 -31 33 -48 -88 -91 95 86 -98 3 -1 99 29 -96 23 -92 94 -64 94 28 66 -11 -1 -96 -43 93 82 71 -31 -87 67 68 58 62 97 -31 82 -6 14 18 -36 -33 -59 -30 -6 6 54 -64 -47 -8 -71 -93 90 11 46 46 -75 -98 12 -19 -38 88 0 67 -62 72 38 -41 29 2 -31 46 22 -71 -60 -54 38 -56 -24 72 -91 -57 38 20 73 14 86 -38 -87 -3 42
|
||||
38 -43 -25 -45 -24 -8 11 -32 44 -89 -40 97 -97 77 -85 -32 -69 15 -74 -15 49 88 -67 36 50 11 -88 55 -80 61 91 12 56 -65 -100 -4 -70 -75 7 47 -28 -29 -57 20 -11 -33 -89 -85 13 -97 -6 -56 -2 -91 -91 33 -88 -45 20 94 -20 81 76 9 -83 -98 39 -33 36 -7 -2 65 -78 59 36 -9 14 -15 -27 95 83 99 30 -69 -87 -25 -87 -50 -15 52 54 -4 -74 -66 -78 -19 -91 15 -30 -14
|
||||
-29 9 100 -12 -89 97 5 -12 -84 31 3 -76 -66 -75 -95 -52 66 76 -43 92 72 -83 23 24 41 38 -5 -60 -95 -38 -33 95 61 -75 95 -31 88 -75 5 -67 72 3 -40 -17 56 33 80 63 -31 0 -79 34 -21 14 87 -59 47 -57 37 81 43 -11 10 -18 45 -90 -72 69 -62 -94 84 58 43 -90 -27 79 59 -56 -3 -37 59 -16 -45 -31 43 55 -7 -18 10 -61 66 5 -52 -25 -39 -14 -89 -82 36 68
|
||||
-31 96 93 -100 32 76 100 16 52 -87 55 -94 15 2 -34 63 -96 13 -67 6 47 79 -48 44 -96 -19 69 20 11 58 50 -75 -93 13 18 82 87 85 18 38 19 -88 56 -80 18 98 -65 -89 99 -92 -93 24 -23 -18 95 -21 9 60 -73 26 88 44 78 -69 -73 0 36 -75 93 -13 16 -61 40 63 -37 14 -47 19 10 -98 76 -12 67 -64 2 -10 88 -26 -79 21 -73 98 48 -80 -50 -85 -53 -89 -56 100
|
||||
1 48 29 -19 35 48 84 -6 89 -83 51 45 15 74 56 21 -65 -92 100 -30 -16 -35 -24 -50 46 16 -78 -17 -32 7 -28 99 -76 -14 -69 -46 6 -93 -9 -2 -70 -3 95 -42 9 -67 73 60 98 98 64 33 -27 -64 8 -1 90 -68 -92 -14 -83 50 -16 98 86 -63 -41 62 -15 58 -68 -62 92 -79 -22 -63 -66 41 -34 74 -59 -16 -25 -49 -65 97 100 -43 14 -61 -29 -36 -69 94 -13 -16 61 32 29 45
|
||||
-66 -16 0 -15 18 -48 -57 -19 49 -74 96 70 -6 6 87 3 16 21 -19 91 36 -83 -5 -74 79 0 5 81 14 -16 7 0 14 -3 84 -31 44 -20 62 -89 -51 30 13 54 -4 -27 -1 -48 35 -14 -76 43 -49 74 21 29 -67 60 64 8 -68 57 83 -35 86 -90 -22 -81 -42 93 65 -23 -55 -70 -58 96 76 17 4 16 -89 46 -83 85 36 45 13 -54 95 74 -87 21 47 41 -84 32 -6 -78 97 1 2 6 62 -28 -62 -72 12 27 74 5 -78 -94 81 82 21 54 66 88 -86 -90 -49 -41 22 29 -96 12 -4 -46 75 -58 -73 50 -11 43 72 44 -71 48 53 -81 -28 -91 -96 78 51 5 -61 44 50 52 23 -31 -98 -70 75 40 -43 -86 -50 -10 -57 21 -28 67 42 -38 -75 -95 -69 -31 9 15 -14 -86 -54 40 -22 -57 -32 -89 -94 -100 61 37 53 84 -43 -92 7 -71 -36 -25 -35 -23 -70 -97 74 4 -82 43
|
||||
-66 -93 13 -55 -3 46 47 28 -39 -9 84 41 80 0 -35 32 69 -32 30 70 16 -52 62 13 42 -75 -96 -81 26 -89 18 3 -18 12 94 -61 84 68 -36 -75 -29 -62 54 6 -95 73 -61 25 28 -87 45 -49 83 71 -94 12 12 80 -31 -51 -11 -100 25 -23 55 -66 84 -15 19 -3 70 -81 -24 -65 85 -76 10 70 -33 -19 -31 -77 -4 37 28 64 -32 23 -28 96 38 86 -5 48 -30 -33 -57 89 30 64
|
||||
-9 -79 -30 36 -96 7 -42 27 -46 -63 -76 -84 48 -36 64 -76 5 -96 -44 31 44 -77 37 -1 17 -66 67 80 21 67 -60 61 68 -79 20 -73 74 60 -4 -7 -95 -90 -10 24 10 92 -18 -89 -98 -65 95 -96 -93 89 79 -76 -47 47 -86 -83 70 -45 87 -12 -32 50 -34 -76 -94 75 -95 49 -62 64 -31 -11 -94 -75 -14 -84 -35 -35 26 -72 -91 22 25 22 -21 34 -16 -11 92 -7 -90 -85 -1 -99 94 94
|
||||
22 -42 -66 -11 -30 -81 96 65 -70 -42 -9 -63 89 72 -51 100 -67 27 -58 50 -34 50 70 41 84 -67 12 -76 -25 75 -33 91 53 -43 -81 -33 57 100 -16 66 77 -63 32 -45 -5 36 61 66 90 -23 -46 -57 59 -12 -6 75 4 13 28 -65 -43 95 63 -87 6 -28 67 10 67 1 94 -99 17 -49 26 34 -37 -12 60 -78 57 21 0 -89 94 17 -99 -94 -85 6 0 -75 -54 51 -38 -74 48 40 -44 -27
|
||||
-62 90 42 4 -84 -93 -18 42 55 -70 -44 5 55 -17 -90 -96 -27 34 2 87 -24 -67 -43 73 25 58 100 39 84 -47 -86 12 -23 -19 100 90 -27 73 21 47 -67 63 -36 -18 79 99 3 -13 -43 -54 -47 -31 27 -50 -81 -37 -84 10 -12 -51 1 -48 -24 7 63 -83 33 35 -95 57 -31 29 20 -28 -60 11 25 84 -80 -3 66 -81 84 -6 34 -89 54 26 -11 -92 2 53 92 -89 92 -89 31 55 21 8
|
||||
34 -64 -14 -76 -76 50 2 99 -92 50 -47 -38 96 -74 32 -53 15 12 49 -35 27 -7 -87 27 90 -58 -35 40 3 -79 3 -40 -52 27 -39 3 39 100 -57 47 77 3 -70 93 -8 86 62 52 86 -23 96 -35 -70 -67 95 38 75 99 -58 -70 15 19 27 65 -10 -52 72 41 52 18 14 -38 32 47 -41 -67 -84 5 -98 -16 -60 -28 37 -39 -26 -34 10 74 -83 53 -36 -40 19 -71 83 -50 64 84 87 16
|
||||
35 -6 -97 74 80 15 -32 -100 92 -100 -92 -72 -64 -61 20 -93 -75 2 38 39 29 51 -13 -61 3 76 -88 0 60 31 8 -33 -93 3 49 22 -21 -80 -91 -58 -1 41 -93 -45 -22 -99 14 -63 95 40 39 -100 99 6 -80 16 94 -34 -70 -47 -37 -36 -99 -71 10 65 -43 -88 -19 28 -50 61 -36 -15 99 73 3 -67 -30 -40 23 74 -28 48 -54 -50 -45 -4 60 50 97 100 3 -83 -37 -85 -74 -44 -59 -60
|
||||
30 59 -2 -55 -26 -83 -93 80 -53 -28 56 84 -83 16 -18 -25 -24 -66 -75 22 48 100 64 -59 -43 -38 54 -97 83 59 -99 -74 97 -2 -76 96 -50 -70 0 59 72 7 -12 17 20 -80 82 -35 -55 74 -33 -85 85 45 83 77 -90 -98 -23 24 -58 -27 56 -13 14 18 -71 27 84 -14 -11 -43 -18 -87 50 -54 -20 91 -28 -52 -22 10 77 -94 -77 -32 -7 -66 57 57 -34 -42 -43 2 -48 -23 2 98 -52 -92
|
||||
27 78 90 -36 -98 22 67 68 87 4 -50 -46 15 25 -17 25 9 15 -3 -41 35 -7 -91 -28 66 92 36 -14 -94 46 43 11 21 -46 -53 22 30 -81 21 -43 -4 -77 -57 79 -45 -14 -36 37 92 31 69 23 -14 -10 -30 -67 24 -16 -16 63 -61 31 -83 -9 74 37 77 25 -57 -71 92 -22 6 -100 38 49 10 98 -94 12 11 -94 -84 94 -56 100 -34 -30 75 87 -79 98 8 -7 4 25 98 84 -98 -56
|
||||
40 41 -74 33 48 -11 -47 -1 -21 -19 74 -53 0 72 -37 -76 -37 16 -69 97 -55 -99 -52 -47 27 -96 84 29 -7 -42 -49 -72 59 -82 73 41 -74 -75 70 84 38 -23 -89 35 19 68 -12 -12 77 87 44 71 -57 -4 22 -83 37 19 35 -26 -20 -24 53 -28 31 16 53 -62 62 10 90 -2 33 12 62 54 -39 83 10 8 -3 -17 30 91 -6 -49 41 -25 11 -18 -56 72 -27 9 -90 -71 -24 83 27 -47
|
||||
50 -42 61 10 50 78 48 42 -16 -48 -89 -90 -67 -82 86 27 -90 -98 2 62 -13 46 -64 -28 4 -79 18 -52 38 47 1 -15 4 -70 -48 -45 56 -89 29 -11 -89 -78 -69 59 64 54 45 21 91 -67 58 56 -67 -22 43 1 13 55 51 -63 -42 -8 46 -47 -30 -90 52 38 22 -10 22 -69 -22 -66 -49 -4 -71 -10 31 6 7 80 -49 82 87 -52 68 9 35 -66 76 99 30 40 -79 -53 5 13 -34 -41
|
||||
-26 -100 -32 -87 64 -56 -11 71 -39 -48 -9 -59 -76 -36 -67 33 99 -34 54 -67 100 39 -15 27 -91 -58 -87 82 29 22 38 -35 100 81 84 -2 -48 21 -69 56 -26 71 -4 67 4 3 57 55 -61 -63 -36 -32 0 -21 87 32 -93 74 -11 -100 -1 -27 38 -74 -62 -99 24 -38 13 81 -47 -55 21 -59 24 -53 -61 13 -10 52 9 35 -29 61 97 -69 92 -98 -97 -47 33 -71 73 -55 -65 -78 -4 -84 -7 -78
|
||||
10 -39 -94 -64 8 73 61 -19 -63 63 39 61 99 -36 -88 1 21 69 46 11 -58 -80 4 52 55 31 -84 -75 -92 35 59 -11 59 21 -62 34 42 71 53 13 -88 66 -85 65 -34 -86 11 -24 -57 -45 -79 29 21 22 -27 -94 -49 -42 47 -85 44 86 41 38 6 25 -16 54 93 54 30 38 -72 -50 -92 -35 6 12 -82 -4 46 -40 -48 53 64 -38 -95 -35 21 63 14 15 36 27 -48 -51 -20 -98 47 50
|
||||
-16 25 95 -5 -85 -71 -94 23 -27 65 44 66 -17 -60 -49 25 90 -19 99 63 -53 -39 50 -38 57 0 -29 -58 -66 -91 -89 29 -44 -7 -74 8 -67 -89 92 18 -23 4 -23 79 45 -53 92 61 -15 -10 13 59 17 0 96 -74 -8 -84 49 78 82 63 74 33 88 84 -49 -11 52 -88 71 -13 -90 -74 49 55 50 18 -40 -50 87 -4 42 -45 -98 77 43 -71 -92 88 -43 -27 -44 64 -97 27 -86 60 16 9
|
||||
-14 -86 18 70 -12 92 -37 -24 84 17 25 46 74 -23 -99 46 -6 83 -81 33 64 -40 -76 -69 83 -67 25 -96 -27 76 -24 -10 -32 25 -82 -29 78 9 99 82 -55 66 -52 71 -89 -44 8 -56 -76 24 67 -45 -10 15 -33 -33 77 -82 26 -53 97 63 -68 -98 -97 78 2 -15 -99 61 -70 47 -89 -39 48 52 61 -46 -9 -49 -54 -51 62 -86 -92 -84 58 69 -75 23 -25 44 -18 -77 -57 6 -49 -47 29 -36
|
||||
-83 86 -29 -91 -64 -82 50 -45 -67 -68 42 -38 73 -29 62 -44 -19 22 67 -80 -30 24 36 -25 -11 55 -31 98 12 72 -88 -65 29 89 -41 28 -97 15 49 -100 41 57 -96 -11 16 32 61 80 -15 -48 -14 23 4 -85 40 -35 18 45 -44 -60 -93 -43 24 71 -65 75 -25 82 94 82 -54 44 -59 87 -89 54 81 6 -10 -92 98 26 17 -55 14 86 -76 96 -23 84 73 51 -15 -95 90 7 70 -17 90 -17
|
||||
-60 -25 33 -16 -74 -22 7 95 41 -72 -39 21 93 -44 -13 -15 -79 -83 -76 -70 86 -90 -90 46 -3 50 -41 -74 -74 20 -24 -12 -94 -64 59 62 85 -31 -84 94 65 -89 -72 -12 -69 -41 31 49 -53 -22 34 88 63 -36 -1 -95 -100 -93 -53 -75 44 64 -20 5 26 -19 0 80 88 94 -13 -72 96 92 75 -66 18 99 4 35 66 -56 7 43 1 -94 82 94 22 31 42 15 -16 -22 -37 14 76 45 -75 -45
|
||||
-65 2 -8 90 75 36 -52 -29 72 34 26 -86 -6 55 74 52 79 -15 95 -70 62 -76 34 -20 68 28 -23 6 -41 20 -67 -1 100 11 33 63 4 -95 -85 -17 33 -59 -15 2 90 49 18 -75 86 -67 50 51 52 57 50 11 -44 -99 -76 -1 5 -61 38 -29 -54 -4 -6 -40 -88 -69 -16 49 -20 -28 -85 -61 58 -2 -84 93 -47 63 94 0 -80 -67 13 -14 -8 -14 83 24 43 -61 -65 -34 -82 44 -64 77
|
||||
35 -79 89 23 74 74 94 -52 87 -40 -90 -32 3 -14 95 62 -9 3 97 40 -53 -37 5 91 15 69 -91 -71 -46 -63 -83 46 85 -24 -16 -22 -39 31 31 19 -75 12 36 -12 65 78 14 -14 -52 4 -65 26 -63 -24 -56 92 -34 51 -93 -42 3 -16 99 48 -36 -17 -30 -1 96 -95 -73 -78 -92 -12 -19 -75 43 -37 52 -52 -59 -9 -14 -34 25 -78 -59 36 -91 -23 20 -94 -81 48 -20 -28 14 -19 32 22
|
||||
42 49 78 51 -49 -87 19 -36 -60 36 63 83 -20 -25 23 -72 84 58 60 11 -55 -22 -37 -15 44 96 29 72 -4 75 -93 -55 52 -27 66 -30 -10 -61 74 -50 51 -19 -70 -9 86 -78 -7 79 44 -55 65 56 18 -10 31 -56 37 77 45 -30 62 68 15 23 -68 10 66 96 89 -85 -21 95 4 -55 96 -29 22 77 42 89 74 -91 -40 96 -1 86 -9 28 36 -30 -77 84 96 13 -83 -47 -9 10 42 -2
|
||||
-15 -94 -62 69 97 -86 -16 72 -96 56 74 -75 -83 57 -23 -58 18 62 -19 69 69 23 -6 -21 70 56 31 -97 -64 71 -94 -84 -48 0 -49 -92 -77 74 -44 -91 -65 96 77 -14 45 -86 30 88 78 91 77 37 -74 10 -40 98 55 -57 -86 84 -50 -79 -15 52 10 -7 -70 59 55 6 18 -67 12 6 -89 8 76 -90 -93 73 -63 -89 100 19 -31 -66 -11 -67 -76 95 54 -72 -35 -18 -70 30 -62 -60 14 9
|
||||
14 14 6 49 88 -46 -94 85 -52 -59 -55 -1 -66 -58 50 -87 16 -72 -53 -18 -54 -84 0 10 -21 62 -67 43 -94 -40 -43 92 -81 80 -41 -97 17 -33 -83 37 48 40 -94 32 7 -19 -23 64 -70 -76 -84 95 -57 48 3 -40 -86 -44 7 67 72 72 98 -97 -24 -98 -70 -59 -26 -3 -11 29 12 4 26 98 1 65 90 -93 28 -5 49 -91 32 65 -49 -79 11 -24 7 -73 -49 -49 -36 28 -89 -46 -12 -50
|
||||
-63 -14 -98 -86 16 47 18 -11 -48 -2 88 -86 15 71 -32 -27 99 -41 -44 -20 -76 82 -86 81 -80 -57 76 57 84 -83 1 54 44 53 -99 -71 44 -3 -90 30 43 -5 88 33 -73 -84 35 74 55 -93 81 27 -45 85 79 81 87 55 -32 -77 25 -76 -50 80 -69 44 81 -62 53 31 29 -32 42 -10 9 15 -1 65 12 45 -19 17 25 42 -69 -65 -4 32 -84 -42 57 40 81 75 -18 -55 63 -93 10 30
|
||||
28 98 -39 -12 -89 34 82 -4 69 38 -48 40 85 6 -40 9 -53 99 47 -73 25 -85 68 -62 53 13 -65 32 1 15 -63 -40 93 -82 -59 -57 57 -44 -30 92 -80 -38 -78 -13 31 -3 17 -38 57 -17 -8 -74 54 45 -78 82 12 -55 5 -65 43 -74 -33 15 -5 -63 17 26 -7 45 -2 1 49 -54 -4 88 -86 -28 -77 -70 67 82 41 5 -57 23 42 -40 60 5 77 16 -75 93 84 25 75 -53 31 -13
|
||||
-54 40 64 77 -14 -95 -10 -85 -59 -8 1 28 79 83 -97 56 -4 -42 -83 -14 37 -75 -67 -32 91 -2 96 -29 100 95 -61 -80 -8 94 49 -14 -24 47 11 -74 1 26 -31 -14 -14 -62 -87 58 54 37 -73 73 -79 88 58 41 -56 94 11 70 -4 -97 -85 -52 96 -7 -29 -63 -80 47 50 -25 -79 -69 55 42 -17 -9 43 36 2 93 96 25 -95 49 -35 85 68 92 -16 -92 -28 74 -37 -73 34 -97 -49 -8
|
||||
9 53 18 -90 -76 -81 12 -55 63 -10 -40 -79 21 18 -84 -49 -58 -30 55 -21 -94 -43 -64 14 18 -84 -42 -96 25 -33 -83 -58 -21 44 34 28 -65 37 20 -100 -33 -56 -48 -20 -31 -44 78 -23 79 78 85 18 -10 37 -22 26 77 83 16 43 41 -21 -75 -48 51 -54 -12 68 66 9 55 42 13 -49 31 34 -47 -100 52 48 90 39 64 -32 -63 27 21 -86 -97 48 3 -28 -62 -37 8 -91 25 -4 -59 79
|
||||
-44 -99 49 84 -20 94 -39 -16 -40 -44 41 -75 -97 -1 -66 -20 33 12 42 -66 25 -58 80 62 -68 30 -39 -25 28 95 33 100 12 -49 50 58 100 -66 9 -81 -73 42 28 96 71 -48 59 -68 -67 -15 38 -36 -14 -66 -72 -72 66 -49 87 -28 8 20 -10 -8 97 -55 -88 -43 15 73 -16 0 68 -18 -16 -61 -7 -65 41 58 -21 -5 36 67 0 11 -31 -100 32 13 -34 70 -36 -76 7 -12 90 85 -49 -100
|
||||
4 68 -66 -98 -81 -61 82 -84 -33 -17 44 -72 51 22 69 -9 37 -66 2 -74 41 -39 -63 -10 -51 -27 44 35 5 17 21 -98 97 52 -91 40 47 7 -75 48 58 -93 91 69 7 -63 -8 81 40 21 90 -50 -96 51 70 -34 2 44 36 21 -45 -13 -22 -99 -39 46 48 -57 -33 25 29 76 77 -41 -39 -76 39 98 -65 -19 59 -25 73 53 17 62 41 84 -40 65 21 -1 -26 -21 -28 61 86 27 -61 -18
|
||||
62 85 6 82 87 -24 34 -71 11 31 96 72 11 79 100 -54 100 66 -1 -14 71 69 -20 79 -84 -43 86 96 -34 15 -28 18 30 -45 -19 97 12 -62 34 -84 36 -2 -60 -55 -77 44 -18 -37 97 1 -72 91 -14 32 -4 -31 -93 -29 16 43 99 25 97 23 -31 77 37 90 50 -6 11 83 -91 50 59 67 -54 -88 -37 -73 -92 23 51 27 62 -82 -38 -65 6 91 -61 -78 -60 -61 -7 -50 94 -13 -97 -67
|
||||
56 64 79 -87 13 44 95 46 35 -13 -3 48 -61 -100 -27 -54 3 -79 89 -12 -4 41 16 -40 -50 -96 56 -4 6 -68 53 13 -20 -5 20 36 -64 -38 59 2 82 -51 89 -27 -77 -77 -29 -33 76 -32 32 84 -28 68 64 59 94 34 -13 82 -42 -77 -91 23 -20 73 100 70 14 61 100 -65 -47 -95 -12 16 84 -25 50 70 35 -95 -86 -98 -37 51 30 5 -11 37 -86 30 57 99 96 94 -47 -11 90 25
|
||||
26 40 32 -89 96 -17 78 -88 62 -79 98 -22 44 -50 44 51 15 44 31 -37 -46 -62 11 -70 -64 -24 12 59 29 88 92 -94 -60 36 67 -31 72 -14 91 -15 -62 -76 -29 -14 -1 14 -92 93 -92 -2 -29 -36 0 38 80 -66 22 -98 -72 44 -68 100 41 0 -4 -78 61 -85 96 -89 -18 -36 -81 -7 -97 64 76 94 -26 -80 -33 24 84 -8 92 55 -79 -14 -21 -54 46 76 -90 17 42 45 -27 98 -65 10
|
||||
71 -42 99 87 1 83 61 11 40 79 69 42 66 -68 -46 10 -79 -42 55 -47 87 -64 -81 8 32 16 -78 9 38 -34 17 76 -11 42 -97 44 20 57 -72 -91 53 -95 -56 -14 -72 -41 5 -51 -10 -36 36 -25 -62 84 98 65 40 -50 -7 -5 -81 26 8 -42 -45 91 -69 -90 6 -13 -99 -73 -56 21 28 20 -64 88 8 90 22 -31 68 -42 -74 56 -71 21 -72 56 94 -27 52 -83 79 64 -22 -89 -94 37
|
||||
-45 -69 6 -54 -81 75 24 -84 74 34 -66 51 -92 14 -99 -73 -45 85 28 -84 -31 -1 63 -66 -9 -86 -17 24 65 82 -68 -100 -55 -31 -58 30 57 -49 -86 -7 -44 -28 81 -6 95 -44 54 47 -39 22 98 -85 4 50 -33 -100 -38 -51 -25 32 3 5 -97 4 -74 -95 -41 73 95 43 96 76 -74 -77 -71 87 -86 94 -7 -72 -67 -83 -60 -54 83 74 -10 68 12 -51 -91 24 55 3 -77 -85 -85 -94 -93 -63
|
||||
53 -95 -83 -62 7 -14 15 79 -97 -47 -94 -57 -96 45 80 90 -59 -4 -33 -48 14 38 -1 25 10 -83 62 97 53 -44 -85 62 -56 47 38 -43 46 39 -55 -60 -87 63 4 -38 -13 -44 14 -23 -12 -84 -48 -65 -40 4 43 45 10 -2 6 44 -21 50 48 67 -89 12 60 -18 -95 -61 20 30 7 79 -12 -60 -38 -74 -20 34 11 -74 75 48 -48 16 -10 -11 -38 66 72 61 16 86 97 -42 8 52 -39 -60
|
||||
-49 -88 -47 -57 -8 -95 -1 14 27 0 47 36 -95 -59 14 12 -44 -28 -71 -88 -40 64 -59 85 -42 -72 66 -78 2 -52 67 -97 31 84 70 72 85 3 -93 8 98 99 -83 17 82 -36 41 -44 65 39 93 -14 -34 57 27 97 34 63 -23 -22 77 -87 -26 60 -26 62 -77 -70 67 -5 -11 10 25 -54 39 -68 -86 23 46 -19 20 -81 97 -81 99 -68 -45 -13 89 23 34 67 53 54 -5 -74 56 59 60 10
|
||||
47 -57 82 -48 58 -15 -88 58 22 -15 56 57 -57 7 -72 -43 -26 19 -54 76 -16 96 -35 84 3 -11 19 -63 -38 -95 -65 84 8 17 -87 90 62 -8 36 79 92 77 -61 35 9 87 -95 59 -43 71 -14 79 -35 -21 49 59 -91 -79 -9 53 -58 91 -93 -11 -11 -65 36 -37 -74 67 -83 -51 17 -80 -80 -61 -90 -50 -3 -47 10 -5 -87 -87 -47 20 -9 -38 41 -38 25 -77 48 57 11 -87 19 76 -68 33
|
||||
-22 73 -67 -98 78 31 48 20 67 86 -81 -58 -66 -3 -66 -8 -32 26 -65 86 -36 79 -55 47 60 91 31 99 -84 48 -2 -94 -62 -65 -48 95 60 87 -79 -95 100 3 49 70 -76 33 -64 -61 -47 73 57 -97 -71 -10 6 -7 -63 30 95 -91 -78 50 26 59 63 5 -30 95 36 48 -60 -27 -37 72 -88 -63 -75 -91 84 -80 -57 -34 57 42 -42 -41 -89 -99 -59 41 -28 65 -41 -30 30 69 -16 95 -46 -100
|
||||
59 22 -18 -36 -46 -27 -9 74 -58 95 -48 59 -83 50 -43 -75 -57 65 -55 92 60 67 -1 73 -71 -34 96 17 -78 27 -99 45 14 54 16 -84 -95 16 98 -7 25 -10 -14 -47 8 -3 86 28 -58 -54 20 -88 -40 12 -48 -20 -80 -46 -19 -62 -86 32 -13 -8 -27 78 65 68 95 18 -19 99 48 83 64 94 72 31 95 51 50 -2 -95 -91 36 0 -13 -81 25 32 -73 40 37 28 -17 -29 56 74 55 -29
|
||||
-34 -73 -34 91 -34 -46 -81 76 -49 79 49 54 62 -66 -61 99 46 -31 43 10 -18 -17 -78 22 -74 -79 27 -7 -46 -4 44 -74 36 6 84 97 -30 -70 3 55 -41 0 27 -84 -79 -75 -75 -11 -64 -61 -5 2 -28 -90 -89 -53 -14 34 5 13 88 -32 -65 -47 -39 -75 -39 -18 -66 -100 82 -96 24 100 17 -90 -30 -15 59 42 25 -85 46 60 -26 38 -1 -78 -64 -15 -89 53 -48 -98 26 54 -31 12 -77 0
|
||||
-55 60 62 1 -10 55 -84 68 -66 12 62 -7 0 10 -86 99 -33 54 31 37 58 -99 5 30 48 89 5 28 -66 -38 -10 -62 -55 -43 61 76 -41 -59 40 -51 -83 -41 -19 26 -74 63 -15 -22 52 -47 -81 100 82 53 -85 92 -12 -43 21 -62 -89 -33 18 45 89 46 -74 24 57 -66 61 56 -30 92 97 92 23 -72 88 -13 -3 -44 96 -93 -21 44 -25 77 33 -24 -63 -50 -83 71 95 -87 -71 78 -39 99
|
||||
2 18 -93 -15 24 73 40 59 83 67 15 -35 15 -35 16 69 5 -28 61 90 -87 -31 58 47 39 10 74 38 39 -66 -91 23 60 79 84 -32 -12 15 85 73 30 8 -99 -41 -66 -94 57 -8 -57 76 59 49 40 53 -28 -51 -12 -31 -16 -37 -12 -43 34 -17 -95 68 -21 -23 65 -61 95 26 -18 -86 71 59 -29 70 -28 31 0 13 56 18 14 15 -54 62 -92 -79 84 55 45 15 11 -52 -17 64 -93 -6
|
||||
68 -52 21 -12 -71 95 0 90 12 -11 4 14 -13 -94 15 88 -100 -98 -81 -91 95 -1 33 -7 90 -37 83 -33 11 5 -40 -41 76 -74 90 75 52 -56 11 39 -88 -94 60 84 51 18 -29 93 -84 53 71 90 -86 73 -98 -19 -44 76 -10 -97 -50 74 24 62 -72 -89 7 -48 7 28 57 -20 -87 -91 27 89 -72 56 32 18 100 23 79 -96 10 24 -11 -84 78 -74 9 -82 -44 24 -18 23 50 -9 75 -24
|
||||
24 -56 54 29 72 -100 35 17 -32 95 44 -30 8 -89 33 -85 -100 77 -100 13 67 -82 98 -28 16 94 -64 -97 83 -12 -24 9 -20 -69 -11 -8 -85 -93 41 0 96 -69 35 96 -12 3 -87 100 30 88 77 9 69 77 -50 70 70 43 -66 -84 -62 29 -10 -96 41 -57 24 -41 81 81 59 -37 -100 95 21 -84 25 29 37 -52 -25 62 60 -9 47 56 -85 -83 18 -38 -68 26 -56 -23 42 25 21 -66 43 -34
|
||||
-54 -61 23 -83 58 6 24 -100 97 -72 -35 -64 42 47 -58 22 -77 9 4 78 -2 41 76 74 82 -11 -7 92 32 -94 -72 -54 -80 9 45 21 -47 66 -36 -81 35 12 22 -3 -76 87 23 -8 7 -32 57 44 28 -46 -27 -50 -3 96 -84 64 -1 -65 58 -70 -76 2 -30 -91 -73 -23 -78 -21 -30 -37 -28 -77 59 -20 -51 -58 18 -94 95 23 8 98 -8 -63 -33 -21 13 14 93 -85 -45 -70 54 -58 2 10
|
||||
16 62 -12 -41 -53 33 77 -68 93 20 73 80 -54 47 -38 18 -54 -57 7 -90 55 -26 -27 63 -10 34 44 52 -88 60 -56 -42 0 19 53 57 90 -71 56 -51 95 -50 91 39 59 -26 6 79 -70 32 43 -39 -78 -17 -56 87 5 47 6 -93 51 -4 -36 -51 50 30 53 -27 61 -47 -46 -23 33 42 -99 89 97 -79 -25 -8 2 -30 7 85 89 65 -73 56 -100 -11 -81 -8 82 98 1 -32 54 54 0 -32
|
||||
-51 -42 -94 -99 5 -33 93 46 7 75 -97 16 -93 82 12 70 26 11 65 50 -71 -46 -38 -51 19 -2 1 -3 -90 98 -38 -86 80 26 42 -24 -30 63 95 -11 -25 -56 -23 58 -65 -46 -46 41 25 87 54 -60 -58 75 -52 18 13 9 58 57 37 35 96 4 -16 -66 -16 -94 17 -52 85 -71 -82 18 46 -88 78 60 -37 -58 65 43 38 68 -83 -53 73 81 -91 -3 23 -96 94 72 9 18 -93 29 42 82
|
||||
92 -20 -91 -8 88 9 13 60 80 -61 -95 -73 22 95 -45 69 -87 91 -21 23 74 36 36 84 44 98 5 -85 14 -84 -88 15 -11 35 -39 -32 -19 58 -12 -18 29 -100 11 -27 24 0 70 21 -66 -53 -81 44 -59 -60 11 74 21 84 48 25 -5 80 99 -11 -5 -97 -19 75 -5 -5 -68 30 90 -52 -24 -65 -28 65 5 -39 89 31 88 53 -79 -8 20 -54 47 7 52 -13 -86 4 -98 -94 50 20 82 76
|
||||
75 -2 30 -36 3 -40 92 -57 70 13 90 61 -63 -8 25 -39 -91 -14 -8 3 -45 5 70 39 -67 88 -38 -6 -43 -29 -69 -39 -33 -80 -46 -74 13 84 -48 43 23 -69 -94 60 -28 2 93 -13 54 -26 -92 -39 -45 61 -35 -51 -91 53 70 -99 53 42 97 85 -98 62 -3 53 46 8 -70 -63 -4 10 46 98 95 -62 -73 78 -34 -76 -91 -94 -79 33 95 9 -48 -23 -91 -6 -84 77 -44 -23 -7 -29 74 82
|
||||
59 -74 30 -17 -10 -93 -75 -25 -60 4 -52 -61 89 89 47 -100 57 17 26 -27 -73 -100 20 22 93 18 67 -17 46 6 -49 2 96 97 70 75 65 -90 -83 -64 -69 -20 93 94 -58 -49 36 57 10 88 36 -28 -80 2 -88 70 -79 -82 97 -40 38 71 52 78 -45 74 -38 6 75 -7 -49 -94 75 -93 76 -87 -85 56 33 78 -67 -42 20 -15 1 13 -39 34 78 -94 -22 -81 30 -18 51 -51 78 -26 52 86
|
||||
59 0 -66 -33 -24 -2 23 -19 -37 31 -16 12 -6 45 -7 -50 -20 27 -84 33 88 58 -86 -40 60 14 -17 61 14 77 -3 78 84 59 66 44 -82 -40 97 51 -87 21 49 -32 -88 -46 -52 -54 68 63 -15 3 1 -7 23 31 -61 82 -6 31 81 1 -18 32 45 56 -54 42 -64 -59 95 3 -71 -54 -95 -63 -79 2 84 -98 70 12 85 79 -69 -68 -4 100 -26 -27 -21 -83 -52 50 -37 37 -20 -16 92 -54
|
||||
-75 -78 88 -68 83 -3 75 -12 65 61 70 -34 99 45 -1 47 -35 58 -21 -92 -5 -22 -76 87 -8 65 51 96 -98 3 -56 17 63 -47 -58 -47 -17 12 0 -65 -89 -24 69 -82 -38 -33 -87 -78 -72 26 -79 -74 71 -81 -95 61 -50 2 -29 -84 55 -46 33 68 86 -15 -80 59 39 -64 -74 100 -38 37 63 -64 40 -65 64 -55 88 68 94 90 87 -3 -27 -62 82 -15 21 -13 -34 -17 -24 -48 70 -76 -89 92
|
||||
-84 -82 -2 85 70 76 91 92 -24 -39 31 81 68 -36 -95 -24 -99 -2 -77 -71 -83 60 64 -100 11 32 -59 43 -53 19 85 -74 -13 75 -59 30 68 -44 58 -91 -86 61 -51 8 34 67 -13 -98 -91 46 -71 -5 39 5 -61 72 76 37 -51 84 -55 34 -53 -82 -47 7 11 64 -82 -60 -39 16 55 -2 26 81 19 9 -7 98 65 66 -30 -49 94 75 10 40 -64 40 1 15 75 18 -73 42 94 -85 -64 84
|
||||
-97 77 61 10 -39 99 -12 70 85 3 -11 61 98 -11 76 4 27 28 61 -10 -55 39 50 26 4 13 -22 2 -87 -10 -41 52 -85 21 -35 99 13 -95 -72 -8 22 29 90 95 -93 74 46 37 -81 51 86 -26 -95 74 51 -33 -77 -95 -60 81 53 75 -77 80 69 -25 6 95 19 -8 54 -87 81 28 69 19 -90 62 21 84 -16 11 92 -19 -28 -4 51 8 40 45 -43 59 -66 9 67 5 10 90 -58 -8
|
||||
-8 16 70 -22 -40 12 2 -68 -93 21 -92 -72 -79 -91 -79 87 20 -44 62 -96 29 36 17 46 -92 -77 27 90 -99 -83 93 -53 42 -73 26 3 -63 15 73 -10 61 18 3 68 -5 -62 37 11 -81 0 54 40 -38 80 18 -37 43 45 27 44 -75 76 1 -60 -94 89 -11 -3 52 -88 -36 12 -35 -15 70 -1 100 -93 54 44 -81 -99 -1 -97 42 58 46 -31 63 -96 -94 98 2 11 -36 24 7 2 80 -89
|
||||
-57 -90 -41 17 -47 -55 -11 -79 -63 90 22 -84 73 92 82 -98 -40 -23 -82 -14 46 -66 -49 -55 -78 -33 -55 86 67 -36 -43 -83 39 44 96 42 -61 94 -93 70 -56 -13 -5 -11 -4 -40 81 13 -36 -61 66 30 22 82 66 -79 35 10 -10 3 41 -94 71 98 -86 -15 25 -98 74 2 -82 99 33 -73 -70 -50 -23 99 -38 -38 -32 -22 -10 13 16 35 -86 45 23 -70 97 59 90 43 -60 12 65 -97 98 50
|
||||
-4 -55 -24 -54 58 8 -17 -9 4 -89 -53 13 9 -31 -15 -91 73 63 -93 -42 -39 39 -41 -5 -83 -46 35 -5 -7 25 39 61 69 -67 -14 22 6 80 -12 -51 -92 57 9 -53 -82 17 55 -22 -62 33 5 -84 -56 -70 -38 -33 -33 88 34 0 -75 -10 -45 -59 -9 50 -100 76 38 -83 46 57 83 80 -14 93 29 40 28 -89 -68 -76 -85 62 94 -91 94 68 49 100 -73 -32 42 29 -67 -71 -83 50 25 28
|
||||
82 60 5 -70 31 -95 49 66 -62 2 -6 39 44 90 -72 19 -68 -55 90 -73 32 23 35 44 50 43 -27 5 -61 36 -4 -1 -4 83 -75 54 -44 22 73 60 50 85 6 90 96 -72 -50 72 79 17 -15 -99 90 97 85 -77 96 -23 -59 2 -44 -28 -94 -78 36 -83 -21 84 -73 53 -11 -34 -80 -94 -50 17 -50 -58 -42 66 70 -55 82 -57 -7 -25 8 31 92 -45 20 26 3 -72 -63 65 -98 -78 65 -62
|
||||
74 78 -5 -68 35 12 -2 -40 -83 -12 31 63 -46 77 -70 88 5 24 48 -70 -88 -87 -87 77 55 67 10 9 -70 6 51 -79 67 18 8 -95 -46 -68 38 27 47 50 24 5 47 -100 -81 -14 71 61 -47 -79 46 -29 -98 16 -10 49 -50 37 -47 -30 81 35 58 90 -91 65 -81 85 -63 -57 -63 91 59 -54 -66 -89 -76 -22 -38 86 -50 0 -19 -24 7 -39 53 79 73 14 -66 33 9 41 3 42 -65 97
|
||||
-14 0 -79 -23 -11 85 0 -71 -83 -72 -79 -34 0 42 81 72 -39 -44 -23 64 58 100 89 -33 -40 -14 -65 -68 27 79 81 -93 -10 50 -30 -62 -18 28 -53 66 60 -14 -70 -13 26 -67 -55 -20 -56 10 1 81 -28 -74 41 46 38 97 8 82 -72 -89 23 62 72 -42 71 24 -10 77 -7 83 15 -69 49 85 88 93 -7 20 -11 -27 -16 -98 -53 40 18 88 -32 6 -91 -24 -36 -93 -37 7 -53 100 36 -20
|
||||
-25 -88 36 -36 70 83 33 -7 -22 46 -23 79 -65 13 -87 -37 43 3 -81 44 38 -99 97 23 -3 -70 -60 -92 54 -25 63 -56 -60 -22 64 97 8 80 20 -46 -27 -36 45 37 99 -48 42 83 -9 -92 -81 94 79 76 69 10 -49 39 -64 -11 -51 49 -67 98 5 85 -57 25 -21 26 -70 39 58 -51 21 -62 -99 17 -44 -91 49 -17 -29 22 -4 -95 -38 91 82 64 -63 20 -7 -32 -12 -58 31 24 -35 -95
|
||||
47 -23 18 1 89 22 67 90 53 63 -32 69 61 29 25 55 71 -44 -25 89 -39 -32 95 35 75 -19 -24 37 13 -94 93 71 4 -91 29 100 48 -1 75 -6 -62 -51 -20 -12 -37 -18 91 51 12 94 -14 80 -47 -87 -13 -78 -13 -89 -62 -22 86 96 43 -64 -26 -24 -75 -71 6 -70 8 98 -64 33 93 11 -83 -70 -43 -70 100 -98 93 -32 -2 -93 -37 -80 39 90 -3 38 -64 -97 -91 74 14 -52 -49 13
|
||||
90 -56 -88 -55 -1 -81 -37 -50 72 18 -97 -80 4 -62 59 91 31 -72 40 35 -8 40 35 96 -82 46 -74 8 -79 45 -5 -72 -20 -43 -15 74 -98 -61 -74 -44 6 -79 44 -69 58 24 77 -23 78 -7 -44 77 -36 -48 -64 25 -25 -79 -94 -41 -73 -7 53 39 -83 80 -30 -25 57 46 -98 26 71 49 68 -36 -90 2 14 84 -48 27 -16 -32 -28 -4 94 -27 -38 65 -86 29 -82 -61 75 33 68 -84 -24 -76
|
||||
-19 -89 -82 -30 17 -57 37 -90 -79 19 12 -39 30 73 25 -35 -63 -37 10 89 34 40 -25 79 71 94 59 -26 22 84 87 -36 32 79 -47 1 -74 37 70 -53 -22 30 42 77 -1 -38 80 -75 -95 48 57 -35 -98 -86 81 54 -91 -29 -7 54 28 27 -79 -28 58 21 76 -32 -67 -74 25 17 84 3 -14 -52 -73 70 67 -47 7 89 -39 33 21 55 32 -16 -88 88 -80 -40 12 -96 97 -29 -68 10 90 -91
|
||||
4 58 -88 -68 -20 69 -20 47 74 -93 0 -30 60 -99 -94 -27 -43 20 81 51 19 -85 -34 -48 -52 -84 -14 -89 -27 -26 -4 91 80 -74 -45 -66 -100 -70 0 68 96 -10 47 23 33 70 -10 16 -95 -97 46 -78 -34 -64 43 -20 0 24 -78 -95 65 23 70 78 -19 -26 -11 -13 -57 -59 -31 75 64 74 31 -8 36 -62 -47 -61 -56 -75 84 -89 -24 -21 -4 16 93 79 -46 34 100 68 8 -59 63 -10 -53 41
|
||||
-35 19 -2 -12 -23 21 -84 -34 56 91 -30 -95 -82 -60 -94 14 61 60 -53 85 -79 -18 -1 96 -5 -41 73 40 -94 70 1 -2 9 33 -65 -48 -67 61 -64 -91 -37 58 -8 43 -13 93 23 -55 -61 79 -3 85 10 -79 -13 -30 -43 57 62 -83 -68 83 -22 98 -84 -21 -41 1 -27 65 5 92 -47 72 77 100 32 -41 -35 -90 37 -6 -77 -89 -24 -79 -77 93 -70 -91 -80 31 -80 66 -67 85 50 5 -89 -77
|
||||
83 -35 -83 53 45 92 -14 2 86 67 79 13 -30 -62 -58 -43 -77 -87 71 -16 -55 -92 -64 67 89 53 -12 91 -98 24 -13 -82 90 98 -55 -50 -46 94 56 82 -74 -77 -66 -3 -66 -14 -87 -17 -68 -98 -88 21 11 -50 -53 -31 -58 -57 88 -55 34 19 94 71 -31 -16 -29 -31 -53 87 37 -48 6 -11 34 34 98 9 93 59 -7 25 -76 89 -55 29 -60 68 58 -37 -85 67 59 97 82 46 44 -72 42 23
|
||||
-15 -69 71 95 72 -39 -87 49 -93 -58 73 -65 -55 -12 -16 -51 99 36 -23 56 44 0 19 -42 -27 -1 -56 -85 -75 8 -72 -58 62 -78 30 15 -65 84 32 57 -58 -29 -62 -9 -28 -57 -18 -92 -47 -54 36 -17 -62 -82 -80 9 7 -20 74 23 89 94 74 -27 98 -87 -15 0 -1 20 -36 -41 -94 79 -87 49 27 17 -68 21 -97 -19 -11 80 -69 47 19 72 -14 74 63 53 -9 -2 91 -31 13 -38 -26 -59
|
||||
-26 19 91 41 -41 -6 83 -72 -49 -11 60 -70 39 74 -62 39 54 49 45 -49 -26 0 -69 32 -92 -25 -67 -91 -63 28 85 -58 -80 32 -82 -68 28 4 -66 58 74 90 -39 -65 -81 -59 31 96 -64 -16 60 -16 -88 70 -82 -26 -69 14 -12 57 89 -37 46 53 -59 -91 -59 -10 -26 90 72 -41 -1 -12 47 43 -83 -3 0 73 -30 -21 -78 97 94 -28 -33 64 -71 8 75 93 -49 -94 33 94 -83 -56 95 88
|
||||
16 16 38 45 -5 99 -93 4 -74 -72 -33 56 -43 -60 69 81 -9 46 -58 -87 44 89 -5 58 33 -73 -27 -82 81 -6 -65 -3 93 -83 2 71 37 79 2 4 49 -10 18 -30 -20 23 -31 -79 54 90 32 -9 -94 -97 58 62 70 88 -38 78 -67 -18 53 -96 -33 -29 -33 43 35 -82 -71 -77 50 -22 -38 90 -48 93 -27 50 31 40 -2 54 -23 58 -38 92 -92 -63 -22 -41 -83 89 7 -43 5 -64 -64 -69
|
||||
-25 60 -97 -77 -40 -35 69 -54 59 -33 30 54 -88 37 -4 81 22 34 -89 35 54 81 13 -92 -98 -58 -80 29 65 93 63 67 -69 73 75 42 -24 29 45 32 44 13 -28 -84 40 -63 -80 28 -78 -40 -49 65 16 94 -88 68 -36 -49 -39 93 -44 68 -21 71 48 -10 -64 -91 85 12 -61 -64 -28 -73 -23 41 46 -89 54 97 11 -13 -34 1 -91 69 -15 90 -48 35 97 77 24 -2 -70 -2 -79 33 12 97
|
||||
74 -42 -46 97 59 -68 73 -69 -56 50 24 62 82 -87 44 27 -64 59 9 5 -69 69 90 73 10 -48 91 -6 -85 57 -40 47 -84 -29 -25 -52 19 96 81 -83 -79 78 -91 -49 90 68 7 91 66 26 28 -41 -85 -61 -57 47 80 -48 86 -27 1 75 88 41 46 89 0 73 13 37 -32 88 -86 -28 -59 84 -68 54 36 -36 5 -5 32 1 -18 18 32 -32 -13 0 -87 -24 49 -11 53 63 29 -38 -92 23
|
||||
19 -61 -93 93 44 64 93 21 4 91 80 86 -64 -53 -64 -1 85 -2 -36 91 38 -6 -47 -20 -66 36 25 -49 -89 -66 -58 66 -24 -77 73 -84 -32 -27 -70 7 74 -79 -44 -11 -15 57 -87 41 5 -75 66 -17 35 34 -65 71 8 85 97 16 -46 -40 88 53 7 56 57 72 6 62 33 43 -63 -63 48 -36 80 -49 80 -96 -87 62 97 2 -81 -2 -71 87 -10 0 -86 25 4 34 -90 -23 47 -71 -39 -14
|
||||
72 50 85 -62 -31 -72 81 -29 15 -20 -45 -76 -29 -22 85 -33 -85 45 -78 -8 -81 -15 33 -85 94 21 14 56 -98 -57 -15 47 57 -48 76 -31 -31 -25 100 73 -53 -90 -83 52 41 21 82 74 -21 92 -99 21 22 -57 33 -11 -53 -66 -58 -45 -74 89 93 -56 -37 -66 47 -29 44 93 -23 69 -51 26 38 94 30 -40 -77 -38 -53 -23 76 -46 -98 -56 12 -14 61 -67 61 -63 34 -45 -80 -76 67 -97 -54 -86
|
||||
48 -90 100 -62 46 -24 -15 89 45 -85 -4 -34 -10 26 36 -77 84 -66 -60 -74 -47 -93 -72 -7 34 71 78 -22 -3 -70 24 -27 34 23 29 -16 19 -47 -63 -46 11 -28 55 -14 -46 90 88 -7 -26 -22 49 -46 -54 52 86 -33 -53 38 99 68 75 13 -15 -96 -21 -22 5 31 9 71 -52 -20 -63 -15 -85 20 -88 -59 36 67 -55 -68 -74 73 -54 100 14 -7 -7 92 85 85 -20 -12 -19 98 91 33 -45 -77
|
||||
61 2 47 -79 44 41 -46 -97 -74 -39 -64 47 -16 -67 69 33 -72 86 -80 27 -9 -37 84 88 65 35 -3 -69 -43 -7 19 -51 -99 -71 -82 -20 -30 -8 0 -34 -41 10 -84 -16 23 83 -33 87 -9 -82 -49 90 -78 -77 -47 -54 78 -24 -44 -10 -6 -54 55 85 74 -34 99 -100 -22 -70 -96 -76 67 28 83 -55 45 -71 -68 -13 13 -39 -21 -49 44 13 -28 78 -9 -20 -66 4 -6 95 56 -61 41 11 90 7
|
||||
-75 28 -39 45 58 10 -79 -81 44 53 12 -43 46 14 32 -95 -83 -3 49 -55 41 41 -32 14 91 -62 71 -42 60 19 -83 73 -5 -63 80 38 54 53 -20 -55 -2 47 -54 -7 24 20 -49 84 6 54 -53 87 -23 -22 -64 -66 26 -11 -13 58 70 8 -29 72 64 58 -45 -76 43 -53 -32 41 69 -9 -78 52 -3 -81 12 -34 49 42 97 -33 -53 53 41 32 -70 -18 76 13 96 -10 -26 -19 -79 -81 -3 -76
|
||||
-73 7 -36 85 -13 -62 32 -81 9 71 -80 -43 21 100 90 89 43 -56 60 -22 -71 16 91 -24 -32 -34 30 -42 -7 -88 -35 58 95 -75 -18 -68 -64 -13 -24 66 65 66 -15 74 -51 -14 99 14 -33 -71 49 20 -28 -38 -45 47 22 10 -56 13 -25 59 -92 -62 -75 41 -89 -9 61 -95 -58 -91 -100 -68 -75 34 -70 -27 84 49 -18 -94 0 16 2 48 -12 37 -62 59 18 71 -46 95 60 51 -2 -99 -56 93
|
||||
1 -52 27 18 40 39 19 13 -19 14 -31 59 50 -51 -100 -33 -95 61 -62 39 -73 -37 62 50 -27 -42 -16 66 -15 51 -32 46 -85 -5 -90 13 62 76 -100 -79 58 71 66 -25 -9 52 -27 73 -26 23 57 -72 -71 -96 75 43 29 13 59 22 -46 60 94 91 -85 51 23 -20 54 -31 91 -53 12 -57 -84 74 -71 38 99 82 -64 -51 57 -87 -50 -71 -79 -49 54 -39 -84 -45 -89 96 88 -77 25 41 70 94
|
||||
0 20 84 48 0 13 13 34 -10 -88 22 35 -82 -80 38 62 -26 99 -43 84 -90 -13 37 46 3 -44 -86 -29 89 -8 59 49 -30 -34 72 0 59 21 90 -95 62 -69 -47 66 15 99 84 -5 -38 99 -48 -42 -83 -1 -9 -41 -30 30 -87 63 -37 -59 3 88 -82 53 -4 2 -42 -17 62 49 -39 -54 12 -18 83 -81 -29 7 57 20 -58 12 -31 31 5 19 10 90 50 88 59 -13 -94 51 49 63 73 96
|
||||
12 38 32 -7 -85 -5 -26 62 11 60 -39 61 100 73 2 -40 -12 51 -93 76 58 96 -88 17 -75 10 -16 43 -42 -16 -37 -75 31 -24 19 32 -15 69 91 -2 58 31 2 -75 -15 -59 -1 -13 31 93 58 9 -98 -20 45 -14 84 -17 22 99 95 -91 4 25 42 -10 -57 -68 -88 40 -55 43 78 20 55 -79 44 69 -61 82 -34 -30 56 9 -81 77 31 -2 -43 -96 72 -98 -71 80 59 -29 -60 92 -57 -36
|
||||
96 24 -68 91 -14 79 60 43 6 77 76 -60 -82 5 18 -27 92 56 64 -24 43 -31 -79 30 -79 75 66 99 26 24 -90 -61 43 -50 62 77 -57 -2 29 -78 88 -29 -38 -46 86 -74 -77 81 41 -36 -85 -95 33 -79 75 54 -38 37 69 -56 -87 -34 0 25 23 -37 13 -38 79 -7 -32 13 85 70 38 -27 30 18 -98 48 54 58 -39 -55 37 -40 66 89 -19 -92 19 -99 -57 38 -19 -33 18 96 0 -4
|
||||
-63 71 82 33 57 81 7 -92 -8 53 -93 42 -23 -56 -38 -35 89 -37 87 -15 19 -37 36 66 -17 -93 -19 -15 91 -34 -40 -44 6 -59 -17 -90 11 81 -48 97 -91 -80 87 24 94 -5 57 -67 77 90 14 78 -97 -5 17 95 -55 74 -2 -22 -76 56 35 -26 66 -85 -88 77 -14 -26 15 9 11 -48 -22 36 50 -11 -72 -69 69 62 28 -67 83 -69 54 -60 -31 -65 -32 53 -45 58 36 -67 -90 -66 10 -27
|
||||
-31 -91 -20 73 68 -5 -87 87 35 100 -32 -46 41 -69 1 -43 -72 11 -59 59 44 97 -10 29 46 84 87 -34 -27 48 -68 100 -6 -1 88 -22 15 73 -64 100 -38 -88 -93 96 29 -99 95 51 -49 35 29 -59 89 46 25 53 79 14 34 42 93 -33 29 22 96 -33 -34 -53 -67 46 -3 -64 68 98 -25 11 -24 -86 -88 84 4 73 -2 79 -51 -90 63 -51 18 -73 0 -3 10 -10 42 92 -9 -1 73 -38
|
||||
71 42 31 8 64 -34 -58 -23 87 -15 39 -7 79 -84 -16 -26 17 61 12 -25 -2 70 48 -41 76 83 5 49 95 -57 90 74 54 31 94 97 -79 -18 -20 10 -68 32 46 -49 19 89 33 65 -25 -48 -49 55 -79 29 21 -7 1 90 14 -84 82 27 -48 24 29 -70 58 -77 100 69 53 50 42 94 -2 44 -24 -30 84 -29 84 -57 -31 90 69 -77 -28 91 -67 76 90 -86 -58 61 12 74 -63 86 39 39
|
||||
0 50 -13 49 44 70 -57 -62 -88 6 -21 -23 -43 -59 46 81 78 -91 -9 16 -21 -73 52 -49 52 30 -20 38 52 -13 -92 -31 46 78 91 -77 14 -16 10 2 9 8 -74 -43 -74 6 -54 -44 -28 -48 92 -74 -47 -53 36 -43 -94 93 28 -90 -68 24 91 -4 -54 17 -68 -25 -76 -87 7 57 8 -27 10 -65 68 -94 96 53 61 81 -29 67 61 57 -29 -69 36 65 -10 -81 43 29 -43 73 56 73 71 -58
|
||||
40 51 -89 -32 76 -17 -17 -34 -67 66 -12 61 29 14 -51 -38 94 17 49 -63 86 -49 49 4 28 -22 9 -40 -2 -68 -80 -27 -25 40 39 -71 -84 -32 79 -81 73 49 -96 -35 46 43 -59 5 83 67 -43 80 48 85 -32 -79 -47 71 92 -7 -90 -26 47 -33 -6 94 70 -64 85 -99 92 -62 -23 44 -7 77 7 89 -99 -96 84 -19 -59 -71 -65 29 -23 47 28 -95 43 -17 -18 -86 -1 79 87 -41 49 50
|
||||
-30 -84 -19 8 33 72 -96 96 6 46 4 -23 38 -37 71 74 -15 77 -89 34 -76 -73 97 -50 -3 -87 -61 17 -38 31 -80 77 22 -43 -67 49 -12 -51 -45 -8 38 71 64 -62 50 89 55 90 16 -22 -42 -80 -73 -60 57 9 -87 29 -81 57 26 -95 8 43 -19 -38 -81 -61 -34 -68 -1 29 84 26 96 83 68 5 -98 47 -19 -85 -18 55 -18 89 -16 21 99 30 56 -90 -7 84 10 77 -73 2 -70 -15
|
||||
-13 91 -54 8 -60 -34 27 73 95 -48 -31 -93 -78 66 26 18 -10 -11 -65 -100 -98 68 33 -46 51 -5 35 29 -32 -87 41 64 -92 -12 90 0 3 60 53 -40 -9 60 -98 -32 -26 20 23 53 -55 -58 94 13 98 31 7 30 -30 -71 27 1 63 88 78 36 -54 4 -96 21 -42 98 -64 76 77 89 66 89 37 54 46 78 24 -66 68 -70 79 -13 61 52 30 -91 -22 61 60 36 -76 1 -94 40 -11 -2
|
||||
53 81 36 -69 -41 -50 75 12 75 -54 -13 78 -14 -72 -61 -13 -43 99 -15 88 -77 -40 98 -83 81 -90 -59 -43 -20 88 -16 50 -78 40 94 -61 59 32 31 -65 97 81 36 -60 70 -20 41 61 3 6 -24 -93 -33 -88 -56 -63 -27 -96 -62 -83 -92 94 91 -35 -57 -12 -7 -53 4 1 57 68 37 46 -12 -65 -80 53 23 22 -34 -97 75 -81 85 -72 12 74 77 -84 -85 -70 -49 21 78 -29 -59 -18 46 3
|
||||
-91 -2 83 -100 -5 39 -87 -6 -71 89 -20 60 5 4 73 -4 -3 26 -35 4 52 92 22 8 -63 -40 -91 68 -76 -74 -95 -73 -96 37 37 -91 88 -50 -73 30 -27 -97 -38 26 77 -14 -59 -29 -93 42 0 -66 -52 51 -75 -25 75 -30 -25 -27 -68 -58 79 6 -41 41 32 -49 -90 98 -68 70 -64 -97 -67 34 -100 -67 80 -21 77 -48 -85 13 26 12 -89 85 -89 75 42 -34 -28 24 31 97 88 94 -58 -64
|
||||
-68 -97 -59 -27 -37 -79 42 -85 -4 -26 1 -98 26 44 18 -99 -40 1 62 91 -97 -68 72 55 -44 55 36 73 55 -91 100 93 22 73 93 14 40 -2 52 73 78 59 23 37 -54 27 -70 -88 16 41 91 0 -18 17 -78 50 50 10 -62 17 92 18 71 24 -87 -98 42 84 11 57 45 86 -80 26 -33 66 67 52 65 3 55 -99 -62 59 51 5 13 93 40 -29 61 -7 15 -11 -6 100 67 -1 -75 -44
|
||||
94 -53 6 -99 29 -70 -24 -12 97 40 91 34 55 -34 -1 1 96 87 -12 50 9 25 56 -56 57 15 -81 -24 47 -53 49 40 88 39 11 -57 -27 43 -59 22 -90 90 -21 -91 -70 -4 69 -47 -88 -16 -36 -9 -81 49 -3 69 -91 -64 84 -54 97 32 35 93 61 78 7 -53 10 -75 -17 -10 -65 -67 78 -79 37 -55 2 -16 -65 -7 7 32 17 29 -77 -5 -66 -64 38 -84 90 -36 -28 -13 26 68 63 47
|
||||
25 -82 -9 -25 42 -83 9 59 36 -5 89 55 -28 -11 38 -95 88 -68 -42 -41 -93 -75 93 31 17 -17 -65 84 1 -33 -99 36 -2 63 -67 34 50 78 -51 10 4 -6 61 5 92 83 -41 -38 90 -6 -31 -72 81 31 -13 -14 -21 13 100 93 -66 22 39 -74 -23 44 -19 -96 -78 37 89 -10 42 -46 61 -58 100 49 10 79 36 62 -46 -8 86 -22 74 -30 31 47 81 -88 -1 69 -78 -94 84 -44 -35 90
|
||||
2 35 -42 45 -99 37 -2 -85 -56 29 -25 3 24 21 -13 -22 81 92 -57 -10 70 -44 16 -67 -99 -72 -14 54 90 -59 99 59 -53 -63 12 16 44 -57 36 16 22 38 38 -2 56 24 -51 96 25 -55 -12 16 18 70 18 -51 98 63 -26 -77 62 -35 -44 25 -70 -21 57 61 4 90 -77 86 -55 -29 -87 -6 -92 96 -25 -49 -92 1 23 46 -6 48 -35 -20 -9 68 -50 -70 -24 34 -54 27 -10 -56 -39 33
|
||||
-99 40 -29 -73 -63 3 -94 -80 -62 -78 -10 80 -54 54 -19 12 75 64 20 -10 9 -11 -93 -92 31 -11 -70 -29 34 90 13 60 -80 -88 86 -45 -74 56 -62 92 87 70 -1 26 8 7 -94 1 5 -46 -61 -94 80 15 -78 16 60 -80 0 33 -48 57 98 -15 87 81 90 -68 -42 -53 26 39 -64 -21 -67 20 -66 80 -5 -43 16 -4 61 37 18 -95 -74 -77 -60 -95 -35 73 37 46 -23 -41 -34 -60 -60 57
|
||||
-1 50 97 -70 -50 -95 -27 -79 -46 68 -89 10 -42 -53 -28 -50 -26 20 -94 88 36 -96 -40 -50 -89 9 88 -73 -63 87 28 1 -59 35 -14 -33 -17 100 75 8 82 -45 54 -100 -23 -88 45 -34 54 -53 22 -76 38 8 13 40 75 57 90 14 46 70 89 -17 -65 8 -89 90 -12 -6 86 -10 -95 -80 60 -90 -7 8 -37 -74 -4 -12 9 49 86 90 28 59 60 100 17 -97 -70 -23 -39 -11 -11 -71 -37 -24
|
||||
45 72 78 -2 12 -32 16 59 63 72 -85 52 -88 50 -91 35 94 6 79 -71 28 100 11 -2 62 6 -92 22 -46 -11 22 -13 3 71 1 -28 73 -21 -6 -38 -44 56 -69 -27 -96 -88 37 64 -36 -69 26 -91 -97 -77 93 -93 -19 26 -20 -72 -95 -97 8 -67 -71 -78 64 74 -57 -69 99 66 95 -30 -95 21 22 -4 -11 37 -89 75 16 -98 81 17 -82 41 35 90 -40 -10 11 95 31 84 4 -72 4 51
|
||||
9 86 91 -15 73 -64 12 -88 -51 -77 -93 100 -99 20 -84 28 -76 40 -46 -59 96 17 -22 57 75 -14 -2 92 82 -13 -50 85 -50 62 10 -7 59 -65 81 54 48 -54 40 -90 87 13 82 -76 -31 -46 60 -96 71 -99 16 67 56 61 70 7 -63 -5 0 81 68 -51 -24 68 13 73 6 -8 42 72 -60 -90 -89 -88 -12 -43 -85 3 26 -50 -67 -3 -59 -69 40 -3 26 80 -11 -11 1 99 -65 -14 84 -79
|
||||
65 88 56 65 -49 -20 -77 71 30 -64 91 -32 -56 88 -5 -67 -49 19 -54 32 85 -41 -52 -21 84 -83 -53 -62 -24 22 -42 0 -57 67 79 -53 96 69 71 40 -29 -73 -47 56 -15 67 -29 38 -18 46 -18 -34 53 -28 -39 53 16 16 85 88 -6 52 1 27 34 -34 47 12 90 -45 49 79 3 -49 -61 75 -89 -89 -34 -62 -13 -35 -68 69 63 -11 10 -72 33 -1 28 41 63 -62 84 74 99 -49 24 -41
|
||||
-45 -79 -35 -64 -7 -56 32 -90 34 -22 -26 72 14 71 -57 91 88 -61 42 10 87 -95 -44 -71 18 35 -73 13 23 -3 -41 78 96 75 72 74 22 3 -8 -94 89 -100 -76 -93 87 15 27 39 30 -90 -8 -2 3 -70 50 -96 -64 0 13 64 39 84 -100 -67 44 -24 -100 36 -45 34 -48 -22 -9 66 -56 -57 -63 95 92 -33 60 96 15 -5 7 -40 43 24 78 -21 3 -92 68 -46 -97 36 -37 10 9 -84
|
||||
56 -69 24 -13 -95 90 -82 -7 -44 89 93 -84 -47 27 -72 65 -33 -28 98 -99 -95 12 88 73 57 69 -9 77 95 -51 -42 -78 -42 20 78 98 -58 50 71 73 64 -72 -39 -13 10 99 59 38 -18 -81 -54 49 -36 -54 -53 85 -99 -69 0 -1 6 37 -56 11 -2 -28 67 15 98 -15 17 -48 84 20 42 17 -73 9 -36 85 -64 -42 -68 67 -46 26 -4 49 13 -21 -17 -51 -23 -12 -18 -46 31 9 88 -44
|
||||
75 -27 12 -48 -48 59 10 -72 20 -17 92 88 -4 -44 53 36 67 8 28 23 -1 92 93 32 69 -52 23 65 26 -62 51 28 63 -47 -82 -47 70 -73 -40 94 -28 -32 -48 19 -2 94 -26 60 2 -26 -91 43 28 -3 -50 -58 57 25 -42 85 -28 93 -46 -27 61 7 77 100 -43 34 -31 -26 68 -99 -59 28 -4 -23 43 -99 -69 -44 34 -12 -47 -22 -56 56 -13 99 16 -89 42 -12 84 -83 -56 -47 -48 9
|
||||
16 15 -29 -22 -98 -45 51 69 -71 -44 97 -27 -85 48 74 -49 -32 96 -82 -12 -39 14 10 -85 -30 26 -45 -69 94 -1 35 48 31 22 84 34 -41 40 -75 80 -9 -39 7 23 -48 100 -69 -78 49 -51 43 -65 12 68 90 -17 -40 -7 -20 -74 -3 -71 42 22 -85 4 10 -12 -60 100 81 81 -53 22 51 26 -41 26 40 -37 31 64 -32 70 85 62 -8 53 -99 -80 16 38 39 85 53 76 -27 92 -72 -72
|
||||
61 19 59 -56 -48 25 93 -46 -83 83 19 49 -41 -78 -69 25 94 55 76 -72 -25 68 -16 -93 82 0 17 -45 54 35 -48 -59 -7 -12 19 4 -13 59 41 -69 -72 57 69 -7 -79 -55 -66 -79 100 -6 -21 38 -10 -18 -2 34 89 -64 45 -13 9 1 -98 41 64 90 29 -40 11 -74 -25 -46 24 35 57 60 55 1 -43 -23 -13 48 -56 -88 41 -74 71 35 27 35 -18 31 20 -21 90 -88 74 -53 -26 55
|
||||
5 -93 -11 -35 35 28 8 -81 -68 44 -33 18 38 -3 -40 -7 40 -33 55 -34 85 -91 2 96 26 5 -19 13 -31 -74 -46 -86 -79 -61 14 -94 -32 47 39 83 -70 -51 77 -52 -37 68 -77 -87 -63 -44 -53 41 16 17 -10 -33 100 -8 36 24 -10 -8 -93 -96 0 91 -25 40 65 -69 38 -32 8 -80 42 -92 26 -79 42 -26 -86 -3 -77 -23 62 -22 -84 -97 67 14 49 95 84 97 16 5 88 50 -46 -4
|
||||
98 82 17 78 -96 97 68 23 89 53 13 39 69 -82 76 -83 94 -83 98 26 -42 -14 78 -39 -51 75 -68 -95 -50 -56 -98 87 -97 63 -29 -81 -15 71 -100 -30 -56 -87 82 -2 73 69 37 -76 -2 62 -36 91 -73 -20 -33 43 -80 13 79 29 16 83 -20 -91 -52 45 -62 -65 82 50 -78 98 0 -78 12 85 20 81 -33 52 -61 84 -77 49 -29 17 24 0 80 -39 -31 -62 62 -5 -63 -77 86 96 -10 -38
|
||||
-22 -2 58 -28 22 -34 94 9 -88 14 80 -26 -55 35 -81 -10 -93 -61 -53 -68 -26 -1 -92 -84 30 8 36 -65 54 -79 99 -11 -28 82 -26 21 51 79 -94 69 87 -8 30 22 -29 20 92 -11 -37 -3 -52 18 -20 -53 41 -37 34 97 43 92 -6 -42 72 94 43 97 79 -8 -55 80 -67 -34 54 -51 21 -64 38 -49 88 -46 -100 20 -71 56 -2 -74 -73 -7 -97 -75 9 4 58 -76 -61 -12 -99 -38 12 67
|
||||
41 -95 -21 84 76 94 94 11 -84 19 -49 -74 -76 34 -91 -100 13 -78 -21 40 -77 62 -41 24 -26 -57 -68 22 89 27 -23 -100 -58 -90 -10 79 71 -22 43 -87 91 -76 -35 93 94 -47 -92 -8 -62 51 60 60 -91 77 70 32 -70 26 80 -76 43 -14 89 -77 99 16 -17 1 87 52 98 95 -52 6 -19 83 -33 22 7 -54 -77 35 -55 -18 4 68 94 74 50 5 21 -34 13 -84 1 31 -80 38 0 -56
|
||||
-59 3 -84 87 42 -26 -49 16 -47 93 -5 41 64 36 -8 -70 55 -100 56 33 51 -65 79 -14 -65 -15 -98 90 35 56 78 -60 -63 -75 -92 -25 -15 21 -36 -11 14 -70 84 -59 17 74 46 -2 86 72 -96 -24 41 29 -4 -38 -25 80 -84 2 26 14 34 78 26 80 -19 -14 -51 15 -63 75 17 76 13 -27 16 -68 90 44 100 40 62 37 -13 -93 -73 25 33 -81 -89 -21 -55 -86 97 57 54 -29 28 79
|
||||
98 -51 -55 40 4 -99 -97 14 -13 -67 0 49 -63 -66 75 42 9 20 85 15 92 76 -85 -43 79 -18 41 -11 46 -48 -32 -43 98 57 -39 -64 36 51 -78 40 -59 16 -92 2 73 -46 22 -69 45 -50 89 -46 26 37 -72 -52 -88 19 -76 82 -87 -49 56 61 75 45 46 -3 -74 -84 39 21 43 -13 -5 -93 -23 48 45 66 50 54 31 -96 8 97 22 3 -23 61 -32 -15 -32 89 39 -95 55 -19 -3 21
|
||||
-21 98 -68 -64 43 -59 -91 -33 37 36 7 -43 42 -27 100 57 32 30 5 -10 -53 -79 100 96 -58 -31 43 63 95 -76 -62 -56 -62 3 -7 77 58 -21 -67 -80 -75 -94 15 76 -32 -6 37 -14 -83 -54 -96 77 -27 8 -72 -15 17 -75 89 -33 89 15 20 9 85 72 -26 6 71 -100 50 54 60 -39 -41 62 -39 -75 -61 73 -56 8 -10 9 -81 -38 -47 -94 2 21 -4 72 90 -69 90 -84 -41 10 -13 -26
|
||||
44 -70 15 -23 15 81 71 -61 -23 -85 -46 17 -32 -42 -94 -3 87 -83 -81 74 -15 -50 -61 -13 69 72 -49 6 -16 -31 37 18 -51 -61 -64 -23 60 -27 -96 60 -38 -32 -90 -28 94 47 -33 -24 -3 -89 -84 -56 -31 67 -87 96 -31 73 -11 71 -57 -42 -91 -84 -33 -39 -75 69 13 11 -16 96 -75 95 -75 -64 71 6 -66 69 85 -67 -7 -72 -19 34 54 91 44 -74 50 88 -74 -15 9 26 -60 81 -96 98
|
||||
-16 -15 -55 -29 -82 -32 -94 -80 63 82 84 -9 -80 -44 -34 -21 -73 -66 -17 90 50 77 73 -31 -58 58 11 61 -41 95 -70 70 -90 -14 5 -54 46 64 -48 -9 -71 33 19 -6 -24 39 93 -40 -15 26 40 86 -32 81 -7 -2 57 -47 -50 -52 63 -57 7 -73 26 35 96 40 98 -91 95 84 -11 91 -80 31 4 -92 -70 95 -22 35 -52 56 -88 -28 93 -32 44 -66 41 -32 -71 18 -49 -50 30 -87 85 19
|
||||
-17 82 -49 -59 74 -26 -77 -42 -37 58 -5 -73 -28 50 90 81 88 66 98 -59 -21 98 99 -19 -33 47 -81 96 88 -70 -3 -44 -13 -94 33 -64 -93 40 96 29 62 -55 100 11 -82 -53 -4 79 -80 -48 69 55 55 -39 -37 -2 -76 33 39 54 17 75 89 -76 -96 -68 95 13 -4 -57 44 92 64 45 -75 73 28 -69 -62 -64 0 -11 -23 23 -78 40 58 -38 -64 -44 21 71 31 100 -22 4 -69 -49 -98 59
|
||||
86 45 -25 48 -25 69 67 -16 83 53 46 56 -8 -53 -91 -36 -52 -97 -49 -27 95 -11 -32 -27 28 -95 45 27 -99 81 -79 84 -96 49 -55 90 74 91 70 -37 46 -61 58 -52 -94 -13 -28 -15 -8 -35 -91 -54 -4 36 45 77 59 -21 -9 -90 -29 79 -50 -29 3 2 -55 -60 -58 68 -16 99 16 75 92 -22 88 -8 73 8 -24 27 -19 -19 95 -79 19 -91 15 46 -16 -70 -20 13 97 -68 90 -13 75 -35
|
||||
23 -31 37 -45 55 39 -56 81 11 1 -9 -79 -56 7 31 -87 12 -88 -42 99 -21 -35 -5 -36 18 -89 39 -13 33 -64 23 -33 -69 -38 -33 -24 65 -60 -32 -47 18 64 26 -37 -78 79 -93 37 -31 -5 -99 -99 38 38 -2 15 -32 2 87 0 22 6 33 54 -87 -74 -61 59 65 72 96 84 80 -86 -39 -47 -7 96 2 -100 99 -72 93 -76 -10 35 60 -63 -16 29 53 17 20 -14 42 -39 92 56 11 37
|
||||
-27 -24 -21 95 62 78 98 69 -61 54 -29 85 49 52 -49 42 85 -90 -50 83 -35 -62 -51 -78 -8 -10 96 51 -34 -21 24 42 1 2 6 81 -48 100 43 44 -91 62 15 11 -83 60 -57 -73 -52 -59 35 88 81 32 27 -50 69 -33 -41 -63 87 13 56 21 -26 18 61 -20 25 -89 -11 -76 -41 53 56 47 -68 40 46 87 65 -44 -13 -43 -100 -39 100 87 -58 26 -28 34 15 -72 9 87 -65 3 33 56
|
||||
-11 52 -32 -59 -92 25 11 34 -66 -45 -96 22 29 31 -10 -36 76 3 70 -83 89 64 11 -21 -40 22 80 77 37 91 9 -92 -40 42 -25 -18 90 47 -42 -63 19 43 -19 62 32 65 53 92 49 -60 -94 -1 -70 97 19 64 69 -77 -45 -42 -82 45 -70 -57 -83 19 -59 42 47 76 16 70 -57 -1 -29 -60 45 39 21 71 -59 -53 13 78 21 28 54 97 86 75 28 -11 -89 -92 42 45 31 23 -63 -32
|
||||
2
testdata/performance/01_mm1.out
vendored
2
testdata/performance/01_mm1.out
vendored
@@ -1,2 +0,0 @@
|
||||
1151854256
|
||||
0
|
||||
89
testdata/performance/01_mm1.sy
vendored
89
testdata/performance/01_mm1.sy
vendored
@@ -1,89 +0,0 @@
|
||||
const int N = 1024;
|
||||
|
||||
void mm(int n, int A[][N], int B[][N], int C[][N]){
|
||||
int i, j, k;
|
||||
|
||||
i = 0; j = 0;
|
||||
while (i < n){
|
||||
j = 0;
|
||||
while (j < n){
|
||||
C[i][j] = 0;
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
i = 0; j = 0; k = 0;
|
||||
|
||||
while (k < n){
|
||||
i = 0;
|
||||
while (i < n){
|
||||
if (A[i][k] == 0){
|
||||
i = i + 1;
|
||||
continue;
|
||||
}
|
||||
j = 0;
|
||||
while (j < n){
|
||||
C[i][j] = C[i][j] + A[i][k] * B[k][j];
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
k = k + 1;
|
||||
}
|
||||
}
|
||||
|
||||
int A[N][N];
|
||||
int B[N][N];
|
||||
int C[N][N];
|
||||
|
||||
int main(){
|
||||
int n = getint();
|
||||
int i, j;
|
||||
|
||||
i = 0;
|
||||
j = 0;
|
||||
while (i < n){
|
||||
j = 0;
|
||||
while (j < n){
|
||||
A[i][j] = getint();
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
i = 0;
|
||||
j = 0;
|
||||
while (i < n){
|
||||
j = 0;
|
||||
while (j < n){
|
||||
B[i][j] = getint();
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
starttime();
|
||||
|
||||
i = 0;
|
||||
while (i < 5){
|
||||
mm(n, A, B, C);
|
||||
mm(n, A, C, B);
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
int ans = 0;
|
||||
i = 0;
|
||||
while (i < n){
|
||||
j = 0;
|
||||
while (j < n){
|
||||
ans = ans + B[i][j];
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
stoptime();
|
||||
putint(ans);
|
||||
putch(10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
301
testdata/performance/01_mm2.in
vendored
301
testdata/performance/01_mm2.in
vendored
@@ -1,301 +0,0 @@
|
||||
150
|
||||
372 -828 117 -590 -398 -195 662 -190 782 -836 803 -156 -637 -529 229 -966 -948 243 735 -579 209 -259 -685 -863 -551 -896 379 452 -945 995 772 804 -265 -248 -753 319 593 989 -552 -438 -962 542 -95 -869 -322 994 -935 -820 -989 358 517 -811 -107 -160 -240 -543 -220 -374 -584 252 -183 874 -64 -527 595 954 -348 -538 -550 752 -628 715 596 -731 -117 603 -387 -650 852 -128 797 777 -372 54 -293 -722 745 860 742 512 34 302 -576 -437 -624 709 -268 -492 809 -128 -669 -141 -891 -946 -464 -150 351 -642 340 -401 -45 28 626 552 780 827 -58 -500 761 -674 -913 990 174 828 -334 -505 286 -671 -577 -379 -182 528 -895 -532 -486 -270 -365 -95 -847 716 -372 -33 566 966 -696 515 210 -310 166 -454
|
||||
-951 334 -741 503 -513 50 732 -653 905 -560 95 -887 -50 -366 213 -247 690 -312 -888 -21 -472 -124 437 -127 -974 633 -159 -392 -339 -187 144 -60 754 330 804 -822 -960 958 -263 251 -694 457 821 373 291 -857 590 -869 -456 -530 -387 -65 -192 687 -763 125 -97 334 -732 210 625 344 -935 -329 -126 117 960 -872 -185 619 480 480 -9 693 668 -709 -461 45 567 -726 358 -858 693 269 -81 -878 -281 86 -527 -41 770 -357 -50 783 -386 -462 -960 535 395 -912 402 621 384 802 -480 145 -904 148 -925 677 188 461 199 -374 921 340 272 955 -702 -832 46 518 836 -897 -571 -53 500 812 96 -936 771 -53 -588 -329 166 910 631 684 -452 -894 -601 -336 219 -681 251 985 -639 -52 -640 -991
|
||||
-801 -955 930 67 -767 -334 787 -789 -25 -187 -547 -44 704 -719 -878 -688 -48 -185 -453 739 -659 -956 -114 839 706 -850 392 75 421 -585 597 689 540 -994 340 -663 -593 -862 614 -986 -17 -883 -61 -561 404 484 390 -774 916 -568 40 911 423 843 566 890 198 906 -296 -129 157 688 510 578 791 189 -80 -671 -836 443 748 865 -698 451 369 311 -596 243 -296 682 851 -28 -603 415 -664 -198 881 -637 988 266 957 687 804 -949 -350 69 -367 -974 -327 327 553 336 360 -700 -603 -762 343 -592 -465 -334 -177 212 -497 -878 131 -355 622 288 207 192 -318 605 -758 -752 378 -720 -8 -698 -836 2 225 555 -670 -993 22 -216 -972 -831 -964 -117 541 494 201 -532 512 -81 968 954 -34 238
|
||||
412 548 935 -171 983 377 92 -681 788 -302 725 731 -861 -168 -237 -794 400 494 -549 600 -475 297 -405 -793 -886 -553 403 997 817 434 -507 45 700 932 951 -801 -532 817 375 565 139 -82 869 -26 -719 -275 711 -9 -927 372 299 403 -742 893 289 -325 465 -611 472 171 -875 665 307 882 680 158 572 794 508 673 874 -1000 -474 -266 -11 -744 329 497 699 -156 -58 -940 986 852 915 779 -119 -748 867 -88 687 -552 -159 -75 -950 -731 -493 -895 -60 -431 -781 39 449 525 -838 -255 -808 -947 677 329 -514 -519 -331 356 -326 -906 911 -3 -249 -948 843 480 421 -546 -323 803 296 546 -468 -791 -996 -590 -584 -685 98 -467 912 620 -16 -854 -422 -534 473 621 788 419 994 646 -516 -614
|
||||
739 811 -624 869 -262 -986 -349 -110 783 653 -341 -686 -931 -303 555 -119 527 -334 257 -266 -195 113 -129 244 41 156 586 101 416 -292 161 -360 999 952 100 634 -300 -408 765 789 259 807 894 2 928 -188 -798 -799 -226 991 433 611 867 29 86 -179 -228 -363 -711 -581 -38 -920 210 444 -56 -346 266 -337 590 -581 129 427 577 -449 387 -876 -593 806 819 23 528 -278 -242 221 518 919 -895 871 -887 -764 -405 -178 -738 891 741 -64 -899 -493 -822 -13 559 -641 -718 303 -73 344 -709 318 -717 494 50 650 741 -684 -264 -18 -326 -599 582 -938 -282 585 -520 -991 745 734 407 254 490 669 -141 -899 301 611 858 123 927 83 -956 -377 415 919 103 -144 499 -988 704 357 -518 -830
|
||||
292 -957 -223 -233 540 -213 118 -486 13 407 653 947 747 50 -109 195 -576 -240 -744 701 83 551 -31 499 -8 828 763 291 981 -1000 -911 634 425 -475 556 -888 -257 469 -107 990 838 -172 -792 490 792 874 31 -219 941 397 -137 71 162 -13 93 282 -800 213 -102 862 -898 -811 -863 -303 -524 -556 301 -683 745 988 -571 -344 700 -475 664 78 460 889 -330 605 146 841 826 -853 876 -829 -886 882 746 -244 -14 -12 179 -435 326 686 578 -486 215 367 661 -329 818 -817 -289 -912 121 2 209 -94 17 804 -817 -453 857 -968 271 325 770 -99 -282 955 996 972 -568 467 -305 940 2 44 -808 -230 -253 504 11 -23 -939 651 473 480 -1000 -610 -373 -500 575 824 860 -557 778 182
|
||||
-941 -160 873 506 -463 442 -475 953 -714 65 640 -547 -496 -187 -141 879 411 -801 460 -223 605 715 13 -926 -258 -425 -99 -377 891 371 -86 407 426 836 -464 402 -760 859 -624 915 634 698 -121 5 459 598 -578 822 -114 -550 35 231 680 -123 -659 498 128 -556 441 -64 -403 6 412 724 865 -742 134 100 -613 -12 510 520 -442 -280 643 793 -369 -805 983 999 683 560 616 -182 433 -823 -768 831 805 -769 -162 -179 474 415 -514 -871 514 665 -128 431 904 -520 -874 -171 -111 717 272 -591 512 793 -563 304 465 -180 131 -96 62 214 381 -440 385 204 -736 323 -127 384 632 -157 820 526 236 429 -980 -778 -307 807 -772 849 -328 283 683 -502 -314 -750 -684 -212 -125 198 726 213
|
||||
293 -926 542 -134 -205 -292 -356 513 920 -508 835 241 -407 -181 -241 -529 239 -792 823 194 -175 495 -99 618 724 -268 288 -231 -362 266 -684 368 620 995 -472 -333 -113 -600 -138 831 350 -488 -826 -204 156 785 -948 -578 -702 467 -47 423 -357 -723 931 965 -900 -361 580 467 986 -980 -716 357 975 467 -550 745 -19 990 814 -861 309 603 -74 395 632 -44 369 -935 449 -635 819 -233 642 -198 -561 601 831 -925 286 687 162 456 207 785 -680 -785 892 -694 976 411 -364 -83 726 -188 683 -117 -633 -569 -939 303 -770 -321 458 149 54 -711 -893 -270 -687 520 946 -218 -628 -607 -480 702 -273 -615 86 -287 -799 270 -971 -336 550 -985 -835 520 -920 429 860 668 79 -579 636 -393 -363 696
|
||||
573 -63 -92 653 -354 -980 -622 298 413 -732 -511 -708 -333 -390 883 -576 -71 -618 584 133 -5 -77 334 -906 621 -976 935 991 979 519 990 -466 -382 -919 -809 791 -730 78 815 -765 -885 138 -179 870 -47 -803 -883 -229 -83 -776 219 744 381 -970 -176 -554 962 -701 968 627 645 -807 -361 297 708 -172 961 54 -874 459 -715 472 -828 383 -581 331 -594 232 196 794 -441 -44 -620 173 928 -640 -952 -582 249 -311 784 392 -484 304 -706 517 -471 848 852 305 -971 -678 -253 -888 -340 -596 -187 -41 -373 -9 -885 -109 -387 -165 33 -334 -219 -969 -642 314 -157 849 31 788 -118 -24 22 -509 654 -949 78 209 425 491 -366 -293 -283 -603 653 -623 -271 -171 -512 -644 252 914 224 -92 -250 861
|
||||
-607 -543 242 -137 -389 -510 -752 834 510 189 564 597 98 -723 351 995 -129 -474 413 -937 -42 300 894 577 608 176 -482 776 -575 -134 462 -472 -595 -35 639 89 -328 103 -367 475 -553 -620 -54 109 -687 253 -212 249 525 -121 799 693 773 707 -183 139 580 -304 308 -842 -630 -921 -779 412 -419 -241 -341 914 479 -783 -474 -586 -60 122 516 -909 -806 -504 -704 -712 154 -3 -264 964 398 34 828 -560 196 216 213 939 473 275 -548 -534 162 -713 -543 588 -717 934 -924 -463 -260 96 -433 118 -537 -926 -685 -485 -498 -338 -414 -744 -151 -294 888 -236 997 -278 733 554 -429 -955 -123 -607 793 190 679 737 -318 433 561 -710 -805 95 258 -58 524 -511 -279 -804 -821 -43 383 -810 -273 20
|
||||
-835 -185 807 -950 117 -907 117 -847 671 930 -822 -905 -624 978 -200 397 -565 991 328 340 -700 540 -126 -208 10 -835 313 320 935 632 93 -896 522 -187 -286 -304 753 -517 496 -751 -162 234 571 -377 -428 61 548 -849 893 359 -489 225 216 118 406 935 -517 -37 -972 513 579 -269 161 -401 -940 429 495 -931 -577 111 -39 -985 -914 700 43 852 -323 -964 -507 837 574 -660 -33 -345 812 -852 -672 -671 -603 414 376 -146 -577 -308 -552 439 953 -598 306 -417 501 -503 -688 83 412 -310 -536 -276 -562 -661 -367 12 546 731 60 869 -989 722 474 575 188 420 -324 -215 450 -129 -166 158 319 384 -63 -170 -823 -294 -38 -387 610 912 137 856 -877 -805 136 -676 715 44 -598 377 876 437
|
||||
-106 294 413 -148 -512 -71 -254 754 -560 904 -354 -122 -912 -131 701 -820 -377 244 804 -84 600 238 -73 -885 564 -708 -297 -773 852 328 -123 127 220 -878 293 979 462 102 -640 -187 -413 417 -41 -263 -393 -766 -208 190 -405 990 789 692 939 780 -347 458 946 319 752 -320 350 149 60 -8 242 139 -955 130 -357 645 -993 -232 -454 -234 -325 402 849 465 -808 -207 -554 985 929 -753 -312 352 158 109 320 -108 -775 -527 -708 -168 -875 85 576 -554 53 606 504 96 81 -26 765 730 724 -202 -384 527 208 -480 -606 -56 306 -675 -143 -995 488 -513 462 -906 -547 579 108 -60 899 998 484 -509 998 -288 -920 920 253 21 655 105 -412 -882 801 -835 -672 -131 765 -811 -990 996 -966 499
|
||||
128 -577 305 283 477 -416 177 -823 -437 928 -818 760 981 539 880 738 467 -376 345 682 613 221 -250 993 46 20 108 -41 896 -776 131 699 -898 917 -642 -820 754 909 356 769 -115 157 319 -306 -88 915 -418 712 -982 253 -348 21 -514 -274 984 -367 -722 195 419 -413 -399 -604 521 -454 -580 59 -895 711 -611 779 603 796 678 418 27 -504 -717 -900 114 -386 -298 793 150 908 617 755 947 -139 364 777 -196 229 684 167 588 -292 -408 -570 838 -769 56 43 752 -968 -124 -948 508 -625 -851 619 -147 -273 806 326 -464 -452 124 -243 -252 -855 -312 -410 36 166 -982 515 -228 -21 98 200 472 113 776 -995 897 -497 442 -265 -25 -404 329 879 -827 -163 -256 432 570 -206 500 409
|
||||
329 -275 462 1 -927 -476 -425 -62 -101 -657 552 14 441 -193 370 -288 929 439 194 -559 -524 -523 795 39 990 -263 -931 -214 -114 -883 286 891 241 112 413 834 -114 131 486 366 -476 -713 -834 927 -168 -898 -239 948 971 -528 -145 77 389 -115 497 6 -357 826 -703 787 -35 -561 -871 39 -275 930 -48 918 -395 219 -752 -207 -919 123 253 -303 -985 832 -59 317 311 -509 449 804 351 -850 -297 -989 936 693 -981 -580 -838 996 710 223 -801 -778 -825 -172 -831 -407 -613 -295 103 176 196 -946 414 87 -222 -276 193 672 -375 311 603 506 -842 666 196 -680 256 -860 346 -805 790 -269 -830 -300 229 -67 -432 -625 646 938 124 -290 877 -230 74 -987 836 -5 -986 -625 233 -757 296 277
|
||||
806 -963 672 489 838 -74 492 -790 -301 822 154 -651 972 -857 -225 97 -125 992 106 844 946 -756 235 -992 499 408 -705 104 -670 793 143 -839 685 -89 -546 915 978 586 -762 142 -245 963 132 463 922 -633 872 -243 410 449 715 799 -294 631 -626 -547 52 -40 -528 -657 69 45 -451 894 -217 -919 704 939 -468 -839 35 -229 -141 -591 832 -107 -872 -288 654 968 656 -643 365 -22 -155 340 491 -392 -787 296 419 -165 -771 263 -104 797 248 -711 409 806 -349 -122 -690 -422 500 -79 -503 -976 -442 -919 -179 558 -78 265 -17 891 -469 627 -728 -510 -931 991 652 -337 -118 -495 -495 -635 -865 -304 -847 -620 239 -487 -880 -315 119 541 116 -748 -91 -671 743 -991 12 -810 117 99 727 991
|
||||
-483 -406 -112 985 -163 -955 -826 116 236 75 698 198 773 382 683 475 80 -139 -453 936 -990 -177 -334 697 -101 -257 12 864 -683 -684 614 -573 -98 -163 -575 858 -177 -396 -539 -791 678 22 -65 822 289 300 -964 633 -511 -674 -518 -367 191 626 30 730 -62 -680 -521 -955 416 764 314 369 -315 595 -356 384 -607 -834 240 224 -216 -652 -703 -488 -259 -617 -769 -438 -114 -295 572 -458 535 379 724 203 -23 -610 -973 -354 546 695 830 122 -794 983 534 66 454 908 -910 -366 716 102 146 -37 829 -623 -396 -469 342 -864 -429 -475 719 -259 -478 -965 714 -978 -286 -515 -19 836 785 -706 -437 257 -504 897 -721 -373 159 -291 -448 367 -302 -984 380 -436 -959 -597 737 -122 580 -584 -950 520
|
||||
-218 351 -861 597 681 -775 797 518 542 663 773 -466 -529 -741 -986 -48 -980 -834 -133 -498 -714 -969 636 268 583 595 772 266 563 231 -693 -423 209 862 384 -158 -733 -800 -515 438 -430 727 97 -392 897 362 955 -855 -930 60 653 -283 356 -401 107 596 797 925 -122 -602 924 -684 -504 -833 587 -310 -491 -996 -453 -827 527 -63 -157 -784 -566 -800 616 -138 -469 -212 740 -825 170 -237 489 400 -82 257 -337 -511 960 551 203 -86 -184 202 -403 -723 477 580 -137 -941 -327 -217 -727 172 -543 -572 198 948 764 -42 796 84 307 -327 -606 -526 207 534 -471 -791 483 760 -337 487 -187 -610 339 26 -831 131 51 -142 -814 -408 -685 -863 803 -87 -586 -720 -996 -84 -157 482 693 -94 -621 -809
|
||||
-477 212 648 -477 356 716 267 -851 561 -839 -892 210 -740 995 -971 735 -139 290 684 72 -526 229 421 -785 -72 -692 403 -554 -351 27 693 -7 213 551 941 386 497 597 405 338 -608 -48 -387 -469 -815 194 665 272 -413 493 607 179 -213 -662 486 576 -666 105 -588 -476 -896 185 -836 -593 639 -725 -866 210 16 893 -49 455 143 -800 -607 -461 698 -225 801 -332 717 -59 -290 851 -955 42 393 -630 -232 -727 825 -703 671 -62 546 652 -710 99 509 -909 -456 748 -165 949 784 -362 975 -843 691 -695 -538 -149 -450 -292 -250 -996 -456 915 -557 -599 171 380 -61 -694 -419 -468 53 110 -864 621 374 -980 -867 740 -212 -560 73 -576 452 52 -146 -763 -585 986 163 970 73 -518 950 653
|
||||
346 -128 -308 300 -824 -552 -718 54 350 -250 -822 380 -696 538 390 -570 -635 626 800 -190 -189 1 -907 -699 900 -324 -820 110 -893 -463 842 226 494 -284 800 -629 -879 -342 753 -735 551 235 -997 -694 -883 -25 296 -965 59 -133 -135 -781 721 781 603 230 -835 -859 70 129 841 10 -560 945 362 700 211 -122 -72 864 -121 776 380 92 705 -897 396 996 464 88 -402 -934 -874 -739 -550 413 30 248 -667 185 237 590 527 533 132 162 -924 -9 836 -275 355 -1000 611 -829 776 -389 157 -288 -985 611 216 -670 95 864 -626 804 945 94 -556 225 -418 -919 184 -292 245 56 612 -104 483 -225 820 444 174 306 363 477 746 -14 68 188 -102 -384 -710 760 -428 -326 665 -482 -680 -334
|
||||
172 491 -916 674 720 5 -741 605 -973 250 -773 20 -817 -559 225 -436 683 526 -917 -986 -327 27 75 -788 719 -327 619 939 177 -733 -575 -148 -927 -222 744 -782 -841 -804 -696 51 -236 -499 942 94 47 -930 658 -891 196 -947 -163 -647 503 576 280 968 732 283 -501 232 -959 533 88 -753 -174 -728 481 -161 -518 356 467 443 808 -148 -223 300 -314 -306 -45 -401 -292 -992 -367 859 -836 -389 -982 -244 -744 -287 -357 808 262 -512 -496 260 642 15 444 25 857 807 -261 -965 430 944 -833 36 155 -80 115 -490 805 582 -828 -435 -622 -861 -781 -139 -879 542 731 -69 470 560 -783 -95 -409 417 541 -429 524 168 -371 -830 -494 -33 -17 -403 425 -403 -338 246 310 -936 446 451 -420 -190
|
||||
-961 933 555 333 -256 -626 275 -798 -748 -303 339 492 832 -397 -41 -896 460 -898 23 -181 -304 -32 445 -521 145 201 -580 580 959 776 -715 286 -743 -811 878 593 -453 -33 103 -751 466 921 -113 -293 869 772 -948 -213 210 880 181 775 -798 -940 -311 195 821 -601 73 367 443 -284 -61 -52 -832 -6 85 495 -216 -214 -293 239 -865 305 -538 -647 654 -902 -424 150 -258 320 -587 -276 973 73 823 958 -268 -317 522 502 578 -37 966 844 30 -592 -783 943 -424 322 952 507 344 16 890 -613 -971 -965 -615 826 -166 -28 -10 779 -231 -480 -89 -555 -918 -21 -227 -787 317 -85 377 -394 -667 -164 -301 -353 -747 -828 15 -173 930 975 -213 299 844 433 38 -518 597 -978 -712 -912 914 -155
|
||||
945 -991 139 -290 22 -164 989 444 -975 -581 370 -307 678 -808 -994 -574 -597 -376 -363 -191 170 -905 -713 -437 251 196 -970 -888 -872 -112 369 982 474 -919 209 -899 -403 -173 806 -607 -243 405 444 548 349 -622 -285 -97 -577 -279 906 -930 -275 49 -823 859 -263 705 -600 -324 349 -766 462 62 -784 293 492 389 -263 -218 -87 428 -511 347 -763 592 -259 344 -745 673 229 451 857 -519 -879 -835 341 186 358 -61 -801 367 381 -202 763 -990 481 502 617 468 -348 399 296 173 -167 970 55 579 113 434 -441 -752 136 56 120 -754 -1000 -657 45 46 -608 107 -765 -201 531 897 -156 660 270 551 -208 -175 -109 322 641 186 -824 -41 -234 165 -4 -812 741 -242 -877 -272 186 550 -315 -741
|
||||
287 -118 136 -603 -686 -501 491 -594 -292 -696 -348 -935 508 589 -764 28 -757 -649 260 -535 -472 -491 412 -259 -459 490 257 884 -13 463 -383 415 700 -436 -742 -435 -879 -575 -807 -245 -770 -545 276 360 440 595 -101 -408 -722 -664 328 -608 572 -326 -937 -112 -370 985 -295 -282 513 -318 -333 -196 -158 352 -706 -210 -296 937 891 -475 -352 988 -298 263 589 334 -785 847 -383 639 918 71 -328 866 171 143 92 942 599 -537 883 -359 -828 -154 455 354 219 207 593 -524 988 385 -14 -232 -721 -408 855 -91 -326 -716 719 -383 -605 -553 -841 856 -401 952 771 -304 -264 451 -598 135 549 313 -593 677 340 331 537 -136 859 -59 -219 -418 449 -82 -178 880 738 -76 720 886 -75 -834 -513 928
|
||||
933 403 915 -491 172 692 588 -246 -623 -803 -543 -943 168 230 -348 772 89 -934 330 -651 -556 -945 314 463 -581 -220 995 -179 -183 -479 -94 -760 631 573 385 969 -159 292 -157 271 790 936 -339 818 -898 -120 -678 403 -921 333 -532 387 536 584 -314 -656 989 189 75 775 669 826 -962 -812 549 -763 -636 355 125 503 -787 840 -943 867 773 898 882 421 932 933 -777 551 -138 -205 -478 777 -416 750 -425 -504 -543 396 -361 676 -875 -477 -151 -619 961 19 942 98 -957 -846 234 952 -650 -906 -344 -318 85 -754 121 -654 270 -772 524 493 -233 -659 803 -914 -911 827 204 -158 -530 439 630 -285 -131 262 671 331 -479 887 528 -757 -113 -313 89 432 822 423 307 -838 617 499 -682 366
|
||||
-850 86 86 987 108 -641 140 -428 -269 890 -654 918 -677 679 -79 -896 385 76 -854 -714 -381 657 -156 -941 543 -225 -166 721 696 -737 -848 -510 650 -38 -677 -723 742 775 -478 -111 522 -51 -495 -190 -486 9 95 35 781 -177 107 -716 -961 506 660 784 410 -823 -323 -751 627 982 -815 739 -256 -68 -383 752 -5 -449 -979 -316 -177 -212 -861 -62 -767 -14 -894 594 -191 10 887 -962 641 512 -50 852 -999 871 -700 438 701 -796 -201 -749 155 734 -408 -775 484 663 398 -141 -23 155 -807 -440 101 162 342 -138 -573 11 173 594 164 454 -665 -208 935 14 659 -925 -389 -137 -550 475 401 872 226 -916 -90 -481 -659 9 -160 464 958 -446 -98 -385 696 167 -523 216 403 500 300 707
|
||||
-491 413 -977 -512 -207 104 687 653 -262 776 496 -53 850 -868 907 -412 -661 381 873 -365 113 38 799 -247 246 -953 373 337 -677 -908 23 574 40 -990 512 -73 375 942 -249 36 361 961 -468 488 -877 390 273 -222 -557 917 0 542 -777 652 -412 -270 429 168 776 -941 402 -542 130 763 -700 835 636 -651 325 909 725 -986 -591 757 517 -961 -262 -766 261 415 -163 886 462 -368 250 -863 -666 956 -784 948 934 296 -408 265 -412 -716 -821 802 -399 585 340 -267 782 247 -92 -709 -722 219 944 708 -291 -178 -397 333 -382 480 876 845 551 176 -524 662 -812 -418 402 440 535 -164 473 -85 705 841 -163 -736 -582 983 -855 -274 -43 -281 11 -500 977 753 -671 -842 609 -262 901 -263
|
||||
-199 -16 -994 394 -219 -793 -435 494 347 -549 612 994 -309 -542 -920 623 -197 49 261 -424 -818 -229 -483 734 601 -198 46 734 506 -237 103 739 -719 224 514 980 101 52 -360 -567 103 385 -102 503 285 506 -263 829 -678 -50 -990 501 661 642 -133 321 942 237 975 407 346 -409 -913 861 -61 -356 178 414 -346 -921 -481 850 790 895 923 -551 854 -841 -39 -713 -369 415 -166 837 -262 642 590 -884 268 392 857 282 -146 -977 -914 80 -736 -720 940 697 -215 523 -640 529 487 -429 203 839 208 539 -565 -975 -515 -190 564 -396 -308 -46 -611 852 153 -724 -52 564 -612 455 -896 544 82 754 -141 -913 928 585 -960 707 -124 -748 -279 445 820 421 -422 524 178 -589 -573 279 -42 549
|
||||
-232 -828 776 405 615 -137 -108 -521 -891 104 -210 199 -315 -918 -900 -168 -701 -193 -80 100 127 -706 935 -122 -163 899 -987 -365 105 -780 516 -345 -952 872 942 -899 -883 -814 330 -568 -998 272 943 219 814 549 245 -756 905 -86 -424 793 415 -98 -191 588 -932 -885 117 590 809 15 120 -544 -100 612 -194 524 -267 -391 118 815 352 702 651 -990 -938 907 555 561 227 664 -792 -569 925 34 -432 51 -221 -999 -196 -404 -62 -848 166 -456 910 -577 523 301 -17 948 475 -711 416 424 200 823 447 458 666 -522 234 498 467 823 26 246 -409 -425 -388 504 -630 -82 103 481 460 618 34 233 -772 485 381 -418 -152 -568 324 -935 816 -312 -824 -381 -439 230 610 -796 -387 974 -869 40
|
||||
-864 -918 874 -883 365 -744 -805 188 -411 619 949 -458 393 344 605 302 -648 996 682 6 -962 -288 -944 929 771 -121 -148 -963 -446 783 513 -172 -357 -663 329 -682 88 490 -738 730 -260 -170 -715 408 742 -31 -603 -933 -818 -861 856 -94 -929 -789 914 -31 -193 445 865 457 -521 282 -691 99 953 -227 -733 175 23 -130 554 888 -983 -56 77 425 -172 -448 -718 -214 -170 -838 636 806 711 -580 -285 428 -335 17 153 509 -786 -193 918 944 307 676 971 -839 604 -879 822 891 -598 -922 882 -197 115 -450 945 -225 972 -220 -465 -29 925 -950 -727 -137 -879 109 -360 87 -810 -542 -228 130 -705 -460 641 -62 -290 74 -663 -763 -684 999 579 984 -469 -360 -58 118 -690 415 -985 -733 -282 -748
|
||||
-56 131 -219 183 171 757 -541 -72 977 186 -449 -609 281 -689 -191 -643 945 -516 -553 74 -692 -818 -911 -388 -365 159 -398 112 -938 -395 431 -415 -47 231 540 379 -191 600 -945 711 135 517 -913 789 -550 126 752 887 -354 584 -456 -878 948 66 -56 -531 968 -117 282 -479 170 -940 585 -304 -652 -428 -445 372 -174 379 688 -474 -542 277 854 756 399 125 -187 -731 -345 -443 417 -256 -774 -850 -766 825 -96 -800 493 826 155 -17 -526 -25 -636 677 948 -650 -617 933 -945 450 -249 -220 -781 149 -125 117 -205 -23 206 884 693 -945 -403 321 -83 -963 324 -737 -444 164 -938 243 -425 313 -155 756 -133 -548 472 -117 -111 -653 -895 309 -746 249 -374 795 196 185 -664 -881 170 -684 -343 -939
|
||||
-787 -939 496 477 462 -916 810 748 944 -602 -623 -170 203 -230 353 597 780 74 904 975 12 -936 -572 -724 619 -927 -504 825 238 975 -691 -501 768 -172 768 316 -102 793 -198 -869 921 -162 980 907 -488 152 -863 635 -142 -586 291 -203 -797 124 10 -607 127 -911 -224 -140 707 -876 282 161 984 -287 351 752 -779 -683 -473 -416 709 -212 -129 -16 653 -278 810 -165 -997 -175 22 -27 373 561 429 683 251 -978 -785 376 -442 -166 -812 -499 -633 82 -759 -945 -381 219 182 -227 -724 671 -988 -105 76 480 233 206 531 -406 -147 -297 -301 -976 399 962 -773 32 -571 -816 959 12 -441 -452 -492 606 -232 126 557 -969 -860 -931 -453 887 745 -314 881 255 384 154 877 935 -322 427 -787 -465
|
||||
471 -676 -649 823 204 -134 -43 -508 -757 838 521 -659 -463 -526 -883 -952 -76 170 715 -639 411 557 790 -480 -173 612 -994 -629 -134 407 582 259 -58 433 220 -903 405 -618 109 532 -502 -780 -509 -105 -794 -488 787 885 673 -29 -19 -500 193 -131 -814 -291 -49 752 178 -948 274 -434 26 580 227 -883 78 304 -309 -438 569 -504 867 83 8 -121 -614 -591 -175 643 275 -273 74 599 -682 339 -560 861 576 -85 555 -105 -62 -988 496 -614 -928 -119 -189 -845 -382 143 374 -35 -454 884 575 641 88 575 954 -863 -607 332 492 -119 -896 249 -168 -354 -754 813 733 -632 369 116 156 -588 425 -21 257 -9 -93 945 921 976 430 -408 -106 29 -178 178 201 36 -267 -498 -353 412 -166 29
|
||||
-704 387 -761 -114 -771 330 -70 227 -214 284 -670 -918 378 -871 736 279 56 734 -139 -263 -507 292 -893 603 660 490 -876 8 -837 329 -467 -905 -456 480 -452 450 -528 231 -363 68 804 905 244 -818 -521 -248 255 -347 -500 578 -260 558 -398 -759 -184 627 954 -92 838 -352 -107 266 115 -201 525 187 917 -47 979 -82 455 -768 999 -226 -200 234 414 -465 610 537 -972 892 -321 215 908 833 -965 -379 -716 -100 700 -273 892 -29 308 108 -554 -190 108 -763 -97 544 -68 648 -603 843 -372 -477 547 694 -748 -581 346 -490 477 -827 691 -909 -36 564 716 124 -94 -464 -405 998 -561 505 365 -444 142 -694 -774 -222 -516 721 637 523 -185 991 530 -593 428 -758 -790 992 525 934 817 -188
|
||||
205 -874 331 279 -623 -262 -836 -115 -581 195 883 607 162 -117 275 -408 -165 -380 121 -765 -498 514 780 -471 194 178 -436 -577 415 -651 -557 408 -373 -99 945 570 -386 -67 -325 783 882 472 704 -396 521 16 973 887 -982 -454 150 -674 -642 311 374 -226 807 -435 -797 -637 -29 -568 -700 58 -479 -203 485 -493 -506 837 857 -133 -33 11 -944 27 -574 -124 -218 911 996 -655 477 158 199 318 -717 256 -107 126 58 -592 -746 574 223 -850 447 -421 155 274 -173 196 -826 362 -219 638 -646 261 183 47 -883 -105 505 846 -990 751 -938 576 673 10 47 -429 -966 236 135 -50 -37 -351 86 -760 54 902 536 -440 545 -897 824 942 980 -882 535 -673 -250 411 315 -9 532 309 201 -869
|
||||
-653 -947 859 -378 867 -588 -139 426 -82 -292 764 -712 -617 909 -715 -80 212 709 8 -908 61 730 -148 63 480 139 -206 -281 411 -97 933 742 -306 361 -672 -126 808 932 850 -930 480 -867 68 139 -660 -136 688 131 -620 625 551 -389 121 -946 601 -745 -982 -650 -951 103 -914 -814 -739 366 553 413 604 71 -603 982 168 -461 794 719 342 0 707 584 762 -693 -607 479 793 22 -728 -669 -61 318 -832 -12 483 301 883 -775 693 -278 497 68 -457 654 -978 -600 933 775 -978 343 -771 28 9 -93 374 637 502 323 -344 -79 -438 -188 73 422 -100 65 -728 -321 -638 -355 76 35 205 193 358 546 744 -91 493 -524 120 -381 -185 -84 114 -123 -733 -331 -615 125 -3 -40 -440 61
|
||||
-867 945 267 -19 -518 611 -934 -825 9 -250 97 -58 533 428 425 644 507 122 -785 -380 -443 -442 774 -254 0 -980 572 -60 674 -215 105 514 262 482 963 33 -20 -392 -759 661 840 841 316 866 235 373 395 751 -114 -723 358 -300 620 -818 -814 440 -77 -216 220 451 -3 280 -286 -499 -322 324 20 663 -325 -534 -658 -394 -747 -63 -870 785 668 -934 403 35 730 934 -674 -580 -749 -808 490 -972 986 239 -19 661 -833 576 878 675 744 711 738 -855 -507 -413 412 -194 512 974 139 127 270 -569 -835 361 -490 846 -102 -311 -907 630 933 375 -586 133 40 40 837 187 -609 -847 -809 -196 455 365 -408 215 927 125 688 -434 287 24 896 443 763 696 652 383 677 647 -992 -147
|
||||
367 486 795 371 -811 -93 714 819 -600 386 577 954 284 647 480 -318 16 936 -343 -864 -408 951 66 -396 773 969 -604 -672 -740 -249 -78 971 -691 565 105 -466 -489 -374 361 936 -59 384 93 694 531 -198 159 196 163 396 -894 -746 426 -214 -133 -467 603 -615 25 -233 665 890 -10 804 638 438 -768 83 -99 363 867 -860 -110 714 159 287 365 447 -769 -793 -202 96 -127 871 905 851 -840 -414 968 -694 355 -242 803 519 992 -980 510 491 -327 623 374 160 -448 -934 -143 204 639 -297 -960 -339 -521 -19 389 169 -995 -69 646 -122 147 -644 -128 -505 713 -935 741 98 -200 530 803 -832 66 -429 639 -996 968 -444 -772 775 -922 933 -823 -291 409 -934 -349 -121 196 -272 -768 177
|
||||
577 468 387 -965 724 216 -413 772 -716 -922 148 -908 494 266 -882 -677 988 -494 -404 335 -201 81 -109 -489 -266 311 -41 -825 266 -644 544 -662 668 186 -793 330 -87 222 -762 -42 513 287 -537 -797 688 -174 399 9 83 -224 -594 -881 936 -595 -321 294 574 -598 166 -808 -253 202 -509 873 -2 715 -468 242 122 -48 -999 1 -571 716 90 -126 -689 438 -719 597 72 -284 848 -79 -701 897 -658 817 963 -291 513 -599 875 -253 -753 247 55 -229 303 435 -910 2 837 -138 -111 -770 466 233 278 916 -604 85 -508 -841 -532 -336 -88 109 -615 848 597 -661 -168 96 991 671 -620 -786 423 164 -139 -120 142 -320 668 327 546 593 523 -468 670 523 -270 -383 -58 -759 651 -236 495 -329
|
||||
945 -222 923 -390 -757 -244 335 -189 909 -669 569 67 591 -968 720 511 994 -372 300 859 -490 157 -238 734 494 -825 20 -475 57 -999 576 -984 10 637 -717 -805 907 -521 175 369 489 -686 76 -971 -355 984 951 -990 701 -536 -293 646 941 393 633 867 -985 -201 475 457 438 -934 843 753 83 114 77 -138 367 -547 453 687 16 -762 -888 -689 -581 274 -762 310 820 -98 -721 6 -121 147 577 -128 -860 -438 -53 374 -962 278 303 -92 341 -929 -596 666 -687 -149 527 -232 -454 567 871 693 448 767 -981 539 -113 920 904 -769 79 700 -779 722 -556 -756 516 996 855 494 -94 611 -383 -416 883 -724 85 -587 701 627 265 567 716 -911 -630 -500 -381 -398 -427 -281 -612 -38 987 -797
|
||||
91 594 -477 -28 171 601 -761 271 796 -252 -212 619 73 401 -898 114 -236 145 634 696 -486 296 -834 242 -878 -76 380 831 433 -520 -303 68 377 143 -718 -260 -989 265 -860 892 79 942 838 -474 520 -641 188 -506 745 -820 -50 945 -424 891 -80 967 -235 -960 -986 146 926 570 620 230 -961 -796 -213 21 348 851 -344 283 457 -789 -778 19 -515 -686 480 14 -25 939 -520 443 356 57 -117 -532 904 166 -158 486 898 394 -781 489 -443 -758 -645 314 -323 -810 -849 146 -939 -202 723 -636 250 -223 -802 -769 115 251 400 -847 445 8 -948 -581 763 -821 -927 -222 -903 -677 306 919 -445 -998 -177 -36 195 200 22 -915 -727 -628 954 -542 -481 -801 503 804 627 636 459 247 664 910
|
||||
612 273 -153 297 -765 -929 828 918 717 718 625 224 148 -640 693 -386 716 -25 -176 699 474 -826 -455 -588 -174 821 6 -761 -366 692 -367 189 -8 889 -98 606 936 -696 643 -17 408 248 -720 -567 716 970 -391 -41 -26 721 781 -658 315 168 16 369 649 509 -487 -307 883 526 -536 262 299 907 814 328 -5 -329 172 569 532 775 432 772 -40 796 -511 586 909 261 209 -682 48 -89 -814 -910 -45 440 96 -122 -818 -252 881 875 -794 -402 77 837 228 21 -587 588 -60 832 -958 950 877 78 -247 -416 855 -493 373 632 615 -509 749 -645 542 951 -314 913 -246 962 -824 129 387 265 -606 381 534 604 -503 -594 -635 -70 688 -640 379 80 928 706 -155 437 -497 -854 294 -712
|
||||
-573 298 841 357 -706 -176 918 -927 272 -28 144 -263 777 524 -281 -445 -129 499 713 620 -986 793 -628 53 -905 911 183 207 -752 784 -456 76 257 962 496 267 154 -801 733 136 308 -306 -271 -458 921 913 90 283 216 -535 21 392 998 756 -121 848 -477 291 78 429 286 136 729 299 -194 -341 -521 -605 -380 -188 303 555 -896 -28 247 735 921 834 806 668 -685 374 376 54 399 -992 462 -455 -308 975 -891 -146 -294 852 -80 -621 546 910 372 -292 556 -386 -122 111 626 -932 -900 -816 702 630 -699 571 636 275 966 60 -461 -727 -900 -45 -778 600 -148 -130 -765 42 -520 583 -269 340 728 -33 -482 326 -969 885 -77 348 -283 -312 790 -313 -206 -331 675 -986 628 -968 -858 -361
|
||||
-298 652 -615 -974 -728 915 -635 -484 24 68 22 762 664 -780 -579 316 -851 -98 831 793 289 -187 -57 -365 233 -21 626 -318 -911 -461 -414 -327 -1 190 925 731 -854 -27 -101 994 -395 235 -985 208 932 508 -727 -621 342 -404 808 897 -998 706 -43 -953 -811 92 492 -344 -765 727 -896 552 554 -728 -968 -625 346 159 -265 -422 -713 -898 -228 163 -725 706 -765 754 -485 -59 649 912 124 -260 -255 499 -330 697 100 216 881 845 450 919 -345 987 404 -46 -872 525 -602 408 306 771 20 -871 356 -462 -993 548 -62 546 -226 15 868 367 543 -489 -965 272 -483 641 -499 137 782 -899 -55 993 -59 412 -685 666 -406 -463 143 277 -287 -113 27 885 21 873 -161 45 -584 240 -221 -661
|
||||
129 792 594 -261 -876 861 -301 -373 902 -78 844 -739 -770 894 330 -930 962 844 -660 672 957 -420 -992 -977 -335 430 765 369 -848 333 436 774 459 138 714 -123 583 912 -636 -696 271 871 840 192 706 164 281 651 271 -690 766 -85 -223 -693 416 -727 146 -75 -552 881 450 -80 338 -688 -426 704 -547 23 902 906 -344 -927 -573 818 777 866 151 134 -796 185 988 862 513 -96 -435 857 -579 -156 -345 -877 -324 -912 618 400 -428 779 246 -91 -715 809 -548 -202 198 893 196 654 248 -761 -321 538 853 -671 751 921 -963 257 -187 103 205 461 43 -871 -746 -878 -154 572 -594 -442 508 307 -744 241 -113 927 -265 70 -69 -259 622 -781 603 671 -752 -23 -791 -845 341 211 -792 -167
|
||||
-892 -77 390 567 -479 986 920 887 893 -820 -960 -86 327 -930 -461 -418 -728 572 -711 -716 -231 871 256 -868 -773 646 -804 -518 365 814 614 841 21 367 -26 -347 -698 -850 -577 817 525 -73 829 -847 -225 -320 -574 -27 242 -101 -61 231 -780 863 -901 -935 -197 466 -651 529 684 -174 466 525 567 -648 343 -480 -141 881 656 -779 439 -879 -100 -409 236 -954 771 -748 955 886 893 -278 -209 320 876 617 157 255 -721 523 153 -616 663 -169 177 -3 -710 -240 -146 252 411 933 -135 -43 558 945 -44 3 -177 507 -57 -298 -875 -227 -395 -508 -755 133 442 -410 -985 -80 703 319 -519 -370 666 -918 143 957 -370 -274 395 433 303 -357 -134 -853 237 -161 -677 -226 647 832 -816 -109 777 -566
|
||||
532 19 -32 32 983 231 123 31 886 -842 452 63 641 -579 -248 403 426 -6 -592 855 -926 947 -306 -739 592 -257 -176 696 -976 -700 -88 -833 251 -30 758 -756 766 324 144 -284 -741 238 -433 -797 935 -43 -911 38 6 -332 822 -162 -938 -800 -967 -56 -816 155 -678 -9 -465 -23 905 122 -564 883 -124 -296 5 398 511 -942 -243 -314 371 -483 557 -975 38 256 129 344 164 607 11 21 -802 734 649 -831 -871 7 668 -356 -320 -355 157 -360 910 370 -51 -563 -15 -311 -124 376 253 -606 -264 -582 -203 -447 -55 -59 544 876 -779 731 -925 767 418 674 790 -888 -489 -552 -86 824 -785 419 170 305 673 300 -748 280 208 369 236 -226 -970 339 632 904 813 562 301 731 30 -112
|
||||
629 -359 -439 -526 996 910 -266 -424 -423 680 120 -672 255 439 -330 204 -29 354 566 527 562 181 -540 801 356 -997 156 -393 -135 865 -914 607 880 719 -361 38 -350 195 -194 -613 -701 -712 52 -471 -232 821 103 924 280 201 152 -312 -13 781 -433 105 941 719 -883 767 902 -811 858 9 764 -591 -892 849 -496 -841 484 356 -106 829 801 897 -917 -537 -947 241 509 537 -998 0 -848 -908 -343 -372 987 -407 204 396 527 88 784 -508 679 858 -152 -90 573 414 -807 -2 370 -238 -693 992 506 663 715 464 943 924 -516 -1000 -117 119 -488 -594 95 -975 118 153 -369 -350 -904 43 -293 416 845 536 -465 650 90 406 -160 -121 -134 -503 -101 608 -191 -347 695 -652 612 991 98 -968
|
||||
-184 652 -98 -187 954 727 616 971 68 -923 -419 993 351 -919 781 -670 -832 -163 462 -886 -839 -747 837 511 408 -631 -932 -671 230 -327 352 105 -483 -430 -155 989 -615 106 12 820 716 394 837 -130 832 381 330 713 -575 279 -856 -365 -89 70 -188 -951 -603 667 562 198 113 933 872 363 -588 321 -994 588 -218 60 239 904 90 -251 -524 -113 -511 -17 -554 775 -166 -368 -713 605 710 160 -891 -318 289 -706 250 606 812 996 292 -771 235 701 -851 405 -756 500 496 69 953 767 -96 323 51 -94 504 -325 -853 756 -737 461 584 910 -193 -7 -217 -397 -742 -725 -518 -337 991 46 163 -72 907 -287 -96 261 -811 -712 -333 192 -216 911 208 -407 681 164 -64 609 496 -582 894 -463
|
||||
595 -453 -89 -254 129 162 -444 -777 998 805 84 -854 785 497 -776 272 -946 -761 -123 396 -819 997 -403 891 509 -786 -624 -425 -326 -57 -747 621 -720 743 -735 -738 279 103 -633 473 961 -745 -698 -409 981 867 -791 -114 -98 216 558 -516 -928 -261 230 -948 371 -820 641 -937 919 879 -600 -737 296 635 -425 -625 353 -268 -191 757 -96 -858 -389 521 -703 567 -438 65 90 -954 -97 -242 -160 -185 862 650 987 986 -201 564 45 524 49 595 -547 655 -879 853 -413 604 745 277 -76 -926 759 -898 135 27 -18 877 -903 100 381 -928 240 -909 597 -241 -64 853 -617 -787 -135 -567 226 -424 -666 665 -230 518 -664 -580 798 916 775 531 -686 -752 26 200 -265 487 694 842 81 421 353 88
|
||||
548 -920 -539 -534 -43 -993 259 940 85 -203 -110 -57 101 -276 859 198 -479 795 -654 -368 990 537 -260 621 801 -488 896 -60 -142 -26 -976 808 870 -222 -751 -907 -422 520 291 803 -248 879 111 -569 -7 -725 700 337 493 961 -514 -814 -443 -607 156 -367 -894 -448 985 138 -576 -606 210 -109 310 708 -935 -1000 -730 458 -561 -638 390 -157 -354 -286 -799 439 -855 -303 -56 842 -67 416 -579 -240 -195 724 657 271 -189 -480 -357 -854 -259 -958 -397 -727 267 471 -707 922 -886 496 -32 -61 -873 -852 251 119 564 -818 -971 -538 -870 201 -68 -967 -459 549 133 -855 -709 -764 406 -546 558 559 419 431 357 -425 -616 -818 -301 57 -719 -189 -87 -541 -946 88 72 -75 841 -523 650 -364 -350 -188
|
||||
186 709 -130 318 -578 -877 -176 -557 -127 340 266 -78 -697 474 -695 -893 -339 194 548 536 160 52 279 648 -603 -320 -395 -520 247 760 719 -318 285 472 711 -610 -77 -900 353 757 140 -705 -507 925 948 160 -571 882 -203 -364 -490 956 -829 729 541 -289 -77 123 -288 952 51 -969 -551 -74 138 -651 14 -553 710 739 43 -549 -73 -333 506 870 635 52 -624 183 -278 -275 458 -57 313 591 803 23 -296 -617 761 -723 -435 501 164 -419 -214 -114 -951 547 -439 -243 958 334 -536 -263 -702 800 485 -676 100 496 369 961 -611 -396 -623 -489 405 -549 177 956 343 105 -31 912 877 820 360 -813 709 -283 -67 -562 -989 -63 -547 -361 -628 398 -703 -394 -383 -499 -766 -638 -555 -653 539 218
|
||||
608 -518 376 995 -493 46 898 -988 -537 -769 -791 -245 -451 272 -377 363 149 -791 -53 -582 -419 495 -289 185 217 778 988 -16 -800 -55 936 751 -338 -448 -423 918 99 933 -920 436 711 998 780 813 -433 1000 39 -353 -188 757 421 413 -230 -960 -207 276 342 -210 -288 -67 205 483 36 -19 -970 824 857 506 -72 -773 -834 -985 264 -473 -601 318 130 -412 478 642 222 459 -87 -73 -224 301 507 594 693 867 380 -901 506 -452 482 -352 -776 -251 196 468 409 181 953 39 385 547 -65 119 634 -58 -342 222 587 291 190 -999 503 -928 991 651 482 603 389 -318 -645 6 795 970 228 247 -715 -971 983 -712 -605 -213 -894 -901 665 705 601 239 -854 -138 360 -418 870 943 -556 311
|
||||
-862 -77 -286 -492 345 341 721 103 -847 914 -103 -844 373 -358 -706 275 -41 185 -658 527 -265 -234 133 145 -736 862 -87 -821 -285 -333 -652 -983 531 -158 774 534 246 70 327 868 -893 256 536 -761 922 -615 571 -338 501 -419 -999 925 551 347 -542 784 340 -111 -160 -701 726 504 964 -601 297 619 -86 800 993 284 -761 832 -960 260 94 647 -655 -401 -753 -972 -98 -788 -201 -57 737 -506 -564 797 -928 -60 -654 81 497 -496 1 562 -208 870 929 -473 211 663 781 -261 625 -486 829 -101 163 342 -838 -468 233 -19 110 92 510 422 410 -237 99 -254 223 138 -862 -146 -642 903 576 409 936 418 -299 947 -793 695 511 13 185 -896 972 -758 -554 247 -416 -86 -311 295 643 162
|
||||
-658 -257 390 -483 934 638 -420 937 -704 755 -535 869 50 -311 -19 -543 -366 -990 -941 388 -396 -86 352 386 -531 -500 -195 661 771 789 372 173 207 31 -868 -979 547 692 178 -679 -171 82 -753 -129 842 -419 168 -274 -333 -591 -781 -6 -145 169 776 -624 288 -67 988 -310 -864 -61 847 113 -404 62 826 792 902 -237 746 -559 72 -757 461 454 -320 368 -277 83 337 241 -973 998 689 347 49 -112 -466 947 -473 -585 903 -294 -251 771 -445 -206 -391 -300 -527 141 883 -16 76 909 -808 -26 193 -466 589 23 -991 -779 -243 -148 781 -177 -948 25 452 -955 269 -810 -677 -263 841 660 67 380 -785 150 -500 -34 260 -319 -935 -858 324 -419 974 302 910 -173 990 564 -235 -543 -748 -17
|
||||
430 -984 266 -874 -774 -844 644 389 -671 164 -372 764 -252 -594 15 738 820 814 506 -383 -946 169 545 -472 -138 407 183 -691 -254 -581 198 598 -989 -790 748 -326 -59 -876 465 -212 -26 749 697 -784 -117 367 513 -242 -320 -797 -989 166 525 522 -950 694 -563 -56 51 673 -585 -237 562 -68 792 -222 524 657 -393 -309 409 -439 181 436 -266 529 29 -448 511 222 315 165 555 928 -119 857 964 -510 -895 140 250 240 373 -342 -890 444 -699 753 680 820 111 826 -749 -956 776 -369 357 487 86 453 809 -2 680 -225 420 -529 959 858 773 -317 -363 847 970 -881 286 918 667 54 -494 607 698 -462 850 353 907 239 -44 -26 817 -697 -493 -561 790 864 379 -735 337 434 784 -161
|
||||
616 607 288 473 534 -867 -722 -299 444 -964 -954 481 612 141 -839 -821 -443 823 67 876 -274 299 955 -371 95 -185 265 -585 189 -603 941 -72 -916 -466 -153 -79 -683 189 -483 -598 179 -378 -88 90 810 -818 933 -899 -130 -584 850 190 532 804 924 50 -221 -357 814 100 170 -600 447 816 581 325 556 544 -837 846 615 750 74 138 510 386 841 -876 -645 -744 943 587 -448 592 -71 168 -879 188 -208 -274 929 643 -685 -276 -294 868 388 -292 -669 -980 65 -141 -420 -810 764 570 520 94 221 -400 -888 457 -743 130 396 852 765 -348 -299 -153 -719 -1000 -951 -372 -443 -888 157 -689 384 813 -251 985 -397 953 -354 -206 201 468 -741 -394 284 -25 630 -215 777 815 -741 -187 789 -770
|
||||
-816 -896 656 -896 -949 83 -831 800 532 758 68 -851 -706 -717 5 10 -639 -226 -634 -546 761 -378 -451 -759 145 -103 -386 244 -31 -533 -496 416 433 581 -870 -703 -903 183 -880 386 971 -898 -939 65 -799 -237 -862 841 -469 100 142 447 -765 386 564 461 392 -861 281 915 2 -995 727 261 -152 -860 895 -316 984 -983 -998 548 607 123 -555 -427 -918 665 868 809 22 883 -840 -373 -91 -814 -913 640 950 -363 873 -749 416 -106 385 -683 -600 493 -233 507 408 -911 857 -527 79 568 394 161 943 -173 -259 122 -124 -177 -291 785 512 -231 758 -462 -836 -122 -314 -307 -967 -647 -355 966 -103 -107 -92 -202 -273 865 648 -818 -14 635 -181 914 466 282 383 -51 -856 414 -912 -228 856 48
|
||||
182 -386 -372 638 300 -782 599 -853 -991 -422 -826 -280 -64 192 -991 -167 -46 331 599 -301 761 -575 125 -679 -506 19 -665 -215 -269 868 984 473 -984 780 -376 846 732 817 957 -963 -916 993 798 611 -779 863 -50 -890 -655 -673 -857 -188 835 540 -595 -462 -794 123 -222 188 -640 669 -662 -647 -99 683 590 -628 766 -152 -360 574 985 -375 724 883 -201 -147 -289 -699 -731 547 -657 742 940 35 533 901 809 52 -969 -576 349 -660 -48 -650 -992 -981 -249 613 918 -957 -72 188 209 463 -831 352 466 -268 758 64 -517 -418 -807 -993 718 43 882 -882 -468 -465 218 876 727 216 -498 916 -661 936 -216 468 -103 -953 173 122 757 890 -470 543 -299 -68 697 -348 165 113 950 -592 258 -147
|
||||
-756 -45 -802 -125 -461 468 -774 -279 443 445 989 221 -572 695 138 -492 396 -975 -123 -469 318 -727 -889 807 -836 -829 673 -247 895 33 -749 933 -998 883 -658 -634 481 585 -323 -123 -572 -921 -423 -631 798 284 497 -257 -235 -127 549 340 412 -802 -824 688 790 492 -34 27 -903 -998 389 -109 379 -995 -971 -363 -570 -695 -400 -126 -579 548 -412 -923 225 522 937 481 425 167 480 -569 314 188 456 -629 -464 411 -524 -441 -153 -988 115 546 661 -911 548 -361 927 791 -300 -196 -929 986 8 -91 872 -79 -423 -449 581 928 -89 548 45 -249 115 -259 -111 -595 -680 -377 -884 238 -435 687 -506 250 -355 -70 690 -159 -460 -118 985 -144 -94 -751 -455 -750 33 -482 483 -888 -305 -142 -866 -342
|
||||
278 -73 -669 909 133 -377 904 893 -754 979 692 579 -256 745 -485 350 407 860 -856 219 634 -327 891 946 3 -735 -274 938 -720 139 857 -599 -706 -181 557 727 -193 160 -255 867 -258 462 -75 962 20 253 -221 -193 -316 -603 455 -760 120 456 567 -934 -494 -1000 -775 539 -724 112 -47 834 841 284 -716 -128 -579 -339 163 -569 -551 67 813 -821 -51 185 208 -773 -557 -337 -127 -528 542 -630 158 -769 594 309 -524 724 666 940 -124 -688 617 859 -773 -67 200 571 273 -260 -158 -788 585 -68 78 -605 -869 -901 -555 -592 -524 950 -694 -520 517 -393 -821 45 -466 -31 -789 -6 310 381 884 -578 -239 -559 739 308 403 585 -226 -543 -810 400 170 345 674 934 -501 -705 -76 -319 588 203
|
||||
-730 345 -488 434 916 350 170 -821 -493 652 101 88 220 174 565 843 932 -278 -714 819 -596 -438 -466 -942 -230 276 627 -965 378 -913 754 -895 -955 871 -370 -57 -668 -592 427 -555 -364 -734 431 -708 -541 -689 745 -880 -340 -830 -95 -216 278 147 -360 150 562 572 -768 -115 -883 -982 -194 -626 88 -681 -708 137 501 575 -239 -114 -834 866 -510 67 -639 -656 707 -412 -432 -412 -675 994 356 -797 -522 -317 -887 -245 150 -801 -222 -121 719 -149 -285 184 -229 540 -945 792 849 -291 -491 869 243 -443 98 -429 208 609 -900 -166 87 -469 118 49 517 84 -437 -69 776 -592 673 304 296 -91 889 458 -414 -954 -563 -270 -843 -931 -465 -732 942 128 -51 -861 864 -976 -774 -820 -383 -658 -35 946
|
||||
-497 -995 -202 705 768 745 -459 349 -271 -547 -44 -551 -701 497 -104 276 -991 -920 484 715 787 -595 860 358 557 226 685 -430 -84 -957 -580 882 -390 -372 -203 76 -906 920 -111 44 -326 133 670 -797 527 -121 -107 741 -959 182 747 725 389 493 -401 799 792 -15 -292 689 663 762 -618 -770 513 721 -756 204 -3 567 393 -481 -279 70 916 -447 -485 -709 -13 -384 428 49 256 699 -380 11 -718 65 -581 -387 486 847 56 317 700 976 176 872 259 -218 942 -549 -593 592 -805 439 -329 -155 -788 359 -37 -105 -654 357 -48 919 -896 830 -220 470 57 -729 289 323 -43 -407 -33 -985 -425 66 -193 805 -392 -642 94 287 49 -60 228 -629 936 705 197 -660 670 -826 919 427 996 -56
|
||||
-131 958 598 -720 -603 -632 -210 -165 -893 681 246 407 888 770 -358 -306 965 -256 357 -873 -913 901 -255 -976 -140 639 -138 37 524 -699 -731 758 -431 -962 147 -649 -869 -84 830 -313 249 -226 -653 282 158 -307 304 853 16 -723 -182 -539 -298 -178 -256 971 118 275 428 -828 754 -499 38 -103 -864 -63 -638 -704 -346 -293 425 -396 184 -594 825 -647 -617 974 -374 -60 -626 -338 919 464 -712 -358 -978 -624 246 -701 -546 326 -11 -653 -76 -187 -802 -391 721 -238 425 -872 -388 288 -250 489 648 -762 747 -997 825 -791 39 -190 658 -173 -614 508 -720 636 -887 664 530 -589 308 -586 -534 231 730 860 -410 343 -456 -841 -875 460 564 61 -765 844 271 -391 -498 -446 -522 203 -666 -361 -604 -712
|
||||
792 130 40 876 -90 418 -935 -591 -21 -762 171 679 563 898 76 -294 -160 -564 849 -582 -152 -934 689 752 492 900 -770 240 -624 406 -784 862 -432 -904 -586 300 -391 145 -636 148 45 -162 -221 200 -120 -385 142 -569 -169 -410 -684 560 79 113 -898 -18 16 177 130 126 -937 626 991 -711 0 -284 -282 181 646 54 -400 -85 -303 -733 483 -319 -343 306 289 123 -915 -380 -927 -695 714 -900 244 709 331 54 -475 384 -865 617 -348 -642 856 419 -890 -68 -32 -60 648 -353 -687 -633 -832 -333 252 -751 -303 87 108 -422 86 -79 618 381 -869 632 897 -84 744 -88 -404 -881 -207 -986 554 -809 -281 -628 -186 383 99 738 568 613 -933 883 565 727 953 -775 39 402 -261 897 -301 -703
|
||||
-800 872 -846 -785 454 828 690 42 268 143 -36 -959 492 -950 -277 541 -526 -446 -762 -833 218 559 414 -84 29 600 -397 669 -366 -483 744 57 837 -732 550 -895 513 616 340 244 538 31 395 -36 882 -24 -923 476 191 963 -415 -170 -183 129 -971 -232 -302 -152 79 -850 623 955 240 -989 -3 -756 -862 -767 911 318 428 -941 -126 648 -846 -932 -218 -45 325 964 700 -548 -892 717 -931 -772 366 645 -626 -949 -320 -755 993 943 384 -387 705 774 -590 203 -902 -447 613 593 273 -368 -485 -574 -30 -128 290 -237 279 -9 667 -753 -603 -700 -159 -822 80 432 536 -509 816 570 541 950 -665 -537 -707 857 271 701 6 -917 -416 415 107 267 434 -229 491 715 532 -379 304 -69 648 62
|
||||
-306 -970 -700 741 944 319 780 -129 607 -716 -374 846 18 -684 295 368 382 -100 -808 850 -259 153 -706 619 579 962 539 -520 370 495 -654 612 18 -50 522 -561 -216 971 -963 484 -867 517 968 238 -87 110 -649 -165 984 -696 -571 -728 -14 411 766 -296 -361 985 269 -503 26 -32 -450 847 369 354 823 779 331 -525 146 855 928 568 -575 -967 194 925 214 885 966 390 -578 117 907 608 -712 247 143 817 890 -665 -831 -281 -782 -81 -791 869 -434 47 786 912 631 -776 940 -730 398 -134 826 -276 -91 -662 201 -67 -183 793 -120 842 -560 -650 -782 -864 38 122 76 -789 -513 -535 -265 448 -764 -227 512 -909 -429 669 315 -964 -194 -214 700 574 765 -445 753 535 -110 -293 726 -527
|
||||
855 543 663 383 -717 914 444 617 -888 -343 545 419 865 903 -128 -295 -862 -232 -682 285 -914 387 675 478 -806 -712 787 823 -68 915 -54 -317 -510 430 -455 21 -244 137 285 123 -974 797 -378 -481 -127 532 353 593 -35 -398 -78 335 289 -188 -96 -276 -980 -930 996 -120 -812 789 101 505 930 -597 -336 -550 72 -548 455 651 544 -157 -770 73 -170 -171 -917 614 425 204 -857 -343 -940 890 -642 460 261 -761 768 323 319 793 944 1 -947 -164 -116 673 -796 -326 548 626 -556 -842 28 224 189 -15 -73 622 -279 -60 -17 683 -33 89 814 -566 723 -995 -309 -816 941 535 710 11 -453 159 959 -913 612 4 -776 -950 47 33 -810 211 -941 67 840 970 474 660 58 -24 -906 -509
|
||||
373 -16 162 848 197 -843 617 868 -434 834 -634 -663 -536 -266 401 309 645 687 -863 195 923 322 -288 -518 541 114 -88 -205 533 -563 -695 89 -178 -243 -726 517 -914 812 -339 -746 -680 -645 41 494 824 -774 -938 -782 -583 594 -244 123 731 -951 -162 362 989 -779 751 -753 -903 -365 847 833 121 -150 817 -37 955 826 142 110 370 445 120 150 -394 -437 -787 754 664 388 -928 178 741 60 297 -462 -593 627 956 567 -403 -47 -794 579 -61 -251 233 -489 -751 -602 -484 -680 805 -356 526 -667 -663 -82 -972 -986 -15 -814 -78 -386 -367 929 -546 -204 -285 -115 47 932 845 -756 -554 194 -780 474 -327 -626 648 83 673 -839 929 -808 -782 -686 551 851 -162 791 -166 506 343 -724 -420 55
|
||||
-75 678 140 19 413 737 -152 -951 318 -551 -580 -961 713 -858 945 -408 267 276 -14 -692 573 -202 8 -883 -294 -795 -326 -338 -343 571 27 654 -499 -685 -636 -833 -981 -820 765 -537 -215 995 970 177 291 -803 66 656 -545 204 -604 730 -811 854 -67 23 -952 115 -958 -736 -527 -523 -224 -320 304 -342 959 -862 88 -659 -790 -532 -515 152 226 -538 -125 255 -874 -394 -292 -803 343 855 776 -204 -42 -606 396 497 -776 44 -36 333 801 213 -235 127 -670 457 -483 -499 772 -717 762 585 504 -966 278 -757 643 -379 354 -103 -66 -175 -700 744 -420 773 840 -528 -496 675 61 269 408 -756 -4 -937 321 -502 58 924 86 -27 -781 -914 -496 -446 182 195 -356 -535 828 905 255 165 141 623
|
||||
-609 821 511 968 267 946 546 -268 761 157 -411 -633 128 -984 -308 45 -987 -540 -499 -619 702 22 -817 -852 121 -877 635 840 140 -130 -162 -221 740 -435 940 -605 219 -150 -138 -753 10 -47 -293 900 -553 943 -218 605 859 -426 -507 443 -631 -495 -867 335 263 -119 864 553 913 -1 683 51 554 999 273 -166 -999 275 -979 23 614 773 -622 663 223 791 -380 195 320 -272 -137 55 -108 762 -423 -181 -324 801 -430 -141 673 -290 -653 611 107 -995 -255 -661 779 -451 172 -935 -881 -431 976 394 -305 -921 -32 381 467 -847 644 -69 -415 -548 -839 910 -539 -576 -327 -245 366 541 704 -761 -561 604 9 417 -45 269 225 970 825 -938 -858 753 -263 -913 -714 623 854 247 633 444 -167 858
|
||||
-30 882 934 -57 412 -624 -392 -648 -929 480 345 293 -354 -287 914 456 -898 -123 353 22 426 -144 -665 -608 552 369 -158 611 -337 684 -270 -598 883 -428 372 34 -290 -25 155 -570 317 836 715 835 -818 253 -211 -806 252 126 -963 -21 -476 337 -828 -431 -956 581 -269 440 901 -542 276 -918 876 403 473 -681 329 -228 854 -795 -799 -27 463 511 -342 635 -696 736 -161 693 -447 278 975 832 -903 -865 719 -688 -146 286 77 -798 -166 183 -874 183 -194 -676 -322 -232 -213 403 -331 -913 912 -755 872 580 589 -125 204 227 -310 -982 584 209 -549 -391 431 442 -416 681 -948 967 -524 -844 875 -59 -884 27 68 610 -510 -512 -91 -445 -210 -453 524 993 777 -230 282 -202 -808 792 -852 -605
|
||||
916 -683 -777 653 -448 -146 -767 876 -807 384 38 -443 -290 -938 -234 154 -451 -423 66 300 539 -128 1 754 618 -28 -29 58 -96 -934 -140 -587 364 -477 725 602 229 -524 509 -742 571 -379 -673 -151 -137 -621 -136 436 -685 853 381 449 -295 -527 262 717 -532 650 -396 769 -969 308 -727 164 -500 639 105 -140 641 971 -321 -524 -670 220 910 -655 -950 712 -184 -935 -304 436 -483 370 1 958 270 594 -82 -87 11 980 821 -436 921 -725 478 -353 346 572 -673 152 -360 57 -517 207 999 -696 -197 956 77 -931 386 299 -944 929 -825 865 652 515 -610 -518 391 885 -93 965 80 -874 -610 310 -849 630 -370 226 983 475 0 740 -601 -611 268 440 -378 -469 576 -410 -638 104 -400 170
|
||||
-606 -638 273 959 -724 230 -709 688 -913 -513 701 204 -458 -822 456 968 528 238 106 -487 827 227 5 -126 978 -115 496 -731 995 162 -134 -171 160 701 -622 25 36 -887 194 964 921 -104 650 -656 -938 -62 -856 -862 999 418 -270 -194 -682 -395 -632 -595 -555 505 -840 366 658 -747 -63 195 -192 -461 -26 -470 73 873 -207 45 -94 310 -323 -619 111 199 700 -410 -800 -703 -658 994 631 -476 -728 -306 918 -295 608 318 424 466 -367 30 -277 -742 -433 912 327 -53 591 -745 -103 -566 967 -470 120 -857 414 90 340 -619 896 885 534 -129 -182 -363 964 871 -298 -49 -212 -106 733 729 -198 839 -131 132 -69 -835 576 574 -165 205 952 -570 902 29 -617 345 100 33 -593 -871 -913 -139
|
||||
-396 887 -734 480 447 215 -576 -658 -327 547 324 272 643 16 -33 60 -570 906 -458 -799 -601 979 -964 753 -615 257 -736 -309 -370 405 -804 461 254 -934 758 -889 754 407 -840 -414 -633 -156 -926 147 -156 41 920 -238 -399 303 323 348 -813 -311 423 -474 432 253 -745 694 194 600 -258 999 149 -710 282 140 262 684 885 -596 -102 -515 -537 -603 -736 -435 -704 693 -590 958 420 962 -506 -890 903 -608 -142 757 178 824 374 749 791 955 71 -957 503 424 -785 -543 362 787 -754 391 290 -937 -998 8 324 708 560 -950 368 648 867 -704 -77 314 -646 12 710 655 -486 -794 486 629 684 573 271 615 -871 610 204 209 -276 165 45 -17 318 286 -934 -338 -821 703 233 -279 -902 649
|
||||
23 -840 -718 354 112 -465 -296 -395 372 787 597 633 -432 463 -287 -245 -669 396 -702 -857 -797 -535 28 -313 -513 -843 368 -443 949 -924 -301 675 -498 -980 -509 974 741 96 510 458 -892 -976 367 137 -485 -428 -809 422 496 191 -292 -683 250 308 -415 -9 291 -602 676 161 890 -905 -439 -295 -565 -605 -676 225 -911 221 235 144 152 157 -190 138 645 942 792 865 94 -233 -63 439 408 -92 -797 -579 31 -136 518 141 177 -447 688 129 457 -120 -102 -182 138 219 723 -267 278 697 346 657 -823 -220 274 800 42 349 -660 282 75 891 44 -32 800 -749 410 960 -625 436 908 957 528 -238 502 -635 -469 908 86 441 -267 439 736 348 -759 -481 357 444 -955 996 -280 -338 -468 -655
|
||||
257 -587 -600 -202 -956 -769 883 432 -921 -521 944 -819 621 816 -54 -488 -851 -300 -48 -496 547 851 -737 881 -863 -393 -747 958 690 -755 -961 -570 773 -447 877 -440 -232 -764 924 -536 503 -879 -169 275 -502 96 585 -17 691 948 -675 58 947 -527 54 -26 984 -595 -683 -511 -384 964 -987 925 -943 -713 254 667 -772 -593 544 -699 -244 -838 -595 732 -935 291 595 -666 254 -391 612 -219 318 949 -320 467 712 -74 -674 107 235 -313 364 -540 -309 134 -364 -481 914 -271 -626 578 121 902 -367 268 -86 694 513 744 -67 638 -354 301 403 -568 775 846 -111 213 -742 -208 252 -308 -660 112 291 49 -935 10 -942 -632 -77 -256 -276 327 129 -125 664 -548 -336 -5 938 226 593 681 949 -8
|
||||
-771 -209 327 -685 926 -449 -797 818 -232 -324 -492 639 -708 -633 -901 -760 33 -631 479 169 -523 -406 850 -279 -719 -90 -892 15 589 -322 -520 -481 -14 -708 172 -725 -904 701 -103 -637 458 376 49 197 938 790 -466 668 790 97 102 -285 -1 46 -692 440 -794 439 204 943 516 315 299 26 -929 833 -462 25 -355 -242 124 43 -151 282 31 -52 511 -376 -44 16 -239 346 244 920 313 347 -896 -940 598 -100 -910 865 -481 -363 -849 889 823 -118 -625 176 -759 -833 -94 -294 314 150 502 151 370 -336 -671 -876 619 11 -164 -738 -929 -786 232 401 -856 117 160 856 868 939 -886 -141 -345 497 -749 803 -851 -624 284 487 214 831 -193 898 -217 -150 744 790 -901 854 -437 -292 -460 -784
|
||||
440 725 -673 -17 -207 118 429 -174 -968 -176 133 -261 -120 -639 -617 -639 436 -329 -967 -96 625 -677 527 -121 469 950 -762 57 567 -257 216 -355 597 849 -517 -419 -517 -371 463 914 -580 -510 -341 938 351 -116 266 -27 -612 -603 481 -142 -974 73 -307 482 -299 997 539 945 715 535 -572 277 -387 831 922 776 -698 -758 476 722 490 -300 474 746 377 260 -744 -612 947 -43 -296 -322 233 415 -968 917 725 -581 -105 -400 -275 263 -95 600 755 846 -126 -871 629 -76 514 591 -853 382 295 -875 698 824 522 821 -112 -980 479 177 -711 -612 515 -663 -899 688 274 -939 643 522 542 -108 -346 55 -484 941 -67 702 -756 -475 -160 558 641 226 282 92 -430 138 -510 29 -372 488 -357 -127
|
||||
628 -79 357 218 82 -384 224 905 535 -222 -50 97 -576 10 828 -930 306 619 882 -626 -563 356 -779 469 226 72 277 -648 -92 -99 836 -49 -674 432 -480 717 106 -558 -765 -198 -669 -583 -498 -589 -39 21 -891 606 -376 502 214 -629 -62 793 -513 112 -326 174 -131 218 811 -387 -348 534 778 -646 -453 116 923 449 -980 -640 442 45 -710 -305 -549 -836 -736 97 824 110 -836 81 -256 -522 -661 -114 905 -150 760 -805 -263 -82 -399 294 -313 291 167 -361 -37 984 311 -792 -112 -750 -432 -109 -538 -852 -40 -177 10 -389 -77 155 -40 652 711 -416 -512 497 -450 768 -713 620 -297 381 288 -901 283 667 412 -37 412 679 755 764 25 337 287 563 818 726 -546 -304 -550 -748 22 -105
|
||||
657 -202 -926 276 -943 996 163 73 -890 57 873 -759 -257 393 -882 534 55 -164 -787 453 158 89 347 376 786 -696 792 969 517 306 178 -672 922 156 451 217 123 490 -504 -874 -415 160 -126 -335 852 740 408 -988 -254 -133 -992 -62 -432 681 579 603 200 574 -80 532 -438 410 108 372 -276 720 602 -470 315 -1000 153 -443 -506 -595 364 614 -16 889 -336 99 -790 982 1000 527 -339 924 -356 -857 -533 464 -495 -548 807 469 400 677 -11 821 -436 22 -594 999 -536 561 830 779 -259 553 -553 212 -985 -348 308 -280 782 733 -424 -734 -718 439 -427 -233 12 -20 -373 623 -882 -686 -495 578 880 262 927 -832 -387 784 923 541 862 -693 934 490 493 792 -615 -560 429 -453 -324 -449
|
||||
-114 491 348 -575 -892 -431 -906 -512 93 799 -419 -167 -316 -630 335 444 334 -980 168 441 811 942 503 -679 238 -70 560 -957 681 -215 133 378 -177 637 364 71 757 252 -682 277 -523 102 -554 -932 -602 -454 -57 -105 -49 60 -410 966 372 -256 -399 -828 512 -964 367 -671 -276 618 -763 -740 -972 400 -140 -21 -497 -67 584 347 445 -799 369 746 269 -483 -398 -249 -34 -258 -430 391 171 720 -618 419 -559 -789 -598 809 181 178 -831 582 272 965 329 -616 -91 -571 537 -313 631 -214 -425 754 -119 -556 294 50 -781 -684 407 -524 360 206 -489 299 -11 310 616 -414 -597 -499 487 -99 178 892 764 -158 -875 -42 811 20 -580 -172 617 -935 790 365 -294 494 73 292 -331 903 739 -835
|
||||
-446 -171 -599 847 534 -591 -994 -473 -720 102 120 69 -166 -278 490 -977 -735 201 -197 -640 185 -470 -975 295 612 923 40 201 -602 -758 822 993 782 32 418 511 860 -571 845 -959 362 -438 -411 962 985 620 573 -135 53 -817 980 -286 541 665 -910 -726 36 -842 -430 -393 327 606 881 136 -269 546 728 -827 -34 -667 734 971 245 665 970 255 473 -62 -619 664 495 81 0 -922 419 -145 250 -848 895 414 -998 343 -325 397 756 -436 839 824 -961 -337 752 -641 753 37 -929 800 947 -492 39 -590 895 -923 672 281 -645 -503 165 247 545 773 -341 -150 226 -216 129 953 664 -898 940 547 -232 -425 -356 303 -291 711 -337 -484 667 -86 327 -336 695 818 707 -907 -791 421 718 -824
|
||||
-751 459 285 935 54 -587 -887 -535 -538 -795 761 588 464 870 -833 -807 527 -599 659 467 224 566 -920 14 -158 -793 492 -831 591 -599 -237 -551 -249 828 -184 -83 749 855 273 -305 973 -505 -366 -531 -488 -162 -982 -18 -705 390 803 -213 198 -638 741 867 -474 -564 -109 -982 74 -487 -903 -527 -606 -616 -621 -965 -603 -220 -546 409 927 -459 89 367 207 811 235 -921 -354 149 -679 -873 511 395 7 496 -599 -327 764 827 374 996 30 -799 -962 -951 -863 -767 -662 -343 143 -335 74 827 871 -939 84 -733 261 -420 -436 727 -193 -750 -37 -491 -245 572 -569 211 -708 -16 -973 -566 841 423 -607 -754 86 -198 -46 304 -575 555 -769 967 89 829 -708 667 -228 -566 -534 -844 -333 -268 -570 21
|
||||
578 -5 808 -123 -751 241 599 272 67 556 338 599 -568 322 791 929 786 947 732 -828 -989 -34 -678 216 271 -500 -348 817 -344 -201 -320 -200 -237 -572 -407 422 256 -785 375 -96 -351 993 811 231 709 -916 -44 153 82 -953 -315 -80 -900 -883 203 -726 678 840 -200 812 -875 -344 -295 483 753 629 769 460 839 -422 -274 728 198 53 -788 -736 618 215 -838 729 85 -822 -750 -19 -130 729 629 29 456 -332 198 -790 -269 574 -42 518 -233 859 608 116 -967 815 -173 -581 642 -586 464 824 348 -401 -182 935 874 -419 552 661 637 -44 302 -321 574 97 95 789 -527 774 -903 -537 -829 -722 -688 -558 439 -806 14 -885 -477 635 -162 556 530 641 614 -79 332 -609 958 -369 115 795
|
||||
-448 -463 -247 -679 903 -808 -785 620 478 42 166 446 12 -193 -726 -59 146 243 -469 -846 947 179 -513 281 3 992 -21 748 749 51 966 331 230 915 66 458 844 742 -148 -259 -954 764 -838 -985 876 903 619 -96 219 -940 628 -148 219 -178 -384 -469 409 76 622 65 345 267 343 55 126 9 -197 978 261 -402 -662 -31 -451 -399 -976 589 -743 -151 -689 -502 116 150 56 -822 481 -93 593 -347 -270 -640 793 554 685 -400 360 969 503 229 -369 -392 483 980 720 -63 -470 -239 -331 -111 759 -458 -169 268 -90 842 -156 -375 -676 -429 -911 -841 -664 -688 649 724 -525 409 -543 578 -231 -427 -561 -255 496 -154 -190 -236 -875 682 -50 263 -117 -318 277 931 -911 60 304 -986 57 -204
|
||||
-238 -519 726 -678 -357 -389 -572 -406 -772 32 814 -779 704 412 -501 77 -776 -619 -63 592 -112 563 445 370 739 -324 -185 -266 732 -621 -250 -217 -603 -272 531 -24 190 654 363 -753 -737 643 -404 -621 854 600 292 192 538 388 -625 -649 -446 -595 -21 992 578 681 -531 -452 -402 -728 254 618 -268 495 567 125 74 -958 586 782 -576 -19 -701 -344 113 465 -715 -638 550 -767 368 186 -635 -387 -894 -671 -579 165 553 454 -780 353 -268 -886 272 711 54 495 468 924 860 -800 -212 -51 891 -782 345 748 -992 473 610 532 127 86 -43 877 42 687 868 -362 -820 -726 -16 -829 -573 91 -1000 601 -655 -700 -531 115 954 646 383 462 119 -980 519 -857 -9 247 -718 667 879 -594 -42 -165
|
||||
258 946 710 -784 -160 860 961 -739 217 -981 -978 -31 470 -595 468 34 -871 -972 249 799 398 741 887 744 625 -657 78 733 912 -774 -6 407 -941 219 -791 686 -291 979 -105 503 460 -687 919 632 430 -804 932 813 -645 76 -177 154 670 766 -195 39 -149 784 -844 363 158 -153 -282 -343 -67 -797 45 -263 -300 -992 -92 455 920 742 -325 277 542 38 -187 -222 496 -164 154 42 381 -853 94 -737 935 -36 112 -573 877 834 358 227 21 -268 467 952 518 458 -185 674 -761 -381 -768 -542 -672 -178 809 -840 236 -526 -822 790 -245 267 -645 204 355 -447 -494 571 -266 888 -114 -485 -196 895 -689 703 168 -339 -95 -593 996 -100 -307 230 -596 759 -948 -895 660 -393 562 -686 225 152
|
||||
88 500 -106 99 -252 -645 816 -274 223 -7 -29 -675 -143 -203 339 465 -653 161 -796 7 471 744 54 543 110 948 -341 -879 17 640 -829 200 -998 -379 312 45 75 -430 964 576 976 -983 748 992 -706 705 -705 -284 -756 -184 -945 97 -792 -61 52 633 719 -466 811 -351 185 460 901 190 -661 -744 -3 208 604 916 518 -143 -28 856 -323 878 848 -156 -575 21 860 -18 -508 111 228 -919 -877 -27 231 -926 -377 724 930 -618 295 28 -527 -164 -156 -731 -967 -100 -821 814 -787 903 35 325 796 635 629 -654 447 -121 282 457 786 -690 190 -229 -271 518 -838 -794 763 -680 -758 537 729 659 -306 -754 -521 -484 -364 -308 797 -556 -910 232 -171 798 354 489 -674 570 807 -337 891 106
|
||||
803 -794 -429 975 -575 675 829 -272 160 952 602 481 928 -811 -18 9 -794 802 521 603 437 -721 901 -395 173 117 -323 932 -191 -132 638 357 -359 659 518 -44 260 628 -530 111 -281 -620 111 528 151 767 -906 263 570 -710 -544 775 552 329 -241 302 -618 -295 532 129 -469 237 -564 67 300 404 -778 -14 527 -496 -472 401 -22 121 303 621 938 737 -274 -34 185 837 3 330 -723 -689 -797 274 667 -231 480 928 -233 432 618 -695 -568 364 -241 93 138 490 504 -826 -249 -747 -803 500 840 497 600 -40 -602 795 511 181 698 30 -516 -78 308 877 577 491 876 -315 -790 -220 816 478 -730 -880 -706 -738 -541 365 -928 -967 199 293 -547 -91 717 37 6 -439 947 -276 -611 -974
|
||||
435 591 120 -675 930 499 -931 21 -557 424 -923 -369 -506 445 181 763 755 801 -265 856 626 620 21 128 944 851 384 -532 413 203 -797 -629 648 556 -538 44 -730 800 -536 -974 -633 593 -739 -910 -321 544 -984 -645 -12 -722 397 128 -708 -397 -839 -781 131 -258 74 -227 -272 204 239 538 280 599 -929 -333 -254 482 -46 -592 -83 19 -90 108 302 757 -256 -942 -296 473 391 -152 287 372 1000 311 -834 -947 -601 634 517 512 558 998 275 -852 4 141 28 -715 -248 320 182 -25 515 731 -515 589 -555 197 125 -676 -255 655 33 -957 -863 54 -491 204 -953 -205 876 -227 -822 -459 755 -967 -86 -839 -547 -407 721 385 806 822 422 101 571 113 989 789 -258 523 721 -823 -900 -72
|
||||
-719 -178 879 488 -299 -965 9 -521 631 -848 -657 -66 244 -605 -275 -96 -182 -709 -894 -972 -33 564 -654 -181 -671 -465 -655 601 -823 -637 -959 433 372 647 574 62 -696 709 356 -190 96 -109 195 969 182 -200 -802 721 -16 -866 -788 966 826 9 -631 -249 448 -92 -529 -909 -673 719 470 -964 680 -138 181 -903 855 545 864 778 -289 359 417 -218 -853 -964 57 674 912 735 -690 862 258 231 246 -795 -255 13 -184 -373 807 -121 -143 273 -864 526 -12 611 997 897 -946 405 -349 305 -691 277 -21 663 -139 452 -503 918 38 -820 -69 895 -704 -890 -826 403 653 759 447 338 -202 -104 -609 92 697 479 -558 -425 -540 109 971 696 429 -446 -733 -434 675 -952 -753 538 258 26 -620 785
|
||||
554 -358 -330 -779 -46 -784 235 18 886 20 686 -294 -40 -270 -163 -245 380 764 -105 84 607 216 935 -614 -461 769 -454 976 -240 -93 -741 -174 586 -335 -529 -370 -611 -758 872 -319 774 567 -140 791 -589 415 698 86 847 165 916 -780 -669 979 -381 -344 456 830 354 160 769 222 -558 233 381 -11 -991 -702 -196 865 885 638 -279 -667 -272 -968 977 -726 -233 -59 386 -749 618 -501 -350 -781 -130 353 964 -25 -93 -976 13 50 -213 417 -652 4 758 -318 236 -326 16 -569 794 255 337 -822 -961 -596 -115 322 775 363 -906 735 -81 -184 -454 -810 276 627 917 184 276 922 -630 397 -231 751 72 -188 921 477 50 356 102 389 225 943 -781 754 -813 -839 907 608 -82 609 415 -307
|
||||
796 34 -604 983 335 -175 66 -824 635 -523 630 -896 -475 -116 428 613 310 -183 562 166 -867 555 121 -843 617 235 -30 1 -794 351 -619 998 277 -570 733 577 472 116 -145 -662 436 691 -31 881 -751 831 11 -724 95 -142 770 896 345 924 429 329 709 -687 269 -815 972 292 -972 812 -175 -342 411 78 -255 629 -872 678 -895 -533 -429 -35 965 358 720 -505 780 -514 180 -245 283 -208 7 525 -337 514 91 292 856 67 528 403 121 -70 -290 839 -144 -680 -473 211 297 -838 -191 -815 -753 248 276 696 -479 698 995 -792 -552 790 605 -479 85 282 -358 -448 525 -520 72 -193 -667 -313 -698 -852 -556 -882 53 537 588 -125 -659 -641 -235 279 -80 -870 517 -125 557 -272 -783 -788
|
||||
674 -464 518 965 -33 922 -446 590 -123 -945 -613 -273 108 296 -98 -604 -242 651 749 -64 -971 774 663 -826 916 -606 -434 -13 -65 -179 867 171 -302 -493 -372 -67 122 211 -933 -73 414 -12 -972 -407 -903 -840 -780 -660 -708 740 282 551 374 876 578 256 -427 -239 -324 -917 -906 367 693 502 -847 -170 89 -92 26 -480 740 664 -838 -492 177 -194 423 25 -316 -169 68 -533 979 290 657 977 -68 292 -167 -568 862 -876 -196 -402 245 723 404 434 674 13 768 182 -896 -858 444 -623 -532 668 -232 -718 300 -519 819 -236 977 -199 453 -975 680 -971 717 -608 -279 -864 -233 830 471 509 -820 -952 82 993 -591 -374 -854 65 -595 148 460 769 -515 -729 239 497 377 572 830 -220 948 -176
|
||||
-890 -193 110 -976 -750 -180 -507 556 -851 567 278 573 -453 106 -927 950 722 78 963 -520 935 700 308 68 -856 650 -1 75 869 73 -906 975 -213 -796 -338 548 -579 -498 -733 -381 -62 679 -264 -129 955 321 -922 -766 -384 593 192 520 -849 -309 -105 -696 -274 -92 -1000 -530 -452 758 -736 159 -54 -3 -876 756 -110 -834 -325 -302 605 501 -560 -815 -490 769 -13 -591 916 -827 835 26 488 -5 263 -283 466 873 -774 83 171 406 -168 83 94 423 707 -696 781 -485 -40 390 -647 824 -835 -143 134 734 -913 146 288 25 480 897 -757 782 668 518 326 -922 -798 -1000 539 -430 -32 -982 373 -18 459 337 -394 -814 794 -384 -999 734 376 -826 -668 555 952 764 577 -733 770 -835 -217 -636
|
||||
79 329 927 18 -248 -379 928 494 5 513 703 -480 562 -695 -648 432 240 553 752 287 -702 461 781 60 -384 -631 -993 552 -550 773 33 931 604 -279 -889 -267 352 -332 -353 -599 303 646 -532 799 -921 703 -775 166 -56 -781 209 566 -177 -192 -491 465 -926 813 545 -486 -550 -587 516 211 272 784 -513 128 978 -655 -94 -891 372 -966 -553 -176 546 702 -361 447 656 480 668 -653 996 462 1000 569 575 -579 30 -843 -71 524 -418 -300 -221 -699 -450 -536 952 -451 -820 -9 -293 671 -63 -462 691 405 -888 -880 -280 678 -825 148 -358 274 680 -348 -377 148 -541 -807 -801 802 -662 -68 528 -89 -613 411 -648 37 931 974 -74 757 -337 -408 496 637 -759 124 794 4 -326 -232 497 523
|
||||
269 -862 12 526 466 790 761 -846 -50 -405 -211 -229 -898 979 -939 -886 -472 -989 915 273 422 8 -163 967 710 356 -754 -835 -958 115 -52 -30 -246 -563 -776 493 617 -556 -821 756 -840 409 -487 -618 909 729 765 -895 -896 -786 -541 736 827 92 -248 164 -850 -963 21 411 -329 -295 55 520 637 -381 712 525 672 855 585 795 -237 -845 73 -885 -996 -70 362 869 340 952 911 796 -698 -576 -283 753 119 -661 -206 558 -86 -55 980 -371 -174 448 -588 -683 -608 651 702 -413 288 959 -96 451 277 -121 -789 189 -283 606 690 -430 659 699 452 -23 -468 -293 -951 901 991 849 -851 582 -87 -862 897 259 162 -98 230 -378 246 569 951 -777 -404 484 115 -385 543 289 564 -147 741 962
|
||||
226 695 223 -839 155 -403 380 855 -171 963 -103 750 -830 755 400 -986 186 258 -908 -669 -322 227 -769 -923 -393 403 -687 -54 -423 -738 -171 326 -95 -233 713 449 -537 827 963 -762 -238 633 -962 486 764 -935 -144 -178 -546 -228 549 304 109 837 934 -693 -275 -14 794 300 896 618 -42 941 -27 525 946 -649 130 -810 -669 -165 -393 519 -306 25 -944 947 -650 -969 -376 -965 205 -486 373 110 -231 -414 -689 809 -52 -360 -452 -481 -212 -45 -972 -570 926 242 728 -102 249 370 -691 384 -831 -764 823 -804 138 -843 -943 817 -132 -464 838 -818 -894 911 -258 -160 -99 -966 -823 486 611 -874 -102 -753 -966 -380 -134 227 -539 476 -112 -169 -280 -958 316 653 94 207 -653 472 -914 621 852 622
|
||||
-618 667 -378 -149 205 -345 -935 71 -219 -250 -747 -849 157 -916 -123 881 -57 16 -110 -100 918 817 878 372 862 715 362 942 -749 -845 -597 896 683 839 494 -135 -257 854 144 86 -52 -412 222 -854 297 525 721 442 602 -527 194 -896 839 706 921 -659 -174 -679 932 447 -742 806 -999 700 -656 644 243 -684 600 -308 93 661 495 914 -7 -452 -100 333 254 94 41 382 -590 -32 500 -186 -230 -54 -701 -46 453 -675 757 -416 571 -72 -628 -189 567 331 -148 38 230 -985 749 -199 917 -576 -976 323 -546 -449 457 -455 169 -926 -445 -506 989 159 148 705 805 650 -375 -962 -571 -581 335 -612 -640 -341 -497 498 -563 -444 -749 145 42 879 -71 890 -254 951 612 648 91 483 -739 360
|
||||
15 277 984 -318 -33 -609 19 -742 967 -601 -158 916 638 924 -262 -553 -361 442 996 -331 975 -661 -661 -276 -157 530 -90 440 -532 -416 855 -319 -304 998 241 -195 -561 -7 -69 459 740 -202 -455 -508 -18 -292 550 -469 706 961 -212 897 -644 -867 -788 -464 930 -258 958 -298 -342 -178 -948 -689 -264 711 -700 261 837 937 -715 536 -616 -470 -2 -880 -650 500 -687 47 -17 292 257 929 -588 -507 -496 -536 304 -99 726 -994 330 -490 -548 -135 481 -820 -260 325 401 -397 -511 -706 -879 -937 644 -760 -253 761 -730 -588 877 -651 423 -211 -132 4 173 -798 -938 -529 -365 99 -255 -262 -524 -125 -194 490 923 -229 717 410 -792 -809 -960 -751 -398 866 980 652 -605 191 297 351 -5 -812 701 185
|
||||
-35 -413 879 253 38 -69 -986 2 -683 -185 246 -504 542 429 81 -974 -558 643 -786 352 973 -813 -248 848 135 -777 -219 163 490 -94 -806 553 -120 -208 -299 -603 -926 961 232 88 -993 890 210 -330 -220 761 565 792 509 557 -221 -528 222 -108 -907 602 362 -193 -913 -302 924 612 824 167 -708 238 -184 92 756 66 494 835 -663 -423 -805 -298 761 40 204 596 17 -864 -958 -99 60 -168 617 446 -836 -1000 886 378 -436 454 -562 775 -859 -265 289 -610 838 -680 -882 262 -181 937 -927 -695 459 471 -583 -834 -215 910 -576 24 167 757 835 -578 -441 228 334 816 274 815 -901 -584 -634 984 493 -682 -101 625 895 -56 422 -752 318 -306 -143 -938 465 779 -840 -858 -175 -159 474 -299
|
||||
-683 -806 503 480 -188 580 -645 295 306 943 757 -57 668 845 116 993 348 -71 -719 22 375 621 246 -164 -185 311 -744 -314 358 238 -144 -507 189 -845 950 -682 -8 600 965 903 -59 -584 -312 759 68 -192 906 -694 -658 887 -163 44 -26 483 907 895 75 109 742 15 786 417 540 474 143 -982 -276 -486 -679 862 439 -778 450 -825 465 262 457 -753 408 -571 -723 -93 -36 864 -70 -859 265 -284 8 -63 -908 -944 761 -806 -773 -865 598 -794 789 38 843 292 796 226 24 -481 474 -455 -962 -484 -472 939 -650 -855 881 -521 843 747 895 -266 474 -655 943 -180 211 760 -838 -393 233 -314 421 -314 748 764 -70 996 -889 306 -315 -74 886 -245 -732 -178 -732 884 -129 -171 143 -484
|
||||
-32 503 663 -213 309 907 724 57 -361 128 39 802 408 851 -50 312 -780 -272 209 -992 411 420 495 -102 -792 -294 674 250 -468 563 -892 -448 811 886 -171 -268 938 252 -973 -70 773 -534 192 -211 256 -811 -639 -305 694 -515 567 172 -368 -421 26 838 968 692 785 -350 -753 836 509 -444 409 -128 -909 286 404 181 -239 -655 597 110 14 -973 -857 917 414 160 958 -40 -344 957 26 -852 405 -204 -400 -84 -144 -280 573 167 664 963 -709 488 173 15 63 733 -264 163 -299 453 -663 -57 965 641 987 -613 -547 -748 540 437 -436 -835 -513 -862 -565 -696 -327 328 -871 -804 -210 -690 -482 632 -872 824 -187 444 -282 833 983 -652 -208 -732 562 -738 499 360 650 -204 -902 198 415 -641
|
||||
-627 397 111 12 146 -2 -400 386 -475 797 884 -490 568 -751 -316 636 -72 -961 -29 235 483 898 -38 655 829 519 978 -175 -27 390 569 555 583 -365 -742 -862 991 108 -935 -435 -125 -164 -752 -915 -592 -436 -452 945 -428 333 -362 -502 -31 -863 398 794 -999 -458 -317 285 -592 399 914 323 -183 989 -922 473 75 93 216 912 -585 -339 60 806 707 925 -872 -526 -235 -405 -439 -79 -130 567 -116 802 652 675 -469 966 505 -37 557 146 -492 615 707 308 -727 -327 -826 987 -683 608 -746 -196 534 907 -138 568 23 110 823 -627 972 298 -401 21 784 88 885 -164 32 155 -431 646 633 -331 229 373 188 398 -179 -218 672 -894 -787 -407 -899 71 -968 881 -61 -250 -621 499 -175 171
|
||||
-301 6 -696 5 660 -402 680 -659 986 630 -185 -125 969 70 368 -804 104 187 -464 933 -319 -244 617 -232 -577 -55 106 -638 924 -925 -700 -640 174 462 -696 -863 -947 -806 491 -560 353 -771 223 271 962 -851 755 -920 -922 -519 -247 635 -389 -519 775 -931 180 563 381 767 400 67 -575 538 -355 -594 -960 -338 -872 -273 515 -213 -468 814 407 952 724 951 900 266 -604 -491 -366 702 933 923 622 -833 -19 -502 414 -590 313 738 744 -383 287 -35 432 -17 618 -572 807 648 -940 730 336 782 -969 824 905 979 -248 336 -537 653 938 -595 -684 292 -666 655 -20 -773 317 -394 591 154 216 388 -493 312 649 -987 858 -460 533 173 774 -736 153 601 464 531 -868 -757 -750 967 -231 -793
|
||||
-197 699 534 563 -475 -928 249 -89 932 -787 628 -967 591 -937 -695 -442 226 502 686 289 -24 814 54 634 -284 421 -198 -137 -670 -414 -319 -96 348 -261 -865 640 -815 356 63 114 924 522 81 -708 -157 179 891 50 -256 756 898 557 183 669 32 853 5 539 -790 -324 -190 -580 507 17 0 -956 -437 -813 248 512 -178 -658 -287 339 -69 -319 -797 -813 -390 158 -42 126 676 -833 -72 -462 918 244 614 -72 174 462 477 -377 528 -297 -927 738 427 510 -564 -476 -161 358 -613 -500 -267 -261 -186 796 -271 -354 -815 975 989 -51 812 -119 696 -22 -81 -242 868 254 -601 -341 -203 339 859 -748 158 -703 869 339 -95 807 366 656 -738 -672 464 478 668 873 1 -109 -552 584 891 -634
|
||||
624 723 -597 -755 605 307 -465 -262 825 -455 886 393 144 -589 739 429 757 -434 -951 -687 -78 -460 -500 -804 -882 206 -275 906 854 -357 118 -83 736 -204 266 -827 494 113 -43 750 249 447 620 -497 -418 -826 175 954 -52 782 -996 -957 -174 195 -610 -364 -557 -662 570 -17 -298 -97 230 -440 146 303 644 211 -476 -978 697 -642 -546 -683 377 -91 -86 -211 -438 -574 376 -495 151 767 -313 -787 -778 -299 905 894 -996 76 -71 869 583 503 -302 -466 260 -254 22 679 849 -731 977 944 -775 -94 456 -653 -906 767 305 -397 -614 -338 78 539 -372 626 -399 72 -395 672 -418 1000 969 47 -964 777 -905 -992 -102 906 884 871 547 -375 -46 -587 179 97 -945 -121 935 -100 411 496 12 374
|
||||
293 -426 664 474 -766 374 376 -73 748 -658 845 -158 -270 -27 -363 555 -181 949 -67 -471 -650 699 -812 573 -616 828 -226 -86 -57 117 953 577 -938 408 85 859 701 843 393 -304 50 386 292 -92 -732 -935 330 -83 727 967 -284 160 359 446 827 -272 979 84 -208 -941 -739 57 602 607 487 845 -332 455 226 -847 -936 488 376 -674 323 -967 439 698 -727 -54 -314 475 321 604 516 726 -223 -243 -616 862 -23 175 -634 -591 784 -799 -982 858 639 830 -165 -608 -274 221 -32 -947 -127 -809 867 167 772 -88 906 -358 -777 215 299 316 739 -58 589 -974 -40 -446 174 420 -58 178 231 -837 -924 494 -652 730 -377 579 898 561 11 917 -129 -33 -108 116 -84 235 886 -775 935 -127
|
||||
221 -941 -253 -208 739 -34 164 -258 -741 -944 175 816 671 264 781 -47 -542 974 -200 28 -189 56 359 -330 -678 -791 -92 247 888 234 138 779 -299 -919 -465 50 29 -289 -309 150 486 181 990 -888 -733 288 -607 -789 -897 -289 530 -647 -631 485 -808 -671 -221 -936 -814 -182 -637 -800 -724 -710 747 -730 370 430 397 -554 76 -30 125 938 -782 475 362 242 237 -221 412 963 -204 -462 91 -398 792 -94 759 -248 -624 -264 -74 65 553 413 -151 -455 -962 -312 130 -644 163 833 466 689 204 234 -161 -10 105 754 236 535 -126 980 457 -237 -95 261 -171 328 -301 -856 -248 -385 293 235 773 35 853 -126 290 -523 -871 -791 635 -257 69 -394 -227 -366 550 -587 888 517 -552 12 -644 111
|
||||
-654 -81 228 489 31 670 -877 984 845 607 438 -449 -35 -554 431 520 461 -98 378 -860 -215 84 304 -285 -749 -170 -875 597 -295 -878 218 -727 377 -41 -888 473 -876 -428 517 -691 641 -838 -676 -537 875 98 -285 -739 -468 -542 -638 571 817 964 -611 347 -552 174 -728 191 -130 591 -607 -697 681 -658 602 -191 -511 -607 729 255 -880 468 -978 843 -516 121 -712 -15 -846 -986 -924 -359 350 -532 -628 -215 946 439 780 411 -762 537 320 578 696 -55 394 -412 281 493 -296 -939 412 670 -399 374 -98 -491 -476 747 -578 -769 492 528 204 502 -963 452 440 328 534 -767 932 140 -768 965 -989 -80 -424 997 -440 47 -541 504 146 -322 -16 909 484 794 -158 51 -324 -486 368 567 -884 126
|
||||
-383 -732 -984 397 -166 241 -366 659 131 860 683 170 -774 -693 138 -428 274 -588 -18 -458 382 -786 -972 372 187 -910 117 981 952 87 -306 -74 728 -140 -677 885 -701 -732 -813 556 -546 -299 498 916 157 214 852 386 -681 -68 890 -609 845 952 882 -964 -953 -278 919 524 487 -235 -265 433 595 299 -894 739 -695 269 -507 878 175 472 676 140 769 390 777 -412 -121 996 -119 -800 505 -826 -252 -278 -795 -434 -207 265 -535 475 649 -848 210 137 305 -235 783 -565 639 -143 689 62 660 -523 779 -394 -445 134 -80 -720 -607 -835 -782 -894 760 -388 -703 540 -87 163 -892 406 536 -871 -944 -322 -590 -987 -792 221 202 -470 -453 -859 700 -381 296 302 63 -31 -937 -174 -190 917 -612 875
|
||||
517 926 999 -471 599 -218 -236 -600 726 -526 -398 -591 669 68 -769 948 975 -514 688 741 -399 -65 351 -614 -363 553 895 579 -339 755 -373 243 657 251 453 863 -107 -487 -19 -567 142 774 919 336 -327 -253 -137 -124 304 -369 382 350 915 -129 325 -609 936 673 -131 940 853 -577 -688 -467 26 563 -624 -812 714 -772 -781 273 -799 -824 818 -134 678 616 -471 952 -857 691 362 -360 784 -227 -920 -445 925 -311 262 691 763 8 -298 -963 -299 -315 -587 -779 -98 -595 -620 759 130 73 -257 -859 969 -421 135 -297 730 169 711 -768 -708 -773 -950 78 669 39 171 -420 -536 -485 -158 -553 51 314 -151 837 663 -252 284 317 597 389 -28 -299 -877 -134 670 -340 54 228 -640 218 -548 -11
|
||||
-575 584 431 -614 712 -193 -376 229 797 599 -241 -300 230 -544 -994 698 -740 298 868 998 593 242 299 -240 254 -463 -853 -867 -864 -614 -946 744 914 -501 -575 -178 -102 182 -501 129 -134 -23 161 520 485 514 74 680 -19 256 -600 -70 -284 -327 44 -224 664 243 71 -476 122 184 836 -115 -489 -149 13 765 -923 -348 -223 -768 764 -112 -164 253 -135 626 4 -149 -887 646 112 81 169 -339 393 -922 37 -601 607 -408 -599 722 884 709 -135 899 715 810 -341 64 179 351 736 -822 391 -555 -995 389 899 -227 730 -474 -214 -718 -65 604 295 -173 167 -506 -665 442 662 296 528 -401 790 891 -980 277 832 610 342 -759 -444 396 542 127 -844 614 -505 -176 783 -933 -938 -105 880 -505
|
||||
-373 676 -987 -990 86 -295 378 -787 991 -329 89 425 -825 474 -121 169 -681 607 -781 -880 711 758 -418 -697 -793 245 658 -707 -439 -806 275 -433 -258 -882 -621 -326 869 933 103 -659 277 -674 820 205 573 -520 519 -486 855 329 -924 8 605 211 135 -989 -902 596 -871 -420 -968 -181 -209 -60 -908 -644 701 696 580 -276 -891 268 965 -896 -438 -634 -440 -976 -914 -398 -372 26 867 -797 -216 -809 327 398 -527 -441 421 -642 -103 91 -743 -644 883 -361 287 342 168 348 -938 872 154 -221 918 -820 -714 -875 100 830 -496 36 408 -369 -568 212 -111 -46 -217 -354 -292 -201 -328 -988 -39 -712 -498 516 -190 636 218 -435 427 -651 -596 969 -647 886 356 210 -582 311 59 -271 -190 688 -712 358
|
||||
-399 -703 466 -876 836 -983 813 853 -15 975 -969 -449 -716 544 -462 952 -327 -592 -653 -275 58 47 -929 887 -505 266 -920 653 292 -467 180 -788 -159 676 -516 887 396 648 -532 -424 442 966 894 348 181 -604 -994 -269 506 287 275 -278 -343 -955 329 -259 -461 634 -656 -39 -250 -838 -18 334 969 894 420 -369 614 189 862 917 990 -420 712 -565 -648 -397 142 -441 701 900 -989 790 -527 925 -467 -925 160 512 -576 370 -311 288 -937 -299 -161 -546 -559 632 385 165 927 818 -873 376 106 -670 -32 945 -544 919 917 -705 -790 499 466 -98 -572 -668 -438 516 -85 -510 150 203 315 -503 333 17 -698 -449 474 -281 -546 -45 -879 743 -156 -325 -195 108 936 -748 -747 156 -350 123 396 712
|
||||
350 -516 771 -178 -914 55 -969 353 -304 -515 -294 -511 -177 -822 -531 61 -604 163 -752 -559 494 261 -797 -376 437 -258 -968 -457 523 455 -779 -835 -434 -143 328 -981 749 402 369 -601 -527 977 561 714 -962 -864 -781 701 645 408 308 -313 -768 -870 -69 985 -358 364 744 -711 -763 -178 -474 -205 -211 382 -218 -34 115 -400 840 -500 -86 93 908 378 -127 -51 -458 619 836 873 -352 -418 271 943 -262 -397 744 -520 831 344 994 -153 88 774 134 -904 873 -138 -399 188 -855 440 -325 -735 -272 -380 772 -130 -288 -498 828 612 537 438 822 -554 -287 147 738 -965 -924 -768 424 554 -441 994 -719 998 -656 -522 447 192 459 983 -361 639 -278 -16 -588 -376 355 -123 29 -497 -998 92 318 679
|
||||
843 -528 98 -883 392 -517 -240 -645 -44 614 -884 -52 249 -63 -755 669 698 625 -95 316 -508 -956 314 -122 197 -553 566 377 -910 725 -824 -12 64 35 -164 -489 162 -413 341 827 -207 -207 -305 -440 549 -916 409 -540 130 -469 950 -853 -691 -926 471 -83 -259 416 -525 682 661 129 981 688 206 685 281 -19 -690 -316 569 873 3 277 -93 -229 665 559 -349 759 546 63 -82 -140 -856 -803 -949 733 -358 -294 559 139 -256 79 718 138 369 838 627 -237 -642 -849 474 -946 -804 -568 -223 -618 643 -665 -14 789 -119 67 -242 -490 688 -374 -436 489 -390 315 429 286 652 -735 -39 -952 -928 -806 -964 -267 297 -735 -115 -92 -22 -196 -433 -419 313 927 401 -886 853 -264 -845 222 198 946
|
||||
803 -837 126 320 540 71 -453 -795 -475 773 -727 437 308 -414 -649 -738 -653 -967 254 199 421 407 985 -482 -415 -68 -899 992 -757 -989 -45 481 -16 659 -284 748 380 -911 767 -977 518 164 -631 182 965 918 -330 -190 527 447 210 -127 307 155 -763 -383 333 430 729 288 289 -345 469 5 -149 994 -381 -691 -957 -947 -254 656 -301 826 -113 866 27 302 -915 -58 -233 -359 585 -916 -834 -413 -553 -857 781 660 723 285 -642 606 -349 681 606 -197 306 895 -311 300 830 554 -720 -812 -353 -762 136 -250 -87 -729 16 -782 -222 -58 -231 -551 442 -465 627 651 392 751 -763 712 863 461 -420 133 -448 -1 -493 -102 260 -321 253 272 431 -330 -162 95 211 -718 176 -832 536 858 764 53
|
||||
-415 -19 217 112 -674 -986 829 490 -476 -535 -812 -371 629 11 698 -298 -960 559 288 139 -729 734 -601 360 648 -813 -807 851 -469 671 -117 779 -1000 -351 -638 -824 21 338 -448 -41 389 154 804 -997 252 850 -798 -681 697 201 812 106 -329 -929 329 404 299 226 285 576 -202 392 953 681 497 707 -109 324 -221 -339 -33 -424 84 871 530 689 745 928 243 -639 468 217 -524 -206 -800 130 575 -223 0 -694 -535 -595 983 164 -722 63 532 404 -774 -476 -215 -639 468 437 -993 357 530 579 139 374 -424 -944 602 -212 -36 80 607 -260 571 -16 -751 -574 -720 -120 290 165 289 -420 390 341 773 815 55 -127 -218 -687 239 -287 -881 37 -772 631 53 -720 991 -465 21 725 -763 -665
|
||||
-827 -665 -733 -200 -592 427 745 527 -50 384 -492 708 928 -664 -919 -140 -212 233 702 347 236 124 849 -134 194 288 -93 -15 288 -662 -395 -468 -787 -336 224 -597 991 31 -610 818 -822 -16 928 -290 387 901 797 -286 611 537 358 242 684 -780 -177 828 382 -72 559 -384 160 -864 642 702 312 -142 476 -134 832 -700 -206 -331 -27 710 -431 349 -725 433 -302 -800 -605 481 -662 -862 835 -100 -747 -113 -594 -734 -734 -552 -956 -737 -766 -280 643 464 -74 459 320 -635 -138 -17 533 -626 283 149 -204 -381 -80 741 60 393 -820 -359 249 840 681 -680 -492 390 -64 -154 -186 -483 436 -660 478 -115 673 886 -460 242 280 -926 948 612 806 685 -276 364 -591 -499 239 4 -755 -651 -559 -788
|
||||
967 539 -590 47 -804 421 -254 -4 115 -345 909 -565 -822 623 -246 966 237 202 898 338 643 224 -870 -644 393 836 767 -965 51 -83 389 456 -651 691 -825 607 -100 -774 839 554 90 -534 -557 334 831 -595 -861 -140 465 -399 -997 -712 645 837 378 -289 -267 -723 -279 -22 -500 2 -93 885 852 -743 612 -282 -501 929 -641 -422 431 603 -883 457 -183 -32 -374 679 -438 269 -529 -500 -621 660 121 -150 -875 762 -820 994 331 290 529 -749 116 -767 -956 250 597 -680 -454 -985 248 -180 -683 -141 -839 -416 24 503 -643 161 -187 -588 921 885 146 753 872 204 -829 700 42 -59 447 977 570 531 -841 -525 437 -103 50 736 -118 -644 -359 780 -575 723 350 -515 293 -602 642 -342 -482 -451
|
||||
51 -570 -979 566 251 -715 160 642 -530 -774 485 926 235 344 -572 -133 560 171 180 204 151 -51 213 -728 292 994 -431 -616 -843 784 893 -760 168 -357 -719 510 381 892 -123 164 792 -795 709 186 843 676 -560 -58 899 239 475 -478 -417 784 -6 926 999 -259 -640 -262 -897 -544 869 -827 513 -706 -739 -93 -280 -128 785 -781 -511 617 -733 649 382 -761 772 -564 -573 -521 -324 854 585 567 987 -737 60 -394 -932 772 70 -138 529 -75 -309 357 -369 -543 267 -934 269 -817 857 -431 120 541 191 237 106 329 143 940 765 233 938 423 -807 914 44 -494 -401 -688 500 38 587 307 798 638 -519 -537 -270 -252 34 -191 213 -888 -692 353 -523 -236 481 -785 -316 -263 793 -230 -652 729
|
||||
-428 -865 116 690 764 -658 233 -689 -73 -938 278 118 745 403 859 669 961 414 -536 558 218 308 -239 -967 -411 -820 859 4 136 479 757 36 -821 -286 -871 -823 892 -916 -463 837 -668 444 267 549 395 133 826 -408 -664 -90 -995 49 217 903 -993 -876 813 -152 404 630 -566 764 -133 -358 959 -535 341 -661 -108 -898 826 450 -161 512 895 -1000 -130 733 -237 957 886 975 443 -991 -52 -160 -625 -743 240 780 -954 -286 -956 440 689 -576 432 -782 -899 -596 15 96 57 -278 -132 50 911 601 -961 -396 -349 364 -763 787 758 230 -341 666 -433 -505 -526 949 734 528 989 49 -518 24 704 -278 192 852 728 813 -466 348 -913 0 -862 268 -928 827 -553 382 -402 -115 510 -157 639 41
|
||||
264 561 -690 -909 -667 107 539 155 578 881 -46 293 -290 259 96 -48 578 -484 736 313 212 771 776 -122 642 945 -651 567 -909 -390 947 -30 676 477 739 761 140 743 109 -169 -394 840 829 -757 -340 270 -295 606 -827 872 944 64 278 615 -977 247 -86 614 -944 -454 -605 -553 918 901 -601 -607 704 277 852 -841 726 754 647 -817 816 849 -917 566 -236 -587 -658 -683 -221 340 946 -880 -840 -801 -270 887 -249 694 -47 132 27 -25 -532 -636 -892 283 -45 -455 -248 -844 232 563 -510 704 -104 775 -383 -483 942 859 623 125 574 -443 888 824 18 -276 -634 -364 -349 336 -529 -863 -54 460 -897 -18 -816 237 196 -989 -627 498 976 563 524 -293 -91 -457 711 65 -270 -495 389 -667
|
||||
-4 985 729 72 -396 -7 567 428 928 854 -901 -580 912 214 -121 288 -748 -635 292 566 53 887 775 735 -316 987 247 779 -743 739 -423 -525 646 181 1000 627 -889 -951 -534 921 85 623 396 -175 -687 -438 697 -716 -49 -451 -538 683 -502 751 430 350 -855 439 -958 561 -438 -768 644 -67 -311 299 -114 567 206 319 -388 -910 764 257 -307 -117 795 -854 153 -80 -380 -546 384 -514 228 -951 -950 181 199 295 338 -357 132 -630 -229 697 586 -299 -721 813 47 -157 935 -510 402 631 -483 -766 205 496 354 -179 -536 -399 -442 -523 -135 -770 375 -148 41 226 366 -69 143 -170 971 -975 987 -812 -324 863 -763 -821 -348 -415 -635 -50 -342 -915 604 -982 982 -529 865 -860 -307 504 16 -237
|
||||
313 211 781 812 557 368 868 -469 -43 -696 -404 71 -744 342 754 795 99 -891 767 446 -987 567 -660 -419 333 997 -244 844 -794 -571 276 -635 -872 -364 -433 363 879 266 518 86 -733 685 -799 -211 366 318 275 78 192 -201 -461 766 7 -794 -131 886 -578 709 116 -283 -430 -254 -24 787 707 -175 -439 454 -865 -279 366 -123 805 971 -521 -804 516 -354 -642 680 -233 -854 183 671 880 996 428 551 -851 612 707 -650 -157 -945 764 -550 157 227 -397 -608 91 813 -221 265 85 -512 750 401 -464 -433 -421 -225 268 368 930 653 841 833 -562 -480 2 -139 46 374 -797 26 -731 -563 2 330 799 -820 -233 -469 650 124 680 -719 -154 -243 -633 -810 -24 -496 434 254 -374 232 614 -88
|
||||
726 -265 -841 -18 -767 637 -112 457 972 -871 343 453 343 -498 -772 980 949 -397 685 982 -147 -186 331 921 -117 -791 926 667 486 66 382 866 -969 716 706 884 318 -569 -792 555 -656 972 -342 -412 -278 -600 -388 -883 983 -517 -739 -278 -796 101 -979 233 -381 -437 368 -108 76 421 -665 -372 -795 -650 86 -19 -263 700 -427 540 263 882 -970 463 112 -956 551 -636 -924 825 780 -590 764 -91 -127 392 224 -494 -248 69 639 -537 -816 -249 -447 -181 -765 -782 195 -445 -402 -436 319 484 248 -880 -572 495 533 859 -115 149 909 -575 842 968 -374 -804 -57 555 688 -274 106 448 -324 323 747 -276 -877 676 293 -94 287 899 -599 82 -403 891 -592 375 -934 3 -743 -375 -562 -381 632 -460
|
||||
910 -811 -186 230 -161 803 2 -47 -123 -552 -371 544 755 682 -536 630 635 -429 110 -656 479 -453 631 622 864 -386 40 -619 520 306 367 888 999 -362 632 -879 997 -667 -247 -235 -313 925 -833 -266 -249 -651 684 -388 40 967 777 -751 -494 213 -554 -277 -171 -554 157 648 -301 659 145 156 882 659 762 -835 -462 371 -155 62 27 -714 -276 719 376 -806 -889 -234 -337 -695 -416 545 -646 0 -213 -977 -808 992 -63 -988 -448 223 731 946 -744 -512 -590 -940 314 -206 321 -70 121 -138 -352 322 -932 277 323 48 252 -219 931 479 912 -364 -573 -23 -348 -771 -891 -592 613 282 258 -917 3 -899 953 -824 617 -239 926 898 981 75 115 -661 495 -31 335 786 -293 -683 -837 343 254 37
|
||||
-294 683 861 -901 -351 90 -935 -529 213 -660 921 739 -559 -463 92 -151 755 -490 -251 -534 342 -913 -988 -308 936 480 630 299 -521 -894 -396 -182 -255 -659 -680 -342 851 671 -831 664 -314 -374 744 442 777 -778 689 -818 953 -357 880 431 44 692 -346 -674 689 -919 -623 -480 -634 203 334 -456 396 -839 -522 -77 407 -605 509 -356 -16 -209 -766 533 -729 -630 252 -131 -653 854 814 746 976 -847 656 -391 -756 926 -377 63 -568 -228 -966 525 -494 -906 239 -824 564 561 684 599 621 -398 208 -16 -714 -560 -112 -169 -277 -427 621 829 -406 132 879 -3 320 181 618 334 143 -471 77 735 516 -758 -494 -145 -335 844 -751 -969 -422 272 437 -78 766 450 315 -968 843 287 -183 870 -297 -463
|
||||
744 -910 -792 210 -75 -255 -492 -883 -213 -88 398 214 619 360 -41 54 -510 -374 571 -946 -217 -469 535 -492 -139 824 690 289 -603 -86 -389 211 684 -626 -590 307 -380 984 -946 316 639 957 387 762 -156 174 -103 -800 -342 -853 -165 623 -61 -888 -946 124 802 71 -297 830 -569 -840 -889 536 403 -171 -784 -730 295 -909 -663 263 -830 -396 -926 -421 548 814 346 106 -689 -214 -286 300 -68 -373 -120 262 716 -94 295 645 -577 29 -715 530 150 839 959 520 14 211 -211 -612 -968 670 -959 701 -875 -349 861 319 618 699 731 364 198 82 260 796 -906 -808 968 -813 -895 -810 185 368 -645 -595 236 60 405 833 -926 -74 -693 555 450 193 915 -421 -2 967 -410 -845 -951 -235 -669 -987
|
||||
-588 482 -239 977 -509 -599 -278 -709 -850 398 699 -310 -337 113 819 228 -489 -189 644 948 712 -882 683 105 -994 -45 -264 -192 83 332 41 -450 957 -301 -215 -854 -773 745 -658 -810 29 945 -758 589 -415 -722 699 -37 -323 824 -781 -24 -992 -899 -716 -602 488 -140 379 246 520 -949 -149 -797 -924 749 -611 -483 11 -804 -303 64 910 586 -685 55 -147 -6 642 -707 -36 -800 -834 -272 -814 -259 -541 769 733 69 233 677 -435 988 -768 -828 -233 370 690 384 -925 16 16 232 -76 -363 -716 -215 746 89 -422 160 895 248 -43 440 -532 -357 945 -311 -107 -225 -19 -780 -826 -348 -562 480 439 -601 -919 348 -283 160 -115 -456 116 -777 197 -838 407 468 -435 331 489 -155 405 273 960 -399
|
||||
-660 -413 -706 -703 -356 48 -373 146 815 268 209 816 673 -150 -597 27 731 -920 -715 -444 295 -474 -80 562 424 -164 790 818 -837 879 -816 511 85 619 826 -359 -308 669 -106 461 -166 386 -826 -340 -316 -741 -22 878 873 125 -125 -703 62 -96 374 811 -373 -915 -754 -772 441 -983 -166 -193 -58 -261 -76 -845 -767 -171 511 339 -247 102 -309 -85 67 864 -5 433 230 -970 906 -663 749 916 996 391 741 -384 525 693 -211 -695 -152 -129 420 761 -885 675 -21 348 -396 615 -2 735 766 -879 697 260 426 -206 477 297 909 -870 -832 -215 785 346 -242 -837 -193 829 -413 -291 73 -60 -686 226 -473 856 179 -24 658 959 -349 -769 -901 -375 945 -620 -152 -47 -667 265 -538 552 231 123
|
||||
89 716 -489 727 719 446 127 -628 552 -815 502 995 181 -252 -895 -687 582 -182 -542 260 833 805 -423 628 362 753 277 939 199 -711 -199 196 137 391 -897 -298 -953 -56 -809 313 836 -807 -42 -304 919 428 -61 670 7 -303 606 -156 -870 -766 822 -296 529 -333 -283 401 200 -259 879 -480 444 309 -467 -824 922 815 571 668 792 -212 -812 874 963 -516 -389 613 -668 -34 480 39 84 -121 174 792 -417 335 -75 962 -641 -136 -604 -831 -696 223 -276 815 771 -532 370 -519 -350 -391 289 -60 656 211 -803 41 254 459 230 -778 585 207 -616 165 -902 -943 -648 268 -32 212 -178 835 -405 -616 44 -546 -307 -13 614 -577 -888 -853 -305 -992 550 -361 -410 -524 -791 721 268 464 -94 -139
|
||||
523 -55 677 590 -526 1000 921 -670 539 289 -153 188 -977 -448 616 519 518 301 633 -293 -706 -208 807 751 -301 897 -346 -505 -146 472 467 -130 667 461 -778 495 67 275 -63 -517 939 -358 854 535 188 87 110 444 -309 -768 -988 482 -604 -605 -499 -620 779 -449 -229 -223 -364 891 -858 297 904 209 546 775 260 -44 -5 138 262 836 408 -770 -948 869 217 -220 425 582 956 79 -26 -511 301 -87 83 -656 -81 903 299 508 167 925 206 336 262 -541 939 929 -757 247 -227 844 -421 -467 587 -897 -135 784 -407 -874 -221 -857 -450 641 -798 -698 734 -439 -393 -131 -611 776 -661 -240 51 -685 867 165 -417 -91 -607 -616 -907 962 648 -300 -387 961 590 754 -5 -748 89 -922 400 -919
|
||||
-762 -532 -339 -759 -619 -546 -622 -208 -709 -974 392 957 -450 -744 -897 960 223 -651 305 -561 236 372 895 -514 48 58 560 351 449 387 -826 955 -294 -881 -397 562 203 -150 -416 978 770 795 -17 -736 497 -214 -910 -601 -876 -380 105 -456 994 316 -417 -607 764 487 -302 -258 -300 -973 203 -814 657 96 -823 759 922 720 -942 856 -867 994 -741 -778 114 -125 -70 -672 516 502 473 942 74 913 -208 698 -384 -113 -227 237 -162 -65 -891 -689 377 -98 243 637 675 -203 345 -962 600 693 418 511 984 -161 342 518 831 -913 144 774 777 268 -215 -744 404 -92 -173 315 -123 612 664 -144 -741 266 541 -994 897 -369 -255 894 -183 90 -297 117 577 -931 676 590 -994 746 -773 -771 -963 -460
|
||||
92 -634 -771 -717 -407 -230 -374 -353 -144 556 -363 593 -779 983 816 290 -324 76 698 379 606 375 -912 238 -310 -444 -595 -983 -828 535 936 552 505 630 897 -293 655 -525 65 -605 591 99 -78 67 -121 -640 853 290 892 -506 -809 -9 -988 -136 700 831 -812 5 879 -114 -660 -677 -481 549 988 709 517 -482 872 478 641 -271 856 608 418 -20 -186 -485 313 -729 746 -235 -138 -484 599 856 462 274 219 -936 -230 -108 -726 -322 -539 -322 -326 -291 -874 805 84 403 104 -308 6 701 936 289 920 -841 310 110 -582 29 643 975 154 -89 648 -670 -760 -738 453 730 281 143 -436 232 -423 140 228 -547 618 1 11 -670 615 38 976 -730 302 847 183 -696 -109 -150 -882 99 521 -48
|
||||
-968 -766 -372 993 765 768 328 -956 -727 -958 -844 92 -280 157 394 388 -532 991 -336 -879 -408 -974 611 -122 498 -118 -41 391 -366 -780 230 234 155 980 998 522 384 316 -553 -247 -454 317 -763 -444 737 -656 122 204 41 144 -289 797 495 909 -232 -71 242 455 541 -393 626 320 580 -433 69 242 -207 -751 198 -132 315 950 -269 919 809 998 325 761 -119 348 -408 380 585 333 902 345 -558 246 -935 627 -483 791 -650 170 -300 -471 802 238 -266 449 918 -969 -705 729 266 -376 942 365 -818 -449 -566 683 413 -528 -266 -569 436 -656 -10 -638 662 -722 74 334 188 680 -96 -920 -195 112 535 496 -251 -757 -732 -442 877 764 399 -554 890 907 85 531 -873 305 427 -451 986 374
|
||||
-286 -345 668 321 657 -483 -168 125 72 135 960 -51 571 -949 -841 161 395 324 -862 -214 662 991 412 -160 -814 579 -262 -719 151 -87 -986 -671 -41 -282 859 -536 865 80 155 -295 -146 561 495 377 -514 504 403 -470 13 650 -546 280 -957 -838 446 -386 -928 -421 493 96 450 555 -315 -631 -391 -605 782 -337 262 657 825 -159 543 -566 616 219 -596 989 595 -926 147 442 965 -912 -753 391 -563 791 -774 855 -286 643 -532 -948 -43 328 -687 172 536 848 -824 320 975 -389 148 605 15 -39 634 -246 -257 180 436 229 514 -640 296 79 -393 -85 -311 107 723 895 -430 644 -827 -336 133 -37 286 780 -30 -751 168 236 182 -359 -116 -976 -729 835 -966 -136 59 -203 224 -19 734 782
|
||||
-218 596 61 -511 -778 889 1 461 422 -357 -570 983 21 -481 -296 737 -867 500 -449 -215 849 190 -591 137 986 442 -976 -437 864 689 123 -37 59 576 175 941 319 -170 179 -451 738 -558 634 -5 -217 -19 270 642 231 916 820 -803 -847 -259 -957 865 -836 -90 -422 -551 -385 347 -860 -565 -194 666 851 143 -587 117 746 -738 325 372 -599 885 -680 -821 229 -597 830 -141 -582 -891 307 455 -915 -384 -528 604 -836 954 -429 -165 -458 477 -806 -463 -820 -125 11 638 625 870 -852 557 293 -953 -700 233 249 -745 -685 585 -449 637 402 381 139 131 897 -75 717 -992 484 831 -229 983 530 -995 -799 -799 -221 -249 952 787 -377 431 -58 -345 -365 550 608 353 -396 -912 671 815 -64 277
|
||||
968 -763 -894 423 -209 606 -238 915 719 454 -327 -525 -281 84 919 288 -841 -628 529 306 794 337 -45 299 -742 -238 826 145 545 410 736 -919 -899 636 430 241 568 711 -187 637 -325 -620 591 -704 -817 -288 -448 853 -947 753 -108 -348 432 984 -687 -319 -860 441 -989 657 -782 -954 150 -899 -951 482 -878 -821 -517 -495 618 -861 67 215 724 328 -451 296 396 13 323 63 412 -407 -764 -8 -411 -726 128 -781 137 -259 732 -828 -496 634 369 -420 748 202 438 -871 384 855 -9 -749 166 603 -441 -18 -145 624 579 141 -369 -600 -325 -579 -824 -409 -636 -149 -698 473 -902 -604 112 -599 -992 542 -233 -978 116 213 19 -75 -738 754 -42 517 366 499 391 -880 924 -171 -353 -887 207 536
|
||||
-750 441 -711 476 333 -203 -345 -993 -366 637 713 186 18 -339 909 849 -697 217 77 599 -184 441 723 -257 560 584 159 918 -104 284 -835 27 833 32 975 -517 482 376 759 -619 876 -656 99 777 -955 69 360 -888 -210 -504 -808 955 -461 778 470 -457 127 -899 171 271 -157 -12 -808 309 648 915 102 842 374 -43 -62 -526 -938 -241 470 641 -363 -405 676 993 920 -306 127 149 -789 759 -561 -91 660 743 -599 662 -370 -761 -773 894 -227 -355 -621 -219 -487 -673 -490 -561 774 960 825 -328 -523 -73 655 67 -78 -145 127 428 52 -220 954 -96 -576 -404 104 263 -669 35 639 -206 -922 396 116 363 645 -273 -748 -125 -336 877 -410 -665 130 -373 -312 -238 683 299 128 874 -725 19
|
||||
-345 246 -515 -204 -622 -135 502 153 350 631 -619 -660 -844 -708 476 -589 -153 -457 360 -180 874 89 -93 517 -328 839 690 -951 -207 -616 974 352 -523 57 -706 392 352 267 112 231 -444 -331 -403 868 391 944 -708 361 262 659 -726 -972 132 509 491 942 -85 -77 -525 261 -137 902 -394 -245 845 790 -477 964 711 -629 677 -500 -779 147 826 -567 568 -430 249 949 419 -166 -574 387 -614 507 154 841 803 959 -813 260 -995 955 427 -904 -257 -56 277 -477 -48 -341 -369 456 248 -24 -21 321 123 136 472 -194 -631 -221 342 -62 -375 -353 -981 -231 -890 -108 307 -693 713 362 344 -469 242 -158 805 -2 656 651 -556 698 -166 192 -628 927 582 651 -835 107 708 -460 -99 675 121 -487
|
||||
365 -905 -255 -261 819 393 462 -508 -479 -715 -153 523 -727 665 -400 -123 909 -202 444 -306 -426 -811 63 86 -503 -539 934 -568 996 222 -232 701 750 379 -591 199 -544 -58 -659 743 -937 662 686 105 532 -397 -28 891 -278 4 255 -250 -740 659 470 965 340 18 -196 -539 864 473 -269 21 167 812 -184 -270 740 341 -662 360 764 990 -578 -804 697 -13 -403 -10 -12 869 -334 626 112 -678 -752 -614 -530 -610 -73 -198 -763 846 -978 -275 605 722 842 -956 975 -777 -824 -773 718 -205 -684 396 -544 -553 -645 -658 152 613 -967 -667 -913 -294 -979 -746 864 -574 432 124 335 824 747 638 -467 -763 -457 -232 750 503 -85 650 95 -841 15 501 -835 174 961 -422 157 -283 241 83 -417 165
|
||||
-614 -660 363 121 -869 -696 -506 75 -653 -795 547 -498 845 -723 641 921 552 603 -395 -518 -140 525 -534 265 399 -145 -295 290 -617 -207 -78 -938 246 653 -164 717 -252 -971 83 -673 995 38 216 576 739 758 762 203 -125 -470 519 -318 -909 282 -14 -480 546 224 -8 0 167 -929 -255 -581 847 373 -299 242 -628 202 148 900 -994 -556 -818 -478 459 -950 -409 492 -513 438 -991 887 800 34 291 -105 169 -973 -364 423 254 460 128 -664 108 -897 251 956 501 -89 133 -810 324 -914 772 -953 787 -35 -888 705 -299 445 -898 855 385 315 -94 396 -33 175 214 -320 83 -129 -418 623 147 -784 -340 -286 -232 -34 472 -191 -321 746 -785 -980 952 831 -309 -528 559 201 -959 -702 -131 482
|
||||
355 886 433 773 -667 642 896 590 -983 860 -172 -599 230 819 -676 -638 235 -636 118 656 -355 -707 -213 -89 -464 -102 -435 693 386 -598 270 759 177 154 388 951 86 673 -33 618 60 445 712 71 925 -737 26 273 768 -460 -327 592 -651 885 113 477 356 33 -581 65 -911 880 395 -498 803 -937 869 12 -186 981 -282 -845 -912 -840 -816 487 -213 -492 837 683 447 -986 532 672 421 790 -547 114 -116 -127 -199 616 -186 10 -696 -750 560 -563 -549 8 455 937 -141 732 -833 -635 -857 256 643 665 169 105 747 -86 833 443 -196 933 -933 -716 -292 -972 614 953 -632 -529 219 149 221 -352 168 237 695 436 670 213 696 549 -729 795 764 132 -612 901 624 -246 -248 -788 -355 -853
|
||||
-633 -727 455 -332 -825 485 453 -850 -204 135 985 -664 -152 164 780 -14 944 14 208 -118 460 -727 -407 992 -759 403 789 -827 513 35 681 -772 612 -197 -13 -241 209 -119 634 541 415 135 -665 114 560 -307 -734 746 -637 799 779 179 736 787 216 -55 -648 -926 204 -256 -186 102 -975 -466 751 200 312 -534 -864 -956 -570 951 381 -624 -442 -562 -615 -680 -924 -625 588 -679 324 728 786 553 63 -959 352 562 270 330 413 -7 982 -423 -596 556 -549 -454 487 -800 809 29 207 -565 -902 171 213 416 -590 -950 466 -640 867 837 -426 992 -957 687 -417 -202 29 -969 440 -174 -424 -151 543 760 293 -954 901 -743 -552 805 -415 -598 103 592 -155 908 -271 584 391 866 -641 -829 766 92
|
||||
-402 554 299 164 618 247 -123 -763 165 -904 184 -265 -129 -829 -666 -572 53 -335 316 -606 587 796 4 853 -111 -914 588 377 189 348 -652 -618 -467 -120 -827 -41 512 -272 -422 -279 -347 -785 215 165 -254 -37 -204 674 48 460 -261 988 707 -588 -977 -810 578 -842 383 -535 -805 -795 -476 -664 -202 873 -756 230 -481 761 883 -890 833 -20 625 -612 575 -913 666 -992 -899 -452 98 -813 367 286 -847 963 -441 168 401 -63 -819 46 -568 -14 -121 53 409 -889 -301 727 520 404 226 175 959 28 896 880 -434 -818 -120 220 -923 936 924 -905 997 920 -227 479 -492 118 612 416 7 364 -951 -451 -106 590 49 346 723 412 -909 906 -660 63 820 220 639 259 327 -860 -236 -631 395 250
|
||||
-169 389 -113 -59 367 -745 687 -750 -656 44 711 331 509 601 19 883 -548 -716 363 635 -335 -613 -929 868 609 164 -272 55 643 923 -288 240 -341 -449 226 -963 449 119 -639 -792 -742 -562 342 478 558 -487 -710 109 -695 174 -440 -184 -787 221 -241 925 831 392 -594 -624 978 -828 -587 356 -426 346 756 975 -82 -861 332 725 354 356 -656 194 31 -14 -482 -214 -291 766 957 532 197 420 275 -410 -29 394 134 891 -101 558 -500 955 748 886 759 -165 592 23 450 -730 679 -900 -152 20 362 -718 -891 276 -300 856 -883 765 -40 -316 -720 -136 644 -260 899 911 -79 746 -199 209 -157 104 214 -514 -839 660 707 -932 986 -904 472 -706 -134 471 176 500 240 -838 322 -43 -205 -409
|
||||
-819 918 -865 -428 -333 455 -182 825 348 -80 303 243 20 554 -121 284 640 629 89 -192 186 -468 -466 -791 -485 -437 -917 -727 260 700 664 -132 -595 -252 810 -610 821 -255 959 193 -407 -558 -936 735 -867 779 558 981 -466 -568 153 961 -575 -740 193 954 -34 -947 256 -926 704 -770 -492 -693 -82 259 297 -190 -797 -991 596 485 607 624 918 -166 -899 -547 -99 -718 -879 209 -913 -354 753 -480 213 -273 494 -361 148 -868 -356 -850 -199 279 414 -827 669 -558 -967 -305 -502 836 -514 -392 424 918 416 19 33 855 628 255 -327 -229 -236 -294 953 -403 -391 251 1000 -762 -335 149 -982 250 -804 -80 -600 691 951 4 923 -744 -982 438 74 102 -934 686 -807 -678 209 -82 267 628 -314 -350
|
||||
-791 -1 435 -135 743 444 997 619 9 -643 -894 -996 -268 535 -56 386 329 255 -672 840 -597 -312 -653 -860 -751 -110 -113 -740 105 982 -839 -138 683 350 671 -343 -371 861 762 -723 -976 -235 126 56 -897 -374 9 148 -604 -411 -476 492 599 -806 -553 -902 -275 -243 -93 885 374 860 512 -495 841 -355 -972 873 -322 -462 381 -392 801 -709 890 321 -838 -257 65 -277 592 -796 -221 -356 776 267 126 804 735 41 -152 -789 -18 -471 435 12 161 -595 -358 -271 -512 -784 221 -638 955 -392 740 -135 586 652 146 -983 -903 690 25 -468 -444 601 928 270 753 939 106 -805 829 204 -210 -744 -689 -815 525 656 -465 87 678 439 -136 -697 799 673 332 988 177 293 -619 537 -930 -35 -452 532
|
||||
-42 899 18 -287 801 -7 -335 330 -469 558 281 -615 -266 932 724 -459 -386 631 961 -203 -74 746 244 -471 155 546 179 -720 668 -863 -992 888 -608 285 -681 -696 -516 875 475 991 473 -34 481 418 -475 -280 747 781 -557 -742 -887 -75 235 200 898 -730 351 213 -197 -619 117 -688 665 48 -909 -150 -829 714 -534 -195 53 807 -897 838 -794 467 89 638 -381 613 -422 -907 259 129 -445 -711 401 -332 933 -995 427 811 -464 -415 148 19 -620 832 687 -697 755 660 164 571 140 -24 -770 -753 58 -584 141 28 -961 -882 115 -166 465 509 849 -60 -509 -278 -222 925 397 -505 -533 -365 701 953 -964 -428 822 -824 -288 310 681 -667 -753 -127 -510 533 -333 -533 -631 861 -121 853 -582 97
|
||||
-922 997 807 -668 250 22 -668 782 831 -759 -171 347 809 695 -626 484 -608 992 802 -503 -391 -157 -463 947 639 876 619 934 514 823 -293 391 -722 31 758 715 -222 -281 -442 14 -889 -147 173 -972 10 -240 927 425 208 -635 -454 49 58 573 -939 260 -237 -766 608 204 328 877 588 241 191 49 -996 574 346 -512 345 -680 613 972 674 -228 4 322 -391 -516 -903 -922 460 -399 436 59 -480 628 -164 -625 186 -90 731 29 -595 254 -932 92 127 -675 -504 39 296 -900 -81 22 -182 -282 612 986 -11 -141 994 -312 792 260 -826 16 153 -827 -286 115 -357 529 129 -336 734 -42 101 828 861 883 302 911 506 965 -138 -379 255 -943 -444 147 -42 -918 582 -667 -977 345 763 -949
|
||||
-585 -304 861 410 893 -85 -471 201 -676 429 -109 -216 933 -405 -56 878 454 -897 472 -406 153 110 624 -554 125 -849 646 471 558 928 -643 -201 -383 -207 -212 -232 -877 -412 -62 670 -371 830 784 -723 187 305 951 289 -718 -984 -759 183 -202 520 -776 752 -895 -410 -387 752 1000 896 416 -139 969 306 -223 843 -96 -186 199 -34 390 818 661 -484 -62 119 -199 184 989 888 364 188 12 -561 429 -757 394 -839 -500 669 -91 -746 -629 891 727 900 -44 726 -151 -49 583 -975 579 565 834 200 -325 699 -37 -86 -682 442 -788 -565 -968 193 994 682 465 -431 529 -156 865 -91 -823 -975 -748 -78 -163 345 -955 -373 -533 -990 -820 -526 -740 -956 -757 -59 -987 -863 -714 -731 249 1 -365 -801
|
||||
429 640 -459 -46 -438 -608 164 502 100 -134 431 176 -803 218 -402 -994 -219 -844 -655 -152 358 -957 895 929 -65 -252 -821 -267 -95 -428 76 421 -1000 240 -27 285 -753 346 555 995 -346 104 -317 561 122 -590 715 423 886 -793 -379 -738 371 604 675 51 123 -155 78 650 -116 -682 -603 -344 -630 -686 -516 856 634 831 326 344 845 633 -839 644 781 -495 -154 -294 956 444 452 -713 154 188 -135 658 -357 -585 732 -632 410 -88 632 -871 247 -281 934 285 356 -681 160 -477 -880 -532 226 131 -256 999 -366 -224 -144 87 95 152 -642 -770 -944 -14 -293 290 622 876 45 131 636 342 538 -888 808 144 941 -447 -324 -133 445 884 -953 593 -713 -95 -841 -684 708 917 639 -177 -152 172
|
||||
171 551 346 -80 925 906 -699 90 -230 -185 302 3 617 -517 -35 494 -130 -734 488 488 413 652 116 -302 -46 -418 -505 564 748 142 995 9 64 995 643 -890 -507 597 78 -144 -34 568 -397 -918 -688 320 711 -399 -921 -290 322 -712 -208 700 -102 465 443 -705 -443 205 -497 -745 754 574 912 977 -572 646 -336 -62 -362 -512 -4 940 -518 715 758 -247 809 701 -443 193 845 737 -537 439 546 -230 333 -817 -900 138 -633 149 398 999 67 921 -450 -737 -659 169 570 -955 -176 -805 -259 -377 -714 -903 990 635 866 524 -673 -289 -864 881 -11 -87 506 -32 616 286 -269 374 -823 802 -265 267 297 -203 938 675 397 -937 -47 -265 982 447 859 383 573 803 91 -308 34 531 323 -894
|
||||
476 775 251 494 251 702 603 -233 9 682 -479 -802 556 567 -260 607 974 -450 -535 611 -85 913 195 -324 -530 809 692 547 -375 841 916 987 427 -342 -364 -405 577 644 -903 -724 997 -570 43 -955 333 -115 76 405 -156 85 -582 911 315 -228 318 -184 86 -90 -31 448 -892 251 792 -333 471 654 -921 -411 567 -386 205 -568 323 -94 470 -985 871 -526 569 695 -42 -260 144 373 776 -294 -800 237 -113 365 513 947 795 726 116 -835 939 266 223 -425 -90 505 903 529 -751 993 -491 -881 456 -932 -35 711 16 -654 -543 -477 -600 132 -449 340 168 -868 79 -601 -967 -148 -160 529 -210 -92 -189 526 -756 378 -770 251 930 998 -66 547 475 -701 -821 723 -664 -150 -743 664 853 216
|
||||
893 962 310 268 850 -533 -485 -205 297 -971 843 693 -483 977 855 -693 29 775 -831 -330 -362 -550 -167 890 -33 631 139 -587 571 -236 -325 -896 330 -332 -163 162 -396 -148 -374 -354 261 -867 -985 772 -948 955 683 -566 -946 -451 -395 -473 -348 832 167 -423 981 -986 -567 819 -716 351 -261 350 -605 -312 -661 -388 418 893 571 273 217 716 811 804 -112 -928 961 -505 102 -227 -189 -650 748 850 307 -965 902 904 -171 -276 -972 -855 -406 462 539 906 908 675 832 971 -496 -461 -258 489 381 793 -208 -256 45 707 -287 19 -755 250 248 229 -72 794 33 889 583 126 812 -107 -115 -299 -591 148 -836 -610 -925 -762 473 -188 245 854 657 510 792 -263 -89 337 128 803 -744 -766 -815 467
|
||||
-401 330 5 453 254 479 -819 -38 160 -806 343 18 946 154 989 -119 702 28 -461 -116 499 27 -503 326 -147 688 -28 19 -5 -838 -331 -416 -206 780 709 -514 982 518 142 -11 597 341 496 140 -811 8 -380 -355 960 19 -543 -626 439 -17 773 305 -457 -27 236 143 -219 -146 758 -334 -118 -956 -604 -345 382 955 476 -709 -79 528 517 -902 -899 460 -613 -746 -570 -958 128 896 -569 638 193 -932 -251 147 898 723 77 -792 -73 -162 290 931 281 215 -744 -516 193 179 658 -442 483 -981 -310 474 -230 -526 -6 -794 -44 235 -88 553 844 -740 504 665 -553 -426 -159 201 -483 -226 599 -98 -879 615 -208 -376 -684 -723 -442 -552 128 182 -236 1 -596 -656 -155 70 237 395 495 -372
|
||||
-920 -58 27 -24 175 -697 -336 -869 -83 -891 305 -505 -172 -450 -124 -409 -52 -933 -525 -539 65 381 700 -272 413 993 -940 332 935 -158 789 498 306 -820 -942 -905 -270 -222 706 555 709 -888 657 792 118 764 43 183 -366 -250 532 338 684 -735 633 964 -383 -556 -916 778 -900 469 987 -587 666 910 536 -300 -725 317 109 -351 499 -979 -676 -803 756 -948 538 869 -896 -164 309 -172 253 -33 -138 -433 980 897 -884 77 -370 114 2 -528 -40 928 457 -815 522 892 244 -31 -546 -182 -118 -292 543 -460 14 92 966 -942 -726 -598 -352 317 -672 991 -652 -317 898 -863 186 292 -68 141 -20 753 -643 523 -726 -633 -497 -430 75 -94 695 -635 395 766 232 149 84 -33 260 -988 -576 549
|
||||
29 66 435 240 -331 -356 -755 35 -830 -562 -83 510 -262 -814 364 -947 624 -131 460 -699 -455 863 -679 -645 506 840 -398 -552 -36 988 -495 339 -55 828 482 -652 338 517 259 459 939 153 -259 424 -578 -309 736 185 -755 957 -550 -188 -857 -572 657 928 -417 90 921 601 -201 -486 -685 -105 32 62 -666 -452 384 -5 -560 -642 31 -406 -185 -964 725 572 -89 811 61 -287 645 -333 -210 -95 674 960 488 31 427 911 -224 -381 -510 903 443 -925 -682 898 -873 393 -55 -345 -108 -42 728 -26 178 343 879 107 -832 614 708 106 795 638 666 -842 -615 -636 119 960 194 -477 -882 232 -650 363 341 -892 598 281 494 858 566 -763 -468 156 -10 -995 -31 901 -554 -183 345 -271 -118 -910
|
||||
509 -473 -21 222 -16 913 273 -930 510 41 948 -595 -583 -65 -785 -416 726 -283 -699 10 -802 -409 933 696 -907 -979 454 -100 636 377 209 899 747 -932 959 -362 107 -969 819 -615 826 788 -772 -109 573 -269 908 -322 751 488 324 46 -673 -1000 -152 607 -929 507 595 -162 -105 -991 -645 -81 -256 443 -637 827 677 -819 -473 -320 551 616 -31 95 883 -927 636 -364 -729 941 717 478 555 812 207 -569 -592 -563 803 -969 -640 -86 -103 -917 -21 -683 -255 279 921 595 -88 -135 -785 -225 53 201 588 500 526 331 414 806 -66 822 -969 969 79 36 321 -194 -461 -423 325 -299 511 -196 832 852 -556 -116 -625 47 -204 941 -148 -545 277 -491 -499 -632 -526 -930 -223 -700 -672 865 293 633
|
||||
-654 352 -27 -547 720 -609 67 -900 650 -133 833 700 -482 902 796 735 899 823 752 -844 -500 550 970 -23 876 -739 -260 526 392 34 -874 572 898 161 900 899 -719 164 -111 -693 46 -305 -879 261 979 781 266 -755 341 405 -505 -926 216 -433 91 22 720 185 -226 355 -548 -903 -249 -330 -882 -173 514 -629 465 189 -388 194 8 -501 540 -867 -695 -547 -785 599 685 -557 -391 416 425 -521 -602 95 -983 418 889 -588 -485 -415 -246 929 939 208 191 89 -234 -757 707 437 -53 -728 -613 -439 998 -620 -911 151 747 755 913 -446 -161 -460 -116 790 119 460 -988 -951 119 -246 444 404 -151 -416 -575 -35 80 698 839 738 -971 28 932 -581 124 -333 -206 -188 -174 -922 595 843 841 -123
|
||||
-514 940 -622 -518 922 -495 78 -489 -810 -67 -916 503 74 -61 -808 858 122 -18 988 -972 -233 892 17 -802 -812 490 665 570 502 143 141 117 -519 -566 -624 306 706 -254 -192 -191 27 -489 817 104 526 -543 -114 69 261 -383 605 -600 -599 -78 -979 -801 -125 -419 781 417 423 98 -292 -402 -840 632 999 522 -457 -167 474 -431 -386 268 526 -765 798 848 546 322 -488 196 -128 411 207 -313 -106 -934 266 692 -575 152 -542 13 594 -190 -495 -100 297 578 -463 -303 -20 -59 379 962 -369 987 973 989 -672 -788 280 183 -880 -564 30 -264 945 618 -406 -234 -346 331 9 889 43 -815 834 -288 -565 -481 856 73 -514 -101 -193 -755 326 5 -345 -857 -974 564 -153 -128 39 -924 229 703
|
||||
-594 905 907 -510 551 -843 -466 -732 592 333 -103 686 148 772 -599 -121 -604 319 -194 -350 -667 658 994 939 111 -183 67 149 319 383 467 -573 -5 -147 445 536 977 969 -281 -974 -117 294 206 415 -268 331 -539 -796 -469 218 683 -242 -343 -517 -125 204 68 -42 -15 706 109 207 -113 -614 211 591 518 -408 81 597 -38 675 458 -651 -353 -604 -61 -242 742 -746 21 -481 -1 -132 35 440 418 205 -307 623 58 -782 706 -809 -698 -687 -443 -157 -204 -965 -315 497 -152 440 -179 -649 -212 -724 -876 227 -412 672 -221 690 678 4 -939 -848 173 433 -795 345 246 -476 474 44 -991 888 -3 487 643 985 -762 -638 2 269 -640 -968 -168 173 57 339 -33 -652 937 251 -701 693 -17 -661
|
||||
-530 537 606 367 -837 -147 362 -876 383 877 -867 -990 -867 903 -254 199 -859 -395 -716 -575 -512 449 -592 -320 -185 -20 333 775 428 -940 -944 -667 -41 785 107 -286 843 79 522 -340 -479 -307 450 783 472 -555 997 -962 825 846 994 436 768 501 461 611 4 998 400 -985 938 -42 670 80 962 501 -167 -165 963 -453 -423 75 999 295 737 396 -326 856 409 -286 -703 -957 -868 12 -735 436 304 -707 -788 376 -336 64 -498 -301 966 749 684 594 315 111 811 824 255 -52 -571 -941 965 406 824 -560 -368 -837 454 -460 181 -924 -971 78 502 759 688 734 641 295 402 -274 221 69 376 626 235 -176 -123 351 -258 -299 917 909 958 -206 -788 747 -359 265 281 818 -903 61 -917 -241
|
||||
-92 522 469 414 -932 -48 414 -581 -954 788 -883 -74 -392 -579 -241 33 -953 -495 863 660 310 36 107 490 -248 -143 -37 493 196 -275 521 -548 -914 610 806 -760 -323 730 -963 70 -118 222 19 457 -149 -20 713 -510 -822 497 711 637 -928 -40 -895 -835 438 577 -821 -938 22 -406 305 593 968 974 -801 -706 -828 -853 -276 -897 -300 -818 729 44 960 361 -353 -783 769 -332 -426 626 811 198 -688 8 4 -49 503 421 220 978 987 -931 522 762 270 -863 -863 969 -539 -472 437 -842 581 77 -834 997 212 -265 -561 184 969 329 995 200 -596 642 167 122 168 -410 292 -680 412 539 363 82 -314 -865 979 824 105 -602 650 -669 -193 -465 -445 230 16 -2 567 -91 171 421 742 592
|
||||
82 545 132 -354 -140 121 953 285 -435 1000 937 808 -552 -475 439 902 771 366 23 -525 -388 521 -769 995 -572 -38 -685 -791 51 630 728 245 789 -304 -543 -62 -661 78 -699 662 871 982 -806 894 353 -45 369 453 763 -849 -960 -53 13 54 -738 306 -84 159 434 73 967 -784 946 -958 773 125 776 -75 -254 11 -537 -754 -82 -575 -187 514 -458 689 -295 501 -839 -407 804 72 519 -843 435 803 40 896 -386 152 213 -107 345 451 -720 -42 119 538 -802 56 -177 -278 232 352 587 -388 547 -784 888 -704 6 180 780 -554 -263 -707 174 -119 52 -151 -31 58 -662 -189 -283 7 -431 627 -674 -477 -184 445 -567 16 -814 -853 -499 -648 -248 701 -27 880 397 -716 503 -825 -813 -932
|
||||
657 756 -537 -536 -743 407 387 422 304 700 -47 809 -503 369 -193 83 -330 -891 532 532 -796 973 -986 567 -353 -320 678 -852 33 -141 -765 873 -337 883 353 778 -121 -241 -869 -491 -495 -535 -794 650 973 888 331 -937 920 884 -450 153 373 499 -226 296 715 -525 606 606 875 750 -277 -87 421 -428 -506 -515 338 -65 -138 319 93 -757 905 -155 -710 -264 292 205 -244 345 42 -583 -920 13 -51 -710 79 -358 -779 -916 840 997 -404 -961 -201 -226 -446 -505 -763 -960 -501 21 -719 246 -460 -794 -461 -443 -514 71 986 258 790 -413 -932 712 -658 737 284 -872 368 -506 -692 724 398 -926 -219 -381 790 344 -897 902 -431 -233 -191 -506 881 615 -298 633 -108 -883 188 -356 986 -906 493 -791
|
||||
-916 407 730 556 438 541 795 -385 151 658 11 962 786 -880 258 980 796 889 950 -290 -604 447 978 363 358 714 106 -519 515 716 359 338 -646 -805 468 -816 -840 299 -482 -301 -518 256 604 76 990 839 80 -80 -422 -164 -806 298 334 473 961 -69 494 -58 913 88 240 -707 35 209 278 459 542 851 -400 866 426 919 187 -595 175 13 329 722 -112 -645 844 907 -441 -881 533 -851 954 -75 987 547 584 -16 -471 -806 113 -324 913 -343 797 -879 -168 200 131 830 -801 812 -79 -207 166 -391 736 -154 -342 412 -993 -860 -316 -488 576 -237 29 516 -712 -518 182 -132 829 805 -411 -44 -995 -209 -24 -159 -611 816 643 -816 -187 -929 -936 568 -250 -651 293 -592 -946 258 -986 -963
|
||||
855 47 -625 815 630 22 -132 -97 288 -229 -22 -720 -109 43 652 454 -630 298 951 -821 992 -903 729 645 267 846 -632 962 -348 -85 944 27 62 668 24 432 10 -618 -206 668 421 -653 622 -480 22 -20 535 -411 860 283 910 911 430 545 605 840 -213 -515 -742 -45 825 962 -381 -906 423 637 -289 -806 -703 -964 6 613 277 -206 25 709 735 813 349 996 752 -387 979 294 -236 -171 -938 -828 -562 -232 -296 -804 -10 -400 -878 -261 597 -970 107 879 567 55 290 -103 786 397 -186 994 712 -809 -124 249 -404 190 195 -506 831 95 332 498 538 918 548 -163 835 825 669 940 39 -41 -840 -169 -492 413 -158 493 177 -112 -948 323 17 731 810 635 331 -870 513 -78 -662 476
|
||||
-713 476 43 -126 -213 985 80 813 -124 -802 -973 367 951 216 -221 -970 -67 927 -208 -835 -972 -553 -87 -425 966 279 458 -165 215 -840 -408 897 -216 812 70 -15 -656 -922 -865 -897 657 213 -950 -726 -970 317 -937 845 151 -483 713 983 588 -449 25 -668 -881 917 249 -681 -50 43 859 -536 -634 -485 907 -707 -636 -649 -173 -633 -256 105 -441 942 254 -229 195 642 797 -436 -358 -937 694 645 -814 -715 780 910 -503 464 -492 118 339 422 7 861 -706 -833 465 776 920 754 -606 -750 312 998 -462 -58 -579 -951 127 757 -572 -961 120 648 348 303 697 -617 808 112 -725 342 799 -45 -798 -640 136 -401 -533 263 850 -435 93 -142 276 742 191 872 220 -786 399 -287 389 296 -351 924
|
||||
-817 732 -40 -502 -616 -791 -928 -674 -879 506 618 -121 -72 -438 352 -146 719 -141 745 959 -469 -728 -314 -308 930 -177 -668 -548 -622 38 -953 28 945 -633 -402 -294 -865 -750 -394 -763 -161 398 893 -49 -370 26 -739 267 -218 -820 492 -567 448 665 85 -218 144 145 153 653 -74 -736 163 954 548 -926 590 509 -913 -639 -987 927 406 123 337 262 -25 -367 -514 -950 591 50 -995 807 907 -134 -196 -532 547 -811 -641 -369 -359 969 -236 -193 -199 142 174 -337 -588 964 220 -764 -931 -596 600 -190 -604 682 334 -696 685 806 -4 715 -434 -149 111 763 743 -123 -493 -73 805 624 797 -919 -187 -65 -292 -818 281 -529 363 64 -14 581 -97 859 -378 -933 -71 -644 -118 -422 468 226 5 -756
|
||||
369 280 -933 -539 12 977 806 -698 -599 -527 -678 -433 -960 118 -888 -416 61 69 41 979 -289 -886 -304 185 107 -798 423 -182 -841 -252 -139 318 302 384 450 728 117 784 -138 -922 -279 -633 -421 188 522 928 -397 78 881 762 376 -660 322 876 2 -785 734 -631 905 -803 955 31 -633 -777 370 -418 -720 -566 -285 -410 983 -205 -679 -79 -952 -429 -268 768 568 517 -419 -170 -337 199 228 -745 -525 13 -28 -455 61 -185 901 -213 332 -601 515 -168 -739 -390 219 -947 -31 -803 956 476 -992 35 835 153 996 -767 767 -85 -699 -699 -624 0 -715 546 79 -518 379 -340 440 517 -805 -563 249 137 -477 -886 -98 -806 255 -796 -973 939 127 606 906 -276 -901 303 -591 -30 913 -156 867 911
|
||||
-250 -719 902 -125 362 -58 406 171 -60 -620 -404 -785 545 -869 -369 -789 -162 848 433 -499 647 -338 723 -661 -674 949 -465 420 892 757 193 -376 -995 -973 848 326 292 232 565 -981 588 338 -587 438 250 287 713 966 251 -903 -24 83 881 -855 492 -955 -474 -512 -146 471 962 217 -752 629 -240 469 -233 -431 -573 357 -131 -562 -623 691 378 -478 869 -409 -112 225 11 501 573 -844 222 283 -508 237 181 735 -685 500 548 -801 -857 252 -388 -244 -280 -482 846 -696 229 308 -798 -456 -824 285 -478 -429 -115 729 -882 771 613 -949 772 -921 44 -205 -556 -849 314 -404 346 -105 -335 146 747 -152 577 -731 -871 -349 -260 -520 300 -886 -464 539 -96 726 -162 -292 -717 259 -829 32 922 859
|
||||
-12 661 -238 433 -738 478 319 -14 286 -298 -591 190 -856 532 793 -20 432 -371 -243 -568 336 -755 512 -693 -448 757 626 991 174 221 874 123 31 425 -215 912 -361 359 -157 338 -419 260 -573 57 -740 257 -626 570 628 548 292 -564 626 925 105 -722 -908 843 346 -347 970 724 -692 586 -931 -875 420 220 -552 702 94 581 -675 111 986 -916 819 -227 -339 -3 -771 -262 259 -916 447 728 723 -576 312 56 969 281 -75 -282 -320 -978 794 624 -402 -12 -232 773 413 -774 -71 409 722 -925 -206 -449 -425 -125 202 724 710 438 -30 636 -552 93 -685 -933 446 -242 282 -27 672 -32 -915 735 415 -849 -30 -849 -334 730 -169 986 24 -149 -834 701 -191 -544 523 850 794 500 646 -9
|
||||
470 -965 -552 650 -475 337 236 -503 94 702 38 -321 -1000 -491 -524 -447 -302 952 -986 -469 -552 -291 983 -217 -193 753 -54 -139 813 195 -551 -682 282 -586 -207 248 326 495 687 -694 -502 94 -208 242 152 -890 626 -416 -571 119 -12 337 788 2 128 -248 392 279 840 -23 -555 -153 -614 985 649 164 -426 -741 -169 -302 -899 276 -161 322 -390 82 -166 232 436 870 165 -827 986 -184 748 -558 -386 -814 497 696 -278 -178 280 -605 -696 -714 209 -892 394 136 -596 -375 -778 533 -501 -732 519 -249 127 51 980 -454 843 884 970 -229 -883 506 754 -847 -799 -152 -163 948 800 324 -52 -828 -666 339 440 -303 -251 -328 -221 374 973 396 753 9 155 -58 -409 -665 -563 61 924 -858 108 936
|
||||
-141 -32 674 -483 -190 45 628 -146 -751 202 -96 684 267 549 -459 110 -499 748 -206 -314 -101 604 663 -476 410 472 272 -250 -181 -277 996 -839 -498 270 -46 288 719 454 -142 112 -703 -484 -538 -871 -865 -955 -712 472 229 -268 -775 -615 -748 21 996 86 -501 -982 782 -405 -346 851 324 -618 -40 949 -679 -615 104 -541 -203 -421 -332 716 -32 -665 192 -140 -616 180 -801 -798 547 820 -432 -742 880 57 727 -284 -747 29 821 -465 -416 -859 398 -21 -215 -608 599 -888 -571 623 362 -800 179 -379 -935 -389 547 572 -121 -537 -975 110 -525 292 934 -987 796 -452 830 960 -63 947 242 325 711 -31 614 623 -933 -899 -283 -650 -438 446 -311 697 1 -509 -329 955 -765 -917 699 -176 -348 -258
|
||||
233 -295 942 -217 -569 223 -79 522 480 125 -44 -575 16 -291 -380 -218 160 528 296 -900 -929 339 -256 -921 -134 -725 -973 224 -560 294 -586 -736 764 -902 -911 -823 638 -847 261 631 504 887 -482 513 134 250 -138 -601 262 605 -185 -570 -619 355 -103 -303 153 464 -885 910 -790 -810 508 -685 -970 878 -379 37 -899 -213 163 430 -720 -396 129 -331 683 508 849 838 -316 211 3 535 -327 984 -276 -126 -236 604 -648 137 -913 -271 772 -434 -568 -913 -741 854 -505 476 -783 153 982 594 -813 -896 98 -443 -688 390 952 -54 114 -998 628 51 92 953 388 268 -66 856 -915 -60 -385 -777 -524 94 423 -356 -355 -722 784 213 475 77 299 -154 -259 -422 509 753 -842 930 -121 618 -22 -695
|
||||
362 -908 87 193 574 743 -43 -793 808 -517 -454 -383 200 419 599 285 446 -888 999 -142 -333 -759 -240 484 265 -346 513 458 -646 -269 271 7 -12 -589 981 649 -139 417 750 771 303 -720 722 -86 407 -665 406 -390 -180 -182 -877 -127 571 110 -485 728 595 776 -313 41 851 344 -9 -786 368 -336 373 32 412 473 347 895 -472 568 29 538 -775 776 378 634 -516 -467 325 290 354 371 -546 183 -961 69 520 550 785 -828 883 -576 1000 6 -89 -305 457 -317 932 806 -801 -532 566 -92 51 -956 -622 -761 113 689 -591 756 -336 740 -144 -83 -112 342 762 -611 -683 -880 525 694 372 621 958 -152 -333 -294 220 -31 368 845 366 679 -837 505 -885 867 -983 631 -582 -849 -550 -180
|
||||
-509 -42 -210 -839 89 930 672 -46 -74 -170 7 -546 509 800 -593 810 -151 258 900 278 912 914 -150 -909 -261 -215 843 -186 766 -732 289 821 0 662 313 -471 -274 -151 -695 -343 -783 -97 -307 450 809 -557 209 -6 503 956 907 208 -723 -764 985 -427 -592 504 -357 480 -191 591 -427 918 -718 537 -100 -405 -172 337 297 294 568 330 358 888 -141 -816 572 -792 -137 -997 143 216 487 -874 -384 436 641 -460 214 729 -618 487 -654 56 275 735 96 -8 -361 -842 -928 -209 -828 -452 -717 646 86 816 509 -22 194 596 -137 143 -52 522 -668 -575 0 742 660 492 70 -633 28 326 936 -774 -628 193 -460 87 158 -711 -178 -89 603 -310 113 573 -256 671 890 -846 55 833 924 530
|
||||
-976 -764 436 -977 512 -320 764 553 151 -123 -892 -79 460 -133 145 779 764 246 560 23 112 6 471 -94 -125 372 -408 430 -579 -324 39 -963 -299 -752 73 739 414 -449 -700 624 841 627 761 -690 -207 970 709 316 -57 237 411 -298 -11 -965 849 88 -251 979 -986 -46 948 -903 -652 297 -498 -473 804 -143 845 93 -293 -849 804 576 896 -30 -428 -748 693 -565 -769 -166 -562 -36 -9 -828 -846 -808 -70 -960 164 504 -288 159 -867 634 958 -489 86 -806 -553 88 343 -838 -627 175 -29 835 286 -658 -911 -734 -989 -621 -557 -417 43 -776 -774 -762 820 452 -261 -124 337 -210 -221 942 -82 329 -609 183 113 748 -217 311 165 -158 -844 856 306 -650 -826 -266 128 -947 25 688 710 -152
|
||||
457 -826 195 545 -84 108 -116 -40 529 -886 629 -695 251 432 223 417 -887 246 4 -168 918 -199 322 -398 126 210 -839 -572 -257 133 -732 79 416 888 238 497 848 -430 433 105 -898 -373 217 892 526 212 -495 540 -814 192 -243 438 -746 -900 628 -964 6 -194 382 864 380 -716 198 98 472 314 -211 675 429 -770 -758 -212 419 988 445 728 110 -488 65 539 -684 -97 -804 465 -35 615 -36 -610 94 592 -826 -650 985 -1000 657 -352 588 838 60 -437 583 -809 -81 463 612 535 909 -158 730 310 -525 -220 273 612 -463 731 33 199 -844 532 587 436 852 -615 -722 592 378 273 -123 -839 -558 494 -683 -683 504 885 932 150 803 -600 -882 -468 711 531 549 -401 516 771 -492 730
|
||||
935 815 2 45 228 -385 756 624 -542 557 261 620 193 -895 -872 812 710 -170 575 -417 -964 -332 -278 -432 432 -811 -969 28 -213 360 -190 353 539 346 -66 -179 -913 88 -729 -2 364 394 -177 428 -196 -950 -834 -389 731 820 -792 762 -526 820 12 93 852 660 -689 -183 773 946 464 922 532 -14 -610 -935 315 216 -125 -891 -823 -34 -290 -254 -223 -636 -720 711 480 -556 -439 206 -856 -275 -535 527 142 -310 44 -816 950 -427 -306 -432 694 -493 10 -901 703 601 -286 -347 -112 712 -322 69 -234 -282 -82 -948 -767 -248 -968 -40 -284 833 -375 992 -553 115 -297 -131 121 -963 49 695 345 348 795 -826 350 -124 -690 595 -526 -926 383 -973 226 12 69 689 600 -809 -932 325 360 809
|
||||
-701 667 756 -316 -443 -8 -89 -679 -500 294 552 -441 -955 158 -25 57 -247 -148 -236 592 -553 165 -75 -864 497 -7 462 813 298 -100 276 227 726 -68 -285 -201 -864 -540 759 -737 -303 -153 -188 -410 -615 -69 -588 74 629 856 -749 -747 -400 111 732 -670 729 -398 992 -473 -78 440 497 68 350 515 788 26 -11 920 -220 727 -204 -183 -629 59 670 -515 -385 -588 -944 -255 -27 -768 -407 -925 -473 -32 439 -183 -64 -613 406 -26 870 246 -974 -77 496 -661 309 -414 410 -576 905 -150 723 514 433 580 55 291 451 525 454 -705 -751 375 -320 525 -560 -887 -214 68 -654 -815 -795 465 773 728 897 676 136 -810 558 995 -584 209 -167 -805 -921 -174 384 -851 308 148 304 -312 -117 -779
|
||||
-48 948 -282 -77 -159 -691 561 -547 338 -902 -232 -117 219 -89 -693 -837 -126 -249 777 629 840 1000 -202 740 852 146 -127 382 -667 -431 -769 276 254 487 -253 591 642 -904 -954 -341 -107 -569 169 -129 -263 -946 -482 389 -670 -22 664 -428 781 -790 836 -972 214 459 740 -872 660 -474 896 794 46 -395 -384 -466 -493 244 -856 -383 564 -267 96 -639 -588 -941 498 -78 -920 -926 -397 -87 -42 -186 -806 -648 -778 902 632 -757 59 -734 -915 -979 610 248 -149 567 145 655 564 -74 -606 -64 -803 -427 -189 -999 106 -181 684 -441 -359 487 -458 -646 772 -536 -909 -750 -304 -850 -78 295 -748 -450 -712 -510 683 106 471 -761 890 447 -860 -124 778 802 -960 980 746 -442 -761 135 -921 622 -205 -711
|
||||
961 -274 937 327 -558 -144 -565 -261 -316 -190 -132 678 304 619 -862 -835 699 -808 695 -551 -616 510 277 -947 576 704 -782 -565 525 -975 242 75 850 452 641 -651 838 36 495 -858 -25 738 452 -970 -478 258 -351 924 -34 -227 -8 -579 533 -483 706 -285 -939 16 220 281 192 -144 -73 -857 -446 519 -660 -482 -881 -99 475 441 904 384 -748 779 -770 238 462 29 784 -544 -347 585 -690 308 516 697 663 997 0 840 450 390 -868 767 -857 645 -537 -568 -39 751 803 679 404 -850 -949 -152 -279 -313 271 -4 -565 372 -129 -358 -72 429 -507 9 -274 -299 -836 -556 -998 -900 -935 -126 145 837 -134 -836 132 693 -368 -697 -851 -294 355 971 -681 -15 -168 -150 87 688 165 -616 -739 948
|
||||
139 44 -205 586 -444 995 36 331 775 838 435 364 -715 292 289 102 -568 -437 -450 975 -117 -385 -611 -224 -251 531 -454 -433 -703 394 972 758 -221 93 -283 165 -732 82 112 541 596 -276 -493 647 -311 -510 -915 -629 -135 -812 465 -213 -731 525 -834 -926 406 29 55 977 -126 252 -896 -29 -29 761 758 -294 343 63 -830 543 -78 -4 937 117 862 476 -250 987 259 -422 734 143 211 -803 -197 453 -846 -829 -834 144 -949 646 -729 59 -359 -48 -352 -732 246 -937 398 725 -255 37 539 749 -75 841 -865 -56 -441 432 326 56 932 -536 16 854 963 -62 560 -909 476 294 51 988 -247 -212 -86 -874 369 80 -238 -958 -75 -976 220 -10 141 857 -191 -468 958 -756 -591 477 -600 -993
|
||||
463 548 548 -883 406 -891 683 -430 -288 -583 -940 -981 -59 -662 -283 -832 645 -863 -423 546 637 -318 -980 -723 344 438 -384 822 -200 543 178 -632 -803 611 -59 767 208 -844 623 -323 -709 -114 -50 -865 -787 369 909 -879 715 995 -817 46 727 606 706 431 -302 812 800 979 107 654 -686 528 -537 901 640 691 664 182 -537 -815 -561 749 -576 769 -414 -59 451 83 -226 -806 -126 761 -114 926 822 25 853 -247 508 -40 -114 613 -300 -773 -802 -430 -975 0 81 -981 215 -333 -601 454 570 777 -817 -87 -48 -312 -904 973 -391 171 -715 930 -444 -939 -958 631 233 510 693 260 118 556 -892 -735 915 -562 -441 319 -337 132 -243 868 -173 -953 178 736 -826 25 -115 975 -436 341 -367 -827
|
||||
185 -54 835 664 917 460 -377 799 500 -46 912 210 478 -331 -665 -815 359 184 -530 668 -258 943 49 -394 505 107 233 512 -680 -473 -134 -953 -590 782 -244 -432 -590 -54 184 -627 -524 209 -676 -957 878 -819 360 779 934 176 654 128 -972 -402 315 249 -434 628 -912 908 -455 -339 426 -351 577 -254 183 -628 408 991 -85 640 -460 -735 421 248 192 -770 -378 788 890 344 359 -938 -979 -98 767 788 947 -742 13 915 3 127 -911 -193 162 -759 65 -267 -126 -382 852 502 963 -892 341 918 -586 863 -76 -495 -480 225 -731 17 -490 -83 406 603 -911 -341 -924 -563 463 181 500 -554 -424 -922 -964 984 -376 -87 186 -120 -498 236 356 -956 178 613 863 -587 -893 -251 -856 218 -34 740
|
||||
-456 -507 485 -299 693 345 -224 -252 -920 705 455 -197 749 678 569 563 829 -506 -149 73 895 -120 828 -687 -64 -916 -407 907 -611 210 557 929 -628 160 -530 469 643 -633 -56 592 -313 335 -349 -90 493 -237 236 417 659 752 485 873 17 -256 -231 956 88 -447 -917 810 -159 -830 -275 -887 587 184 128 -239 276 -676 -133 -226 -711 650 326 -150 -399 -83 -979 -85 947 920 765 370 -104 369 704 600 -825 -475 350 277 -998 934 299 14 -887 470 -727 -903 166 -7 -170 -756 -517 857 190 776 -72 46 686 -674 68 -909 -839 400 371 -958 -355 421 76 -564 -349 -88 918 -435 -390 -593 917 -446 344 -578 701 843 -173 -385 -229 -856 840 -740 -53 -254 196 951 -487 -868 961 672 -960 407
|
||||
-718 824 -584 838 261 593 529 413 -592 92 -189 -700 -567 -696 -240 218 -132 667 711 -883 377 -825 -94 -663 -772 814 580 -413 394 -505 354 -546 229 996 -732 -472 -455 359 -452 833 -5 -475 402 -897 71 733 -877 -600 -204 731 990 360 162 46 675 -627 534 -379 -670 480 -926 567 919 -503 973 -762 876 -509 -665 -516 209 -824 -258 -161 -995 -599 629 -419 -253 996 -722 -414 -596 25 716 237 -254 -639 -82 -701 467 -658 -862 1 583 -865 -662 -242 794 -630 -137 15 719 -267 254 891 -700 510 -64 741 235 -562 -532 645 -625 637 -387 964 -34 -204 671 -119 -316 254 -185 180 996 880 683 -680 -975 565 202 159 575 127 54 -681 911 993 921 222 618 238 274 -777 -511 158 170 338
|
||||
-87 529 9 -885 140 406 -649 -858 -676 -226 919 -532 -922 831 -295 -571 464 67 953 587 984 -42 482 -59 385 824 905 96 -691 487 -709 -592 -805 -265 106 -531 -446 -117 21 -657 -788 273 86 231 411 -99 389 116 -985 268 -328 -953 537 -42 -412 -633 337 -550 -566 451 425 -908 -213 253 540 -742 105 48 -936 485 564 356 -476 953 47 632 -130 1 -204 519 546 -575 -929 -361 -206 -483 -860 616 396 310 -890 -30 676 -96 -902 -57 -531 -879 476 -322 390 799 -833 -211 982 -606 574 388 -551 472 -291 167 -840 -539 -273 -212 -533 -917 839 -898 -564 365 504 -646 150 283 72 -845 -575 976 906 728 364 562 194 89 -446 -481 -599 -820 -283 411 -877 839 -610 995 321 546 823 74
|
||||
382 778 186 -510 -179 -206 -509 -380 509 -975 -310 750 -807 -349 755 486 769 -249 -891 -902 209 193 -796 244 804 151 485 -315 272 705 992 -674 446 -350 691 938 -778 -617 816 468 306 -55 222 904 -277 -898 -91 676 -939 -925 -576 121 -737 460 890 -644 859 -821 -605 451 -359 -545 -435 -332 -694 -140 -397 558 211 775 -105 520 -370 -630 -106 765 263 765 -452 -45 951 553 278 -83 -270 134 668 757 631 393 -958 530 -420 -30 -823 -834 89 763 235 660 -588 -550 -800 -709 -793 672 -678 -311 -630 -602 189 800 587 216 -738 687 133 476 -712 -803 -237 -329 955 -872 852 -917 739 327 -803 784 27 647 -508 -532 -197 304 337 895 -72 712 -71 529 489 -647 659 397 27 -259 67 945
|
||||
479 603 -901 -720 -396 366 887 -401 860 -149 -960 425 341 893 513 925 243 958 -934 -166 805 972 -725 602 253 -14 -739 154 849 -433 -568 -542 -911 550 776 -573 311 263 -172 -829 -207 224 621 -965 297 -164 -841 959 -962 -142 -845 -357 -863 680 -484 44 361 646 -646 3 751 -482 256 -242 295 534 -445 -959 -403 605 66 134 150 892 382 59 -750 124 110 -198 -288 325 782 16 -233 -114 -762 955 -624 -844 -804 -920 -476 461 -739 603 -971 826 -653 513 802 203 821 178 -579 37 312 409 727 500 13 -556 -883 -166 862 -962 -950 -142 -801 703 505 281 -591 469 219 -161 329 -211 -516 -781 631 500 7 -490 -982 386 -678 480 994 -328 704 756 -651 977 -772 -481 196 -362 -832 -682
|
||||
-343 -691 -238 -490 -69 187 511 -202 -973 485 -21 -133 -374 678 939 899 33 12 43 559 650 -781 -862 -265 -902 -361 -661 142 413 -495 -503 -520 -657 791 -231 -699 -839 495 261 742 -740 -590 107 -407 318 937 -6 -982 143 -696 560 719 -570 68 -693 -109 817 619 -673 34 -352 974 -161 663 -970 -860 -79 -955 -520 719 387 437 -746 -409 484 -625 201 -168 206 423 -444 817 362 -46 754 445 678 -205 524 359 135 -825 -157 197 764 232 -117 -622 543 -885 766 -632 441 355 -765 344 -778 -807 125 84 861 -218 -395 -885 -296 -386 -939 948 -748 -928 -501 309 -512 499 -134 -608 38 -417 -337 -816 -861 434 -724 266 -562 777 479 -711 28 15 637 -214 862 999 -703 917 -484 -845 -124 -647
|
||||
-633 285 953 -870 404 856 -327 -207 424 490 5 270 -410 686 186 -64 805 -658 442 317 286 964 635 -324 -660 -366 -749 -226 371 870 859 480 699 126 866 -811 -76 856 591 -643 912 13 -116 -9 -930 849 894 -691 93 651 -56 -69 -509 3 -416 432 582 607 504 -386 -144 -913 -812 554 -503 -389 834 -777 -768 543 -855 -134 875 934 -252 -467 -303 -973 938 498 634 956 -915 -585 -530 250 180 853 379 -654 511 -296 -279 350 -745 168 22 -345 96 -804 -241 -597 -823 -955 708 -402 -787 863 587 -219 -89 -320 677 -794 576 -268 -30 283 910 840 -581 -479 -742 -580 -564 963 -528 -362 165 178 185 -102 82 -236 689 316 461 165 -644 -531 -699 399 -29 413 435 -280 -269 -857 -644 -36
|
||||
-902 425 30 -537 -424 462 -873 784 -161 -790 -308 961 -456 389 482 -493 -724 -493 -982 -807 845 504 -839 -785 354 711 682 -783 -644 -86 20 -778 138 939 650 -53 -524 136 -459 -142 321 -591 271 460 -71 742 3 240 955 989 784 574 949 718 -777 216 -487 -730 454 -792 -316 -408 -139 -615 147 -754 -183 556 346 651 -106 590 -235 75 -570 728 996 856 -694 848 713 564 724 -531 428 -641 767 -551 155 -319 -475 443 -283 615 -207 -899 -990 -665 -385 -241 999 -990 -639 574 -309 -577 -218 -558 -828 -746 -582 227 -779 445 -611 -436 -526 -87 -196 273 277 283 -732 -864 652 -60 -816 -256 -465 418 532 -317 120 857 -917 -694 441 -114 497 -707 756 241 144 -111 -592 -289 507 995 -871 -955
|
||||
-31 948 -208 98 337 -750 755 -8 164 994 575 -151 498 935 -420 -343 -99 -828 -596 216 -291 335 -859 -482 117 -236 -327 -218 676 -966 182 487 -233 217 408 212 -398 443 -989 -314 -950 399 -440 331 223 819 960 -87 -743 998 -386 464 -827 -42 -336 100 -370 -103 -982 224 20 743 88 -760 -26 650 -604 74 94 -415 -923 -334 -11 -795 -127 -854 -255 12 655 721 -323 -916 -408 -494 -107 -161 -568 461 -292 787 -511 337 -15 179 -349 801 348 -774 -134 32 850 -713 834 -592 -292 386 -979 -545 -5 458 -168 -326 -305 195 431 -803 427 -672 895 864 -294 -255 -368 -5 728 -743 688 161 -743 702 842 -587 622 178 -544 -446 718 -355 -371 234 -258 273 -372 -460 -749 400 -948 -470 -57 -70
|
||||
-90 -47 481 871 -627 694 772 908 -686 -850 -567 -872 960 498 914 472 -141 445 -904 614 533 -311 849 -533 798 -783 -113 701 77 -527 747 -280 -997 52 -125 -150 23 402 280 677 -317 907 -281 183 -269 -19 929 -449 -728 -20 -746 -370 -276 798 558 -449 -389 182 -367 -704 -673 347 348 711 -831 254 48 54 608 241 912 -32 -529 124 753 -494 -250 -310 -34 917 162 -980 228 -974 -5 848 -925 814 457 -803 -863 -166 280 -437 -246 894 323 -911 817 259 784 780 -528 212 417 144 798 -161 344 -932 -480 511 594 -480 259 100 176 485 -196 -778 -57 290 103 710 726 -80 -759 -954 -900 -877 924 -102 -166 545 -341 -261 -53 -836 749 -324 -664 136 -845 110 -486 620 571 785 -690 -711
|
||||
240 -856 714 354 963 979 -142 303 563 -741 914 974 -106 597 -79 -645 908 32 946 -138 -248 -783 -433 923 955 456 -233 -748 -902 385 358 -365 -209 271 893 702 278 -672 -688 -553 927 305 -262 371 -113 485 592 -422 660 -691 -996 -260 -818 459 -189 966 346 382 -403 593 204 -221 -62 768 -762 -739 803 215 694 620 383 -36 998 -72 -167 -524 -877 110 -863 2 951 507 -344 -835 -624 -356 12 -87 -169 -280 745 -41 761 935 708 -666 -250 -696 -502 472 657 819 -557 680 834 -339 764 649 427 983 906 -762 970 -457 57 -113 -852 -531 684 -755 765 213 374 -84 352 -159 137 -454 488 207 -567 95 276 966 533 54 183 108 -643 -172 623 57 443 -688 -439 -812 -372 311 256 -255
|
||||
-250 776 -520 -947 235 -940 -146 -630 -885 391 945 -860 712 655 -176 -940 -347 -622 -234 954 439 788 -637 362 -872 -710 -780 2 1000 159 408 -531 -203 -351 416 887 -311 206 533 935 -689 258 411 612 917 -331 -6 138 977 916 -925 -685 960 637 427 80 -183 74 -251 -232 887 -696 -753 988 937 -867 -184 -175 56 112 -650 -613 -675 -527 197 -341 809 -503 892 238 -947 -822 274 900 -710 -203 -257 607 955 665 -990 -248 576 -545 -158 -820 -910 -44 -435 -748 808 -698 -979 -764 855 -347 623 117 -531 979 -662 -246 467 289 302 -84 -183 -770 -125 447 600 676 -83 163 736 236 -628 273 -38 573 979 376 236 -488 -745 371 -865 619 -529 332 736 152 -496 232 470 -361 -81 994 17 -756
|
||||
-478 366 907 -46 -552 523 776 -543 -662 54 723 576 -55 545 677 -349 -943 -242 -234 -681 -715 17 119 262 -121 767 -447 -965 -102 320 -176 324 -578 505 -916 586 -421 -956 545 -12 955 166 708 -697 -51 -835 821 -320 -688 703 -196 -513 -826 71 650 -68 -758 664 -752 17 356 56 316 -846 -826 -840 -439 417 591 857 811 -660 -421 -784 843 -829 285 -168 -253 102 -346 -288 189 411 988 967 135 -273 -290 -857 817 -802 -587 -96 983 953 -728 -328 280 245 -445 949 742 -298 -484 -882 188 -775 94 791 102 -83 384 -975 -681 763 651 806 330 213 -803 -393 476 991 561 -736 613 916 669 -626 -490 559 -414 -291 388 -245 975 391 667 864 682 837 601 -749 -859 673 567 13 489 988
|
||||
720 -665 302 750 -397 -895 -951 -620 -208 -388 469 389 -153 -653 650 -712 -180 925 873 976 -661 -981 -643 -310 810 -888 53 -390 580 -400 261 591 -436 -728 356 -510 231 -909 -31 -239 676 814 849 659 -96 219 -165 -773 -709 -210 -598 825 -82 504 211 -57 -821 783 -887 -253 -16 -217 -486 -61 506 -640 -132 -8 913 946 -715 -391 -822 -683 566 855 -858 -795 -481 22 -837 -157 312 -680 759 -407 304 712 191 266 -609 -365 693 -398 652 477 -511 935 -907 -74 508 -429 85 -139 -30 186 -630 -640 975 362 -333 872 546 720 -292 825 -874 636 -588 201 -313 165 981 388 184 -457 747 490 -510 -201 64 -227 -290 -945 -339 823 -183 -605 710 -168 -465 547 -867 196 -345 999 -392 560 -575 715
|
||||
-195 694 -1000 -994 806 477 45 -611 -564 -848 57 47 580 591 -456 -63 38 430 -228 -549 -44 737 51 -136 -445 127 245 700 -519 126 727 -686 -147 -560 -714 181 634 -865 -271 -668 857 772 -331 663 -721 -283 311 478 327 -525 700 -665 -716 927 -952 794 3 -476 -687 822 -708 -529 -69 354 -888 948 823 -458 685 830 -220 -255 -391 -961 212 -760 265 -794 236 310 46 928 532 -474 -537 582 -361 913 796 -875 -695 -892 876 899 400 -264 -956 228 412 282 279 669 -351 -400 758 509 618 740 -88 -485 30 4 -172 894 -872 586 746 -280 553 -690 -169 -733 248 312 245 -403 496 -189 -643 198 571 -215 388 -576 -343 -903 -737 -510 -728 -184 -310 -889 656 242 890 709 -212 719 -855 -999
|
||||
299 50 -78 -358 968 -638 521 -304 -906 -424 -76 358 696 113 693 579 -869 -166 -96 434 -40 -87 -763 -978 826 348 -528 -807 -151 -487 690 -6 118 134 920 917 -79 793 -455 668 863 -173 -976 795 573 -243 938 895 855 -592 611 -194 -828 -528 2 -186 53 -843 91 26 851 -582 645 -959 956 794 567 -583 -48 357 -930 3 -196 629 212 411 631 717 -635 -130 128 -924 2 -436 -656 -406 946 -31 183 641 533 674 858 488 935 -565 -244 875 -772 504 -955 206 -176 -288 415 837 461 453 -598 357 275 -306 631 110 554 -664 595 8 -788 -531 -159 434 -828 -400 -214 -447 881 493 591 844 455 -32 62 267 169 -859 179 -159 -92 268 -871 -224 -294 948 -99 -705 -196 -165 383 15
|
||||
61 399 233 18 909 503 482 651 -202 529 271 -451 -180 -591 174 253 237 997 650 -514 515 684 630 124 497 870 -217 -789 -292 -624 376 360 389 534 -750 -155 -200 -756 350 871 257 -695 836 -160 458 648 -339 -698 642 -899 551 -715 -529 -342 376 -281 258 -739 193 -593 171 -16 525 -172 -450 -880 -697 -1 -844 -477 -358 159 395 -81 -524 -501 -453 188 510 492 -34 -552 -123 962 -144 71 100 554 412 909 -439 -829 -702 -566 628 -329 -898 -998 -343 -577 369 -856 871 -720 508 -121 -813 108 -299 -838 467 455 509 -865 883 -273 -328 -197 -864 91 -523 -956 953 482 -825 -892 -303 567 -926 510 666 771 -178 -947 501 424 -972 310 561 297 -334 -326 531 -494 922 -380 63 -464 224 -499
|
||||
-410 -16 -394 55 -550 -768 -916 -704 689 -205 854 965 488 680 -758 684 -355 281 369 -32 205 -654 413 375 -509 -864 851 7 -605 964 479 904 969 714 -210 385 -989 683 347 872 -133 -107 987 -977 910 -521 308 -971 -281 -248 -304 946 -422 -435 756 -416 -771 305 -378 577 4 744 579 -480 590 -76 326 547 -574 187 -623 -836 889 515 -266 -680 -463 374 642 -617 928 -217 275 -831 -411 708 189 -522 -714 -662 -790 -658 620 -925 -890 -87 -736 899 -692 773 -722 -174 -922 -14 -583 -888 -516 -753 444 369 -455 -584 968 -663 59 551 -747 177 -911 -93 936 -668 886 -716 -498 658 -832 -625 -123 -192 -917 -375 -392 971 -726 303 911 -284 -960 -821 572 -285 549 983 779 -473 75 548 800 823
|
||||
-207 -200 118 -154 -53 522 -508 715 273 930 -245 177 659 -101 -729 -284 -449 245 649 -669 948 513 -842 -385 298 606 551 141 -162 -462 762 -785 625 -857 -564 -49 674 -270 942 -138 -823 783 -662 -665 182 83 -416 -847 584 -957 -966 -305 552 229 -394 -510 274 -231 627 -907 506 -81 -995 790 477 740 -258 -489 -352 77 108 -655 -71 -668 -678 -987 404 604 -968 785 -977 757 452 -718 867 578 -423 -149 -786 734 773 -724 -509 -409 -85 -615 -976 -435 -645 -600 264 736 -932 -434 229 -964 -540 772 -399 576 269 932 367 -705 321 -396 -739 -87 246 -192 775 -817 774 -813 -576 -756 489 969 -532 422 -365 -458 831 513 -399 10 398 628 -986 223 770 626 811 899 -724 -2 49 -461 893 -455
|
||||
-610 -420 536 371 -378 961 136 -863 172 417 576 565 -472 -671 -750 779 157 -588 -51 -782 -808 -271 -231 26 -444 497 -378 966 82 14 -873 -245 521 48 635 722 -543 259 804 -502 404 434 -573 -741 -436 -781 214 -930 97 223 334 823 -944 -931 -955 48 158 -222 247 550 -386 -773 233 -11 373 447 967 419 -324 -359 -960 -562 -455 -695 217 -930 292 -188 749 -964 245 409 215 440 -787 159 618 -45 583 797 888 150 110 192 784 751 -540 108 -216 467 -922 -254 -53 633 715 563 -67 -459 870 -266 351 715 -906 892 175 908 -446 42 -551 981 665 -201 291 532 -111 -488 -245 -832 -964 292 700 -759 529 734 811 -940 -888 464 912 921 -976 -966 -217 -501 -30 795 720 739 12 -348
|
||||
-79 490 -771 -425 217 289 725 -469 54 290 651 -218 -486 932 284 575 217 -586 643 625 -919 -760 -184 -755 -116 -86 454 602 99 292 -344 55 -567 -338 -611 902 -926 332 960 797 -520 -269 258 99 220 -105 746 747 -940 808 -788 4 207 550 -177 -446 -900 563 -429 839 -9 -338 231 -821 152 228 638 882 981 43 -71 -453 942 -220 -589 663 -369 -268 -908 895 -626 -286 898 42 -93 -813 -856 -602 -231 850 568 976 1000 -466 -242 197 774 526 971 438 755 225 -760 337 778 -140 994 -71 -412 589 777 653 -549 660 786 878 846 641 -103 565 -139 -773 -163 779 -487 -461 558 180 95 -657 631 -695 -933 374 69 -262 780 950 12 -85 -623 -779 -352 166 -737 -161 -600 633 -229 -590
|
||||
-574 18 -228 -996 -698 309 -14 -535 -84 -671 -991 -428 157 -820 901 -224 -131 165 686 350 -729 -554 -914 707 -499 855 408 -919 -923 857 815 279 -674 -286 35 -979 773 -941 -957 299 842 102 740 466 -917 625 -647 980 -193 -391 -146 -865 541 668 12 601 -333 459 498 287 -137 -37 636 -563 -333 487 -243 -753 -934 -762 81 -239 -694 195 -770 67 -439 729 -178 -155 -383 -187 -661 564 173 644 -684 531 -498 240 -973 147 -921 -936 -109 -82 259 354 -305 220 339 839 -588 983 750 682 -997 639 181 163 113 -823 729 -509 155 317 -785 713 57 273 -960 357 715 -408 -299 -265 -844 -137 -990 -664 860 -770 66 -763 -852 360 489 -69 -710 -871 -866 -636 -393 265 338 -864 -33 -282 -751 -328
|
||||
-923 807 828 875 -487 98 -718 -193 -8 914 762 74 731 242 96 -424 -204 -683 -938 -742 -399 352 -28 -394 -241 -447 -243 5 -129 -239 750 816 -436 -372 630 -963 489 -159 -908 438 515 618 -999 453 -471 -330 -620 -566 -795 46 -920 965 -249 548 818 266 522 -90 -139 426 -106 194 536 -399 -869 982 533 9 959 921 -68 525 81 640 -293 -252 -875 849 413 -349 -617 659 601 842 -169 969 930 -653 397 -810 -225 -591 -126 -240 -606 339 800 849 -455 -925 -66 879 -695 -885 -832 -42 -616 926 144 -579 118 -572 -683 176 323 -575 827 -13 370 83 767 -938 -266 -704 61 -501 -220 394 -669 -479 -21 458 -68 401 -448 -92 -404 -791 14 -497 39 272 -970 70 403 780 679 129 -384 -722
|
||||
766 501 -722 911 823 -265 477 209 219 -882 -780 927 -7 -8 -992 -316 711 -743 -330 952 -857 134 121 -575 -554 972 -756 87 308 956 210 -516 -237 669 -809 -234 -815 321 -770 810 104 -733 -865 218 -917 615 812 -501 -890 -598 720 -912 -332 760 -322 528 823 887 121 431 735 270 379 -261 -565 803 731 -919 -474 -969 782 46 -41 789 -460 -139 627 -534 822 702 66 24 -969 149 -18 -455 890 -230 684 -643 -622 876 -96 -702 479 748 -565 224 18 -666 796 540 428 -758 739 -204 206 -671 688 -660 149 -313 -670 892 768 -234 371 846 -624 -642 -781 134 -723 464 -412 -718 734 189 525 833 -37 208 -630 180 20 -661 -271 -47 842 275 -256 576 -478 -195 -218 -86 658 -904 120 -473
|
||||
276 -495 405 -958 -194 379 -48 816 436 -850 -722 800 660 106 -298 -937 -648 156 960 -842 -620 641 858 442 -895 302 -549 926 359 117 -830 682 -34 194 122 -367 577 43 2 935 -416 476 66 -111 -608 573 -321 999 351 -550 -849 -556 755 903 -927 855 -846 -54 -31 -80 -282 608 -883 1 781 -73 203 -113 -633 -858 928 -404 -393 -527 929 -229 428 569 862 -143 -686 -438 -743 446 -860 -391 -963 315 947 838 460 555 -670 -631 940 27 167 -434 187 776 -1 950 -853 674 143 -402 128 995 -337 199 -409 -411 -35 -392 371 -418 -738 444 -805 -192 659 -224 -762 -344 -211 -358 281 -872 -804 -527 -58 265 988 618 -263 -225 906 728 -64 83 843 -366 134 -455 -49 -48 -467 496 -34 -867
|
||||
998 529 701 329 797 993 640 524 -710 -130 776 26 -959 -605 542 715 -392 109 -566 -181 -912 -908 433 164 -555 549 868 -672 237 492 956 -4 689 300 957 -886 32 419 707 -625 -366 737 -375 -162 -588 -373 -236 -594 -879 -367 -295 953 -272 708 391 -816 625 279 -175 626 764 385 -876 -396 149 -729 9 -547 -670 512 -853 67 -745 675 -419 -353 4 -196 -627 202 -128 258 -207 985 391 131 -705 637 733 -319 61 300 75 788 2 -577 762 143 540 -86 -876 772 886 516 -945 -200 837 762 -302 548 -559 -588 -888 1000 313 382 -219 118 818 232 -690 316 -828 89 -683 387 553 127 -641 901 156 -607 -217 562 738 894 -254 480 -577 -54 292 -125 -980 -514 -898 -995 -343 -138 391 -601
|
||||
-784 -86 161 711 82 -898 760 456 -519 -400 717 -917 50 -787 -137 458 789 656 -120 -890 615 -801 -473 -512 -759 656 -656 412 681 -376 -895 -65 958 39 761 869 -838 -916 679 444 -723 -189 -59 -421 589 -114 -930 -762 -326 -884 432 575 94 -772 990 329 309 835 438 987 -879 -676 402 -59 -66 496 143 849 -481 851 -891 -242 -241 -597 -593 -116 309 -453 112 860 243 -789 510 533 581 922 225 225 -685 376 109 274 -688 -96 87 -923 -110 104 480 -337 -279 461 -769 -336 -621 137 952 668 -250 -621 -432 207 132 341 320 -394 -847 835 -354 816 604 511 604 311 366 463 -715 -806 142 -843 332 -227 -591 602 73 -203 -357 353 474 747 137 792 95 -382 -945 298 -897 999 721 -119
|
||||
-322 -585 338 -308 802 -256 429 -766 -292 -620 -655 397 602 946 102 -383 -460 321 91 -737 708 -533 -667 -71 649 -928 214 430 265 968 220 -233 634 14 260 835 -142 723 -221 737 232 515 538 311 356 -991 -664 791 -427 -197 220 -417 952 -334 -802 -512 379 451 800 585 626 -68 209 -103 122 -247 293 405 777 127 935 -8 -699 254 632 -519 831 580 113 -741 160 -984 591 -109 768 541 847 164 -550 -596 -201 -931 -632 108 -56 -531 842 474 -679 -25 -792 -500 -720 389 525 -904 51 620 -101 281 -591 455 -739 -982 -594 275 549 863 -530 -743 -620 -763 -853 -978 177 -364 937 -941 114 -614 -913 930 249 -813 61 -837 543 -866 160 -305 136 377 684 -985 -735 163 922 -847 -766 647
|
||||
301 431 -217 2 774 245 121 -918 561 -119 -661 513 -192 693 -517 679 179 -773 -13 655 875 -811 302 -239 317 828 -335 -708 -143 -226 -815 -814 -651 57 -965 934 -53 -693 589 -1000 -740 59 723 32 -625 762 -251 -843 -972 -34 -420 -891 -577 635 264 436 159 -863 -999 -660 -29 48 880 156 -886 600 -419 996 -500 271 -416 26 231 604 356 613 -503 175 -161 -705 -959 464 663 826 -90 -552 670 671 693 934 -178 832 -675 -923 308 -66 548 -718 363 -160 334 -329 -489 -416 -591 -252 94 -701 -200 -738 66 -970 709 990 -542 1000 599 -188 993 -592 -252 -965 -100 411 798 -742 -234 216 -731 -156 -466 -82 -197 -207 -193 585 448 504 -355 54 119 -118 940 703 -523 480 -428 392 -945 -36
|
||||
-740 -771 823 -929 -587 971 -506 638 -733 953 541 -72 145 646 -404 -863 77 -791 -620 212 -3 618 -843 -796 575 -35 -525 265 -867 -444 -61 785 492 -783 413 -381 -150 401 -822 -397 -957 -975 -908 280 -509 343 -730 103 278 -900 142 745 -854 653 -930 -880 462 -430 -189 -552 580 59 707 501 17 -643 691 950 249 -796 -616 -12 250 -318 356 -363 262 -800 -457 497 14 60 324 779 682 115 329 -985 755 -304 -678 -110 -369 242 -475 347 348 949 995 364 108 -198 -493 -48 -698 251 -320 -760 -400 590 -381 179 439 -808 -873 -899 130 372 -585 17 -319 188 895 976 -468 -440 804 868 -202 -783 -357 330 356 -658 712 -110 940 103 610 8 137 -894 911 -675 974 16 -955 -393 -593 911
|
||||
-655 -140 937 -931 844 202 -781 605 701 -432 -978 -502 -18 335 -544 293 -586 262 288 248 -806 -78 -395 -976 -133 -508 -291 344 -851 390 786 -600 935 -815 539 -872 -77 -163 290 -102 -92 223 905 -121 385 -574 932 78 1 201 980 607 -885 231 122 -880 -533 780 934 432 -700 968 883 20 424 -210 -55 -785 -436 -225 845 -404 952 -857 245 60 -203 -665 -678 -922 793 757 255 -492 -843 -261 -299 981 974 -288 110 898 988 877 -623 -271 385 -112 -470 131 -49 -857 -22 69 -366 138 -915 348 -889 597 158 -378 103 -413 440 -276 -949 774 -649 642 -987 810 35 4 362 947 -415 26 432 -947 -214 -962 281 -91 -582 -499 -271 511 555 110 -838 -997 -799 948 560 301 260 -78 136 592
|
||||
868 469 533 -128 545 687 -822 -934 -42 99 -884 442 -380 -140 -367 -944 907 99 297 592 -598 332 -943 933 -223 632 831 -812 82 -121 -441 70 -33 -939 -203 -558 647 -641 554 326 -439 332 378 572 -536 -893 -812 -497 129 -499 -661 168 -544 621 -550 -140 269 788 -890 29 369 -758 -487 563 -957 691 216 748 240 -557 599 -102 377 -52 151 749 -503 -459 -495 -509 46 -683 43 -490 -313 -340 893 376 155 -107 -450 138 304 -746 805 -562 -131 -207 -593 -624 -553 -829 -211 607 -566 470 704 -28 -910 -512 619 299 -450 38 -653 715 -406 195 348 -135 484 730 818 42 -612 41 427 -85 -11 719 206 -330 -838 55 -629 472 499 221 -972 101 487 -678 -116 519 -541 518 650 632 348 -948
|
||||
423 -257 -496 288 243 -458 -716 683 86 -465 -563 461 -687 567 -334 -946 -15 151 -98 521 -111 -139 98 -719 47 272 274 -428 -166 -744 -396 -920 355 659 20 -728 -425 -846 -815 499 390 149 378 231 -104 520 -695 -150 -832 -414 -91 755 283 948 -179 262 -745 48 -16 -954 586 218 709 -724 -728 431 -783 141 -778 -154 -584 -646 -151 458 537 796 749 475 -343 750 -23 -563 929 725 -476 834 889 544 -498 253 726 -530 311 746 -752 -892 -961 -793 -710 -940 -539 126 781 -407 -451 125 -63 454 -667 201 -466 546 865 175 -771 838 -538 835 -637 -590 -841 593 274 13 503 -126 767 -439 736 -466 -498 366 -140 -354 -41 -527 -422 -340 432 -349 -730 654 628 -324 177 953 -156 916 83 348
|
||||
-706 276 176 572 -931 -615 533 -828 506 328 827 -710 160 720 807 542 592 -327 402 -422 232 554 -1 -878 590 21 844 156 -517 510 206 336 504 505 -868 396 857 -409 626 -551 -994 70 -498 -26 -757 778 -199 333 312 -147 -697 44 -850 -10 -358 596 936 44 -418 909 902 -961 -428 973 -167 -275 548 -924 82 -283 127 451 -645 -400 491 -937 -635 -270 470 992 846 -253 -405 99 -648 -115 -703 -830 602 339 -990 918 -361 -95 -872 877 2 567 -688 118 -893 915 -94 842 76 287 -344 386 -808 572 758 418 514 -242 -517 -648 -899 23 -746 696 950 -128 887 782 -343 220 -457 863 137 243 646 -953 210 -174 459 -702 -50 -874 950 270 -95 737 -500 948 203 451 939 -862 -649 -531
|
||||
-412 -224 -192 -94 -755 929 -427 -438 405 925 277 739 -157 -875 -332 759 -146 743 -772 795 9 -362 636 392 -557 -825 -230 -647 290 470 333 963 -69 -374 -136 246 -713 355 -235 818 879 270 -315 -872 -831 695 -257 -36 -895 -321 350 -898 -903 -117 435 20 -871 -41 -401 615 311 -262 -391 464 -61 88 -421 552 614 886 181 -802 -528 649 232 59 -974 934 816 555 682 787 978 477 559 469 -227 -672 242 742 -812 545 638 -884 358 -216 311 -359 869 -455 -345 -451 753 395 954 -909 699 650 -931 392 -93 -250 -88 59 -815 621 567 -38 -545 -152 -572 -652 698 814 201 598 -757 819 334 -900 170 -613 -405 152 369 324 -1 342 -370 392 231 131 -474 466 264 832 -535 -191 -705 677
|
||||
186 -430 -671 823 -240 -364 -394 -337 566 886 -377 248 -425 -280 -16 75 -852 626 343 46 -624 -896 -787 829 84 -845 -379 -758 852 -462 167 435 443 -120 -254 -331 350 -422 466 1000 895 823 -498 631 8 342 -132 566 -882 855 749 -392 -78 158 -263 -111 283 535 162 480 -672 269 -766 -215 -829 -581 177 127 -591 -890 -45 154 -931 -94 -655 -926 548 934 -136 502 -767 -513 -178 580 -785 -876 416 768 -763 996 30 745 -611 -233 -378 -315 527 795 996 499 859 -976 53 480 781 -806 -52 249 516 624 452 507 999 619 295 488 594 -115 487 110 -545 64 692 -952 -467 -628 836 -150 -124 490 25 57 -869 106 272 743 185 185 -308 313 428 -117 162 265 -132 -533 362 -549 190 -813
|
||||
-413 -754 720 -702 -907 885 519 390 -846 -678 -96 823 795 -385 742 546 298 -96 -728 -969 637 882 225 -781 -174 533 45 -721 -469 546 458 -159 -208 811 521 928 -866 -258 -372 21 -278 -946 603 -563 -304 743 634 -719 737 137 -913 390 -838 -256 136 476 124 -626 -916 329 -586 840 140 -544 -883 -686 -856 -721 -236 572 921 -78 763 136 150 831 418 833 -581 353 -857 421 -789 462 906 754 -774 839 276 815 -212 -237 -656 -89 -638 686 -495 -730 -359 -877 -236 -307 -551 284 -159 -862 -63 -565 -190 604 -198 120 950 -958 -837 -148 -952 -164 -573 280 287 763 931 -363 -423 -204 336 36 -503 -233 -127 320 -950 -616 985 303 -641 -609 -717 -577 -800 -939 81 888 643 -811 950 -515 -168 683
|
||||
579 -371 -713 -802 -943 -122 163 541 562 -348 382 64 -892 185 948 -769 318 -477 757 546 721 931 -521 -56 99 -591 -335 96 -255 604 -650 -380 -85 -452 -119 -623 282 -783 -621 107 -451 478 -655 744 178 261 527 801 278 -788 251 127 -272 -902 -812 866 -644 -198 421 -652 -133 925 296 660 967 11 682 334 55 457 147 -386 -939 464 -885 -234 -378 -360 997 -658 293 518 626 168 630 342 -318 -919 174 -702 644 -273 241 767 415 37 -5 -350 -187 -62 -816 420 582 -139 948 -982 97 932 679 431 -316 397 715 -674 -924 -321 -468 675 -111 -120 -315 334 258 44 -944 -153 900 687 -395 590 -302 -789 488 -423 -338 -106 408 -874 760 -626 -50 -718 -337 924 -841 -223 -849 846 205 858
|
||||
509 -219 961 862 94 -451 601 536 358 -522 -822 306 405 -996 -918 -41 -140 113 458 941 -823 881 -482 8 456 -763 201 -321 902 -188 744 328 586 328 23 98 376 67 240 343 151 -466 -883 -373 53 454 401 -219 -505 623 103 281 -824 -457 -145 -606 581 -708 -68 -750 598 -575 864 -52 -493 -285 -560 285 -7 475 -364 -604 -973 219 11 513 -582 531 -978 204 -972 -921 160 950 -640 232 521 260 98 378 476 671 84 967 -674 -790 351 673 334 -959 -409 -905 991 -770 -818 198 -321 -129 -903 968 -106 215 -911 599 -875 -434 -542 -165 -210 -544 -76 641 740 313 -164 530 315 610 -3 841 -159 99 968 494 -540 -339 394 462 57 -452 24 906 952 146 -396 -343 2 -875 815 428
|
||||
769 -331 -836 877 -653 50 -252 -737 -55 877 963 978 313 463 291 -996 372 165 -965 -162 -16 -433 -223 -520 -855 71 535 -88 537 753 -655 -325 -108 -271 -365 -214 -222 -511 987 -996 -712 -125 -936 -617 549 -216 -841 62 -485 481 486 646 665 121 203 -33 191 681 -227 937 -617 567 -725 -495 403 -412 -76 -685 -234 -663 -514 266 -905 273 121 829 -985 534 811 -743 -71 -5 289 -786 -839 -649 535 -794 -519 -928 -883 -682 831 -2 495 -657 948 -700 194 994 978 -138 263 599 -631 -479 -47 -324 573 -452 621 533 807 -95 745 379 91 505 583 -146 714 198 324 -637 880 -338 -323 -719 782 153 78 -478 994 908 610 -936 -996 -876 699 -202 350 90 680 -918 541 10 -691 759 -40 -393
|
||||
-298 -5 128 -394 82 -226 995 -914 606 849 312 -489 947 -331 729 331 -703 -877 -322 -961 -757 -956 964 -354 640 -288 515 999 1000 984 946 238 386 -417 -6 -529 -95 344 567 -276 163 -797 -187 -98 532 151 -212 799 -389 987 -133 -507 -1000 255 -797 675 -96 -528 277 223 -56 -900 51 584 -759 926 278 -103 -506 148 360 781 -623 856 722 180 250 -601 125 -240 -897 -199 -686 985 -906 843 736 -163 913 -207 -910 -310 -188 962 525 705 -587 -726 -770 -179 -919 -564 786 250 4 960 736 -318 -336 -227 -466 499 710 -610 877 843 -802 -102 -785 298 -134 963 366 504 486 -836 -546 -987 -895 -858 46 821 -882 -634 901 567 -371 -138 269 239 -752 902 -519 -3 45 856 25 665 -448 109
|
||||
-802 -260 950 378 502 871 -211 -395 4 -433 621 134 -570 953 601 200 649 -913 882 -169 291 706 -16 -112 806 -300 487 -841 480 59 -719 701 378 381 456 -595 -256 -570 -932 71 -662 -913 781 -578 732 456 784 92 -652 337 -12 -73 -390 -656 -925 946 146 409 -830 -815 738 -455 343 954 554 -86 -519 236 -215 -664 -531 886 -218 204 -407 579 347 563 851 662 698 -183 -391 382 -58 217 678 -574 17 -537 745 140 -308 -64 60 -38 -770 770 -818 383 178 -765 774 650 408 -138 870 273 548 -885 72 -540 -183 838 836 -452 316 815 629 -892 760 625 -739 -975 -351 389 848 168 -868 -92 -55 -856 617 965 8 -231 13 -194 -398 645 707 693 758 720 274 488 182 161 -735 -286
|
||||
78 137 389 -443 -624 -799 779 963 -907 -637 460 946 455 -319 92 524 279 932 -4 31 64 -597 -451 330 948 -799 -408 -690 294 -729 976 -115 -650 -20 95 -889 -88 845 -77 -19 -916 883 603 652 421 413 83 -641 31 -506 305 337 633 39 627 167 -977 655 -29 223 449 -970 616 4 -645 760 -938 -86 -663 -351 -525 922 687 -504 315 -563 97 -770 -926 67 141 91 -481 -399 418 217 -460 -107 -761 -557 -57 998 -768 877 959 132 -559 -13 -410 -79 612 194 749 -890 -435 -848 -172 -209 -138 -742 1000 -60 -621 -544 498 -140 -984 -606 -553 361 33 504 539 368 391 -890 -481 -72 36 506 734 689 540 -19 -923 -366 -543 -243 402 -353 523 -685 -225 313 -150 -829 396 -134 -321 -600
|
||||
830 331 969 -134 596 -197 -5 681 -61 -354 296 -993 -368 -53 -155 72 636 107 136 -169 906 -852 283 603 675 -76 -169 -64 692 894 -693 -600 -78 -502 357 895 933 -368 -881 29 -133 -386 289 -874 991 -139 650 -775 -909 221 -802 -272 921 -430 398 -905 -143 688 -452 283 833 -603 -697 986 765 -849 -135 522 528 -146 878 632 -94 -265 -173 20 -890 701 710 974 838 -43 866 -610 -686 -154 -466 538 -683 936 244 549 312 -863 997 -198 -671 -796 -91 -911 -181 61 214 67 -886 166 218 -428 198 985 -205 -685 1000 965 855 -783 -491 932 708 -260 -832 468 354 645 -735 473 746 692 614 249 -535 -584 736 -301 276 190 38 953 736 816 -730 682 903 250 931 730 -41 -31 546 765
|
||||
-195 -755 215 886 168 -791 407 299 -847 577 -195 193 882 153 -591 618 -433 204 740 -62 79 -875 -771 625 -258 -794 -313 557 990 301 632 631 659 852 -108 -886 -915 378 -497 -192 985 815 -275 139 23 170 -818 -683 380 41 -268 -233 -664 504 6 -394 825 240 -847 -609 -3 584 -972 957 -38 81 564 795 -795 7 -649 -465 -838 389 -549 -165 573 -898 421 -206 121 -443 -586 959 -565 -553 -514 395 -43 -654 475 -122 -297 89 -205 772 122 -919 965 892 -200 901 -502 -336 528 964 -746 132 -754 -447 -545 -408 -938 -515 683 -374 -805 -44 -614 692 869 997 113 942 219 -666 120 587 -702 397 715 -129 205 512 -685 47 318 -486 749 631 -552 -782 419 909 -486 708 -295 414 -474 -73
|
||||
209 -867 -735 801 -97 -154 53 226 313 989 -928 -332 -749 686 -488 137 -97 67 751 -588 412 400 771 372 620 -167 -939 293 751 -723 56 197 177 571 302 -101 667 848 -184 -885 -623 -250 427 -640 -722 -863 654 -692 962 172 823 -26 -9 -48 112 -649 10 342 -680 883 162 416 -763 -427 824 -2 180 339 555 194 -978 773 453 -877 -506 -328 756 -526 -39 -656 544 -864 582 54 -8 771 -550 559 -155 533 754 212 133 -458 854 -516 623 884 160 -743 -988 -472 629 -25 -751 303 560 377 -140 363 -653 565 951 -351 577 246 721 321 -510 -223 -10 -878 -106 13 -619 388 -794 -756 328 -658 791 503 654 32 -26 34 262 145 -146 990 488 7 -835 -749 -518 -558 -832 114 68 -113
|
||||
-975 -913 286 -638 -167 -514 387 727 137 670 -542 -734 822 536 623 417 423 901 -212 -89 715 -353 -312 -75 387 -632 -643 758 100 -227 611 -858 231 43 -746 0 42 -578 -478 -419 -914 355 379 318 -58 -601 -659 178 -998 947 -882 -584 -991 23 -800 118 -770 -89 -418 344 274 395 -993 805 -461 -714 543 588 -655 -597 -434 398 138 886 -751 483 -549 223 -512 -355 -635 -557 50 291 -679 -629 -313 196 841 542 -663 295 -209 426 -484 -257 945 -426 460 -249 758 350 -504 -542 -747 584 795 -898 312 142 498 -228 -999 -536 880 -195 -556 510 740 968 453 -997 161 533 515 925 847 -542 -651 -367 -312 -973 -798 -83 405 761 238 140 -395 196 987 460 528 -937 -25 -802 870 254 322 416
|
||||
311 307 -654 -201 -983 14 -17 -971 151 -699 706 -460 -475 -117 14 183 868 -312 -169 -361 -263 -112 -494 -93 -308 -338 312 -302 104 -457 981 209 -921 -199 -931 -541 -884 -912 825 -416 -485 -723 749 326 -428 -366 459 -734 -587 -479 570 747 696 -726 978 -116 -399 -945 -561 -567 767 -840 400 660 -26 432 261 -162 -638 5 -18 167 544 314 484 -302 -809 -252 -466 486 674 717 726 385 859 495 -215 -583 -708 26 -162 -316 -668 -741 -417 -475 225 342 764 -677 -79 343 709 -304 284 470 54 -19 -3 -257 604 -810 853 663 -639 284 717 809 925 -260 -449 665 715 863 -486 550 782 -14 744 935 -824 420 -70 434 644 -443 195 98 457 878 -204 299 -723 752 -193 724 272 397 -402 -958
|
||||
622 221 -481 -838 93 -109 -613 371 244 713 927 337 232 -971 785 104 -472 -11 -235 272 -427 -207 -953 385 -435 833 507 337 219 -551 -896 -781 -756 -134 410 -855 -207 -69 -304 -743 891 861 -410 -409 -557 287 731 367 -402 -388 -472 564 -308 591 -251 528 -963 -603 -319 -378 -584 203 573 327 333 -78 -131 -851 898 735 -217 677 -259 -462 -313 -633 -410 700 679 -344 -691 979 831 -118 706 -18 559 -813 -138 -171 -612 -487 -385 223 -686 207 -773 53 -668 470 -694 311 -656 165 11 372 -238 138 173 220 -547 -92 754 198 351 -887 -983 507 34 663 290 443 -437 876 764 -387 -854 485 561 231 -622 894 -899 640 54 735 -148 -94 -634 774 834 -825 -892 -199 942 -94 25 182 865 -554
|
||||
-940 -959 -194 -816 -319 -277 -997 -888 114 200 272 -18 -690 634 -218 704 512 764 -178 -117 935 969 586 305 514 306 -302 726 -303 189 333 -942 -525 315 835 920 -720 77 -677 -807 -873 -912 -228 490 -52 463 -184 164 486 -18 568 -760 749 -373 -735 544 -964 933 157 -89 -807 -63 524 35 811 160 -213 -510 132 -81 -898 -316 909 863 -234 47 674 -853 494 876 864 -389 513 0 124 -239 467 840 550 -714 -328 719 -905 102 -875 -613 -750 109 -311 -969 -321 484 -875 798 -64 566 -573 428 652 -500 95 24 -878 166 169 -541 -79 -627 21 202 844 725 38 608 -412 -708 849 -6 -759 -617 951 820 -195 -218 -537 69 -200 867 715 718 -528 -278 -856 -257 -503 844 -20 495 -723 -758
|
||||
436 -986 464 691 992 660 -827 -196 254 -913 -835 -273 13 -503 -995 -666 250 -971 358 579 -563 -451 -964 -533 944 -825 99 -790 -411 -337 -283 718 410 -610 -759 112 296 378 842 358 -262 -980 -638 -289 163 189 958 421 674 843 315 489 714 480 -215 744 789 -934 -673 335 644 241 270 538 797 554 -144 -173 333 336 364 -42 -743 262 -32 55 -801 507 -219 -696 -792 262 67 -815 348 -887 181 486 585 340 737 -329 -332 347 37 734 -140 579 -625 105 -605 -134 420 142 396 199 -13 162 -937 -308 -566 -243 874 943 609 -446 742 143 -254 -68 202 -157 540 -701 211 60 702 -891 -292 429 -156 -255 314 740 236 631 736 317 -178 -429 -923 104 994 298 816 566 -561 935 -974 -742
|
||||
-872 -668 -54 -855 373 609 -718 -534 -67 -288 316 -745 -84 526 -74 -749 -117 -891 -149 -857 -37 -146 -509 -218 658 -546 652 -344 -648 207 -462 -901 -774 -25 -312 87 784 -639 406 698 -697 -518 437 496 647 -854 982 545 -334 528 -183 364 -632 -877 459 428 -582 -387 246 874 983 -165 141 27 -522 -19 441 -436 695 29 -244 -335 -564 556 -326 -539 143 -614 972 527 -38 -201 63 -80 811 -544 866 -766 -117 319 86 454 -96 583 241 -130 74 763 91 -816 -485 632 -659 -247 -625 263 970 851 -602 -280 -200 -51 415 -906 -996 -337 -575 -910 484 -772 -168 555 422 159 909 186 -111 -412 721 730 -723 -120 -947 -777 -244 627 84 -503 -682 -200 -92 691 937 -61 -599 20 -891 -767 -847 832
|
||||
-444 650 -503 529 403 769 -58 -871 -835 -556 -345 -311 432 -736 178 693 -270 588 -85 918 711 -916 -709 -739 -247 -742 -682 811 -335 418 -149 -687 790 486 -955 -224 858 860 -953 -409 942 897 907 989 -428 -621 947 870 119 -855 -82 116 481 539 -979 -457 -870 -896 104 -737 593 929 480 944 -601 -91 -535 -29 238 -734 422 576 233 823 -55 -749 431 750 920 716 642 906 881 588 -518 -785 -395 -180 975 -419 -615 204 -220 -231 218 997 -703 -294 441 -586 -600 -659 -610 973 449 297 142 -161 -190 -231 206 338 -789 502 -451 538 -12 933 411 132 559 984 -497 -875 -284 783 -123 580 290 822 938 842 -560 -104 -744 -274 334 -655 360 -721 -912 39 -210 652 593 -555 288 497 379 -950
|
||||
699 -497 373 -608 283 -395 -106 -976 -309 49 503 271 946 -638 -732 673 916 701 -996 193 -378 187 -818 -663 39 451 225 -567 -993 672 -242 -468 -233 -345 -52 -729 214 -433 -572 -625 305 -584 -185 910 -386 -387 263 748 -567 714 338 -371 245 221 -364 -479 847 -293 520 577 -869 -693 -993 -874 -353 559 -625 -34 735 273 287 704 -459 -571 671 248 913 350 -832 134 477 854 35 -129 -504 -225 503 341 -114 629 -630 313 681 -218 693 595 -768 -355 834 -111 251 785 -387 -406 309 266 -121 208 -231 899 199 -811 -943 313 800 -270 530 743 954 252 -314 846 -681 -539 38 -461 874 -257 -675 852 -671 -695 -399 -610 330 -796 -741 -415 -734 387 951 -741 -924 -52 -339 324 269 111 850 317
|
||||
-595 -194 -243 184 -904 -758 -391 -849 -678 678 -260 -715 632 -23 46 -939 779 804 291 -952 272 -309 598 -812 -66 666 203 -721 215 -103 -799 -975 417 761 99 -188 -984 50 -451 13 -807 -505 469 420 -596 -31 -246 -892 780 -860 983 -228 788 418 -499 198 526 398 200 187 313 -917 444 818 -981 877 -798 -596 640 -964 -848 -789 -686 -279 -635 678 22 -844 421 -865 253 -291 -987 175 -580 -251 -689 235 -818 674 951 -859 50 360 -888 640 413 -353 -426 -491 -772 -731 913 -45 -99 8 837 201 274 919 279 -589 191 911 312 182 705 217 151 -912 -454 -994 -148 158 133 667 -793 808 -562 108 497 907 -933 930 -208 841 -102 -740 956 -868 119 942 -922 425 957 646 714 -962 -285 -22
|
||||
-10 395 833 232 229 290 849 839 348 -617 -157 29 365 122 482 84 274 -670 -57 -170 87 -981 -304 914 -564 -23 -47 569 171 -965 632 971 -730 850 -223 841 -9 844 -896 -993 -916 -619 -632 -605 215 531 453 -11 364 416 23 433 733 363 947 -673 -759 -867 822 -276 -283 252 -785 -785 -386 -706 96 279 -292 -712 194 7 575 -966 188 410 582 969 16 378 -218 917 -863 -184 -629 249 284 357 634 -921 648 587 706 316 509 449 -229 -587 -496 -71 -484 10 501 175 -648 928 -673 919 -419 -481 261 -666 -70 -437 63 -690 -556 -641 514 720 0 752 776 734 -171 -667 -482 370 162 -915 588 -967 429 254 543 -967 302 -785 925 377 158 46 -736 1 443 131 602 -503 -816 516
|
||||
-64 762 -810 -462 227 33 557 424 84 -735 349 84 42 -673 -734 271 -862 770 161 878 793 -895 -306 -484 504 407 764 -13 -527 -39 -689 -3 394 -319 -928 904 -120 -985 25 607 941 -468 162 992 -319 -287 -195 98 570 -743 -826 -814 -589 -330 -949 42 -167 101 -774 -993 480 529 446 -512 235 802 797 -955 230 -511 -783 979 -557 77 -254 -944 875 -928 -89 -555 996 -274 -756 954 -423 -38 -299 892 176 -100 -956 437 -629 313 -12 226 -111 -746 881 -784 -292 -335 26 444 -888 172 -234 -181 -998 341 -318 -519 782 940 987 -872 -714 405 685 889 109 -958 335 -452 -599 684 -205 -524 -296 46 231 -861 -842 94 861 872 -146 -165 411 -625 426 546 886 583 370 92 80 493 -748 -167
|
||||
-524 804 -24 -64 -991 216 637 -276 -804 -27 -931 -22 782 -624 -840 -193 442 143 -797 -20 688 -365 -887 -963 -336 -471 -685 -526 -166 -679 -857 48 404 563 -173 800 799 779 -264 173 66 -360 203 -914 815 165 908 -188 -158 211 -971 354 209 -727 993 -730 133 635 -595 921 -983 -163 -354 250 -208 320 69 961 435 272 -354 -428 -846 501 970 86 165 -207 294 -746 -671 50 -638 260 -324 -526 541 -631 802 647 -792 705 -967 -44 -315 18 -991 845 -280 -978 417 212 600 316 621 -915 -819 -885 -582 42 -55 332 282 234 -442 35 -973 -339 855 -186 461 261 410 -2 728 -647 209 354 583 -71 -917 386 648 -235 416 -832 -624 343 872 -759 705 853 -40 938 832 412 553 654 888 917
|
||||
-439 102 -279 -557 -285 938 544 -190 191 -832 504 223 -417 -351 525 -878 40 580 868 889 677 888 284 -202 452 642 710 841 -761 692 148 778 -575 -372 465 -82 -982 -112 621 -158 351 789 530 -292 -473 -885 -658 -77 868 -363 987 192 623 837 -788 -698 -161 -120 955 -310 -378 -169 -66 -457 190 -70 -243 109 653 202 501 279 857 60 19 825 -442 415 890 -410 275 680 202 -882 -313 286 -605 983 -398 -26 143 345 -196 999 952 67 928 452 -890 323 605 445 -551 -427 -889 -276 199 -799 -768 498 262 760 422 -155 1000 644 32 101 965 -618 742 -871 317 -204 -30 -817 -204 822 -783 405 -931 814 -673 -1 -744 138 -336 -348 -491 400 267 -260 -310 -268 -157 -162 -655 -531 -629 -254
|
||||
271 -742 124 -111 -258 -734 432 393 -882 -405 228 -322 253 738 341 -354 525 -40 164 451 -971 -573 142 -920 -652 -68 -972 -140 -941 846 -812 772 505 -155 288 456 220 990 17 498 -855 -568 227 -259 -875 541 152 264 127 -444 -254 -685 -319 -745 370 919 -22 -764 637 -199 828 -313 680 -397 -814 152 -503 -68 812 967 542 -617 242 -335 -164 -446 393 223 845 -492 -918 -82 -985 672 251 -51 -785 412 268 -143 919 602 316 914 40 -193 510 -843 846 317 -233 420 -293 -117 581 91 -510 -882 326 683 377 653 -770 347 -920 930 41 -3 -646 -545 -315 -450 -974 -547 -323 -574 393 372 765 -511 -179 554 -676 -957 -475 -941 555 -675 -300 848 450 534 -790 -845 219 -96 924 747 512 -399
|
||||
826 968 -440 -111 839 557 48 252 -799 966 533 -262 -965 -45 709 -893 -432 273 -373 903 317 -163 -173 683 298 -667 168 335 30 483 -969 -450 -917 -248 783 -225 -806 990 963 -892 -599 -127 990 177 -629 -91 465 -752 -343 308 -696 320 -860 -112 345 -71 248 -150 726 -70 -358 -119 734 -680 198 849 137 -572 -785 -928 -446 417 -470 -905 -75 838 231 216 -468 -218 839 518 344 -867 599 745 -478 -312 -542 -181 798 961 -843 171 81 831 -627 -92 763 -679 16 -969 -424 410 319 443 -736 773 -690 343 149 297 183 92 519 -984 -358 858 -294 305 -928 100 -464 -847 624 -56 303 666 -218 -734 -686 -32 -851 -315 307 992 761 -280 680 303 -175 -135 592 -86 579 -416 -918 805 -677 -52
|
||||
-672 305 -686 -433 29 -863 885 587 -654 87 349 383 -951 -6 -865 482 -312 -564 -230 -532 56 -154 514 -467 -744 -576 -220 51 341 266 -121 651 478 597 -168 -606 596 -317 -555 -805 -824 -592 113 -96 367 107 -58 -192 -440 -257 -651 977 980 948 -805 470 326 -542 591 -549 275 627 133 -772 -524 975 151 577 444 48 -296 384 134 179 -69 -195 -334 110 -19 -313 -190 707 286 -431 -219 -294 -481 683 -194 814 719 409 -269 -357 -464 -617 -28 993 -849 200 422 488 760 -338 -437 409 473 -178 618 465 -825 -762 -411 -832 -458 665 -335 374 -837 -715 839 86 913 -27 -83 -649 -240 790 901 -67 -740 -566 836 5 -66 -705 201 94 -844 -77 -623 569 -626 -895 -980 800 -887 841 85 -524
|
||||
244 -613 -611 -541 347 -504 -790 430 41 582 -456 248 -927 -682 636 -815 -191 -656 -858 918 -621 -505 813 421 756 -269 985 469 299 644 394 -950 776 -840 358 -113 998 -256 923 427 -675 -682 13 -156 -255 -815 713 621 -211 -879 -504 466 -429 -824 -927 -387 201 -702 103 612 789 548 -668 929 836 -363 -469 -106 -263 627 -495 -472 267 194 978 636 -325 -593 -745 676 -408 -636 -437 926 -834 -162 118 -987 523 -320 -196 524 474 -71 376 505 -633 771 -452 -178 -914 194 283 689 -183 -44 -628 -409 84 121 46 -14 408 607 749 46 445 358 -672 353 307 -115 -459 164 -615 100 -351 -75 161 -586 396 243 -824 -789 -709 399 391 50 -278 -603 503 -281 602 -153 -848 111 -429 872 -43 665
|
||||
109 -695 914 672 536 -925 -806 991 922 -522 39 238 -206 423 62 313 713 129 116 -877 -231 134 500 -925 707 660 676 744 119 -206 420 -891 -967 -320 232 -409 115 -421 521 705 -904 597 971 235 -72 897 385 989 566 142 -569 -504 -11 -754 -7 -412 284 77 -832 -801 164 -350 -907 329 871 -785 388 176 753 213 331 -450 659 852 992 -558 391 894 390 -569 -848 -5 115 -632 -223 44 -938 310 122 914 -853 -295 383 -482 -257 673 511 341 665 -317 -757 -865 -895 -826 -63 -677 652 880 -55 -435 -597 259 -888 -338 943 336 -456 832 -545 -399 -727 285 768 -249 -3 -389 382 -486 920 -36 -292 401 707 -351 782 -768 -508 -635 -692 -191 -21 585 -691 -545 -50 659 675 -544 -779 924
|
||||
978 -921 487 -180 -73 -930 648 -495 -339 171 773 -539 -792 -935 -492 -522 -51 -806 149 -137 744 62 -623 375 -886 29 737 -141 -896 -609 -203 -630 -503 404 -554 156 -648 255 -251 430 -795 817 536 716 -223 -793 423 -985 -901 210 -376 552 -602 -279 -552 951 -230 -884 -586 102 883 -939 -258 -637 -631 -689 -289 557 378 -875 -31 689 615 512 762 -437 109 -647 -776 362 487 314 400 -97 953 348 536 156 655 307 -758 248 -987 463 862 -85 850 708 826 974 448 959 -687 -451 75 -168 -683 -251 229 -489 -278 -739 -73 -720 347 -817 -369 154 -78 -718 -445 -351 -223 860 -84 -42 -996 -490 688 130 -284 -308 394 -649 393 -226 451 996 616 -208 -770 -42 54 -973 -509 661 562 743 876 -754
|
||||
-196 -189 -897 307 -878 -14 105 667 304 982 501 -47 612 -434 -836 927 -663 966 294 544 -994 -437 -747 403 -952 886 -35 -867 951 855 -472 776 -859 -31 917 -873 -139 -713 -380 -802 146 659 939 -515 -995 -285 -403 828 288 191 -470 355 -115 -423 -572 -648 -240 737 758 -764 -17 -600 -782 112 456 -71 838 339 669 -900 -844 -22 -55 413 801 -802 133 120 931 -130 227 -651 -499 -68 22 945 -976 -888 121 -277 -520 513 631 -956 484 -70 -787 -695 -121 -775 526 447 626 -469 -82 506 660 201 -992 -827 340 -594 -841 -276 927 -76 -509 46 -813 -29 -469 870 -833 -623 777 -594 515 -322 191 647 -658 474 231 940 246 -359 610 -591 -213 607 610 -904 -84 -169 -861 726 -870 -741 133 659
|
||||
78 412 314 -463 493 -27 963 693 -221 -172 -977 -532 227 -259 637 -83 772 -315 -818 -182 -280 -833 339 -529 361 96 948 -361 -213 -933 208 -270 -809 -745 -755 917 -345 -333 -444 284 -779 -537 -807 390 238 -508 197 424 -683 -288 606 -804 -754 -900 410 -368 -714 200 -21 226 514 -866 410 587 698 771 -683 578 375 -370 -166 -528 284 420 709 -512 590 211 794 -946 88 -198 -497 662 -182 -815 487 -119 -53 212 598 207 -9 -533 -857 856 803 -498 -172 -559 854 734 860 -395 541 587 -869 -885 -959 -271 794 460 -198 829 224 685 -548 -187 430 -69 98 -292 -434 -876 -445 -771 808 145 -60 -338 453 346 -194 535 -212 212 -678 823 -911 -279 202 -716 -49 -175 -864 -802 -12 -142 985 -403
|
||||
-468 447 -105 987 459 102 781 519 341 75 -578 838 480 -771 -309 -676 616 607 99 -852 -225 -259 811 593 -386 314 145 -828 -222 574 758 -642 -463 -539 -376 50 -975 64 -537 475 -362 66 -682 921 -67 777 277 -791 -247 -498 -268 361 -492 948 -784 773 -648 -234 935 -168 -167 828 301 -330 -412 867 932 929 868 -651 494 -332 -595 -846 -853 665 985 -898 170 -31 -231 -443 -762 -170 -509 314 -6 656 162 206 441 -254 326 998 -688 -832 60 21 -911 427 -154 -315 795 -327 -206 -261 513 -617 -579 -79 -628 -1000 460 -726 -45 -284 -414 -75 -168 -988 -912 -286 -410 -815 -90 -275 -623 -655 -455 721 -436 588 89 993 579 -757 -460 561 826 -118 -810 476 -14 -301 776 -491 1 -931 74 -50
|
||||
372 657 -567 625 951 -608 -169 614 -876 -359 -108 149 -151 419 160 -425 660 -339 -763 126 530 321 798 108 683 573 562 881 -577 -185 -934 -688 -443 890 -20 832 539 -46 250 -567 782 695 -253 -864 786 -239 -869 -569 457 -478 972 -583 -894 463 767 -916 460 20 -511 -1 80 -202 609 -408 -250 -301 85 -161 376 440 768 281 -522 -103 -208 -812 384 -597 -831 -693 335 -748 963 -258 363 667 686 690 -103 997 240 399 -962 180 -471 56 767 240 -607 858 -304 -418 -530 -732 289 -708 -219 -568 481 -838 292 -717 -201 -253 -736 -215 57 -295 282 -542 16 143 502 -903 -440 630 164 401 948 -792 -853 -296 292 -276 177 46 -571 66 725 363 -850 -709 379 -528 401 351 -307 833 -310 -6
|
||||
801 -47 833 430 -893 -96 889 -448 334 -288 -483 289 809 -673 631 718 52 -712 -92 -125 -579 -349 111 827 457 784 220 -166 -396 -173 -802 30 -131 71 796 112 410 -512 198 -12 -419 858 761 -660 -592 -327 -320 227 49 228 -357 273 766 -984 -327 -241 13 -887 945 508 -927 -19 414 857 -118 -758 425 -933 677 -143 -265 147 93 -593 41 88 -15 899 -440 970 -718 360 803 -291 -622 401 42 835 -987 -303 816 -368 -44 -649 -122 160 501 937 739 -562 -907 -566 476 74 -654 -45 911 -614 407 82 -119 -771 -940 950 -72 918 391 -551 364 -950 -448 990 419 -210 330 -655 -53 -252 -131 -887 493 780 -368 -420 244 -968 81 93 -253 438 -559 156 -564 -521 329 970 -63 733 -168 299
|
||||
-615 -829 -53 -148 395 -190 -909 -221 370 -405 255 230 -910 -448 -348 -413 -433 -32 595 466 -344 607 492 993 91 779 -903 -165 -474 214 -367 -996 -935 -904 160 374 -347 118 255 480 -433 706 -724 -624 135 -928 303 -608 -716 -924 -218 726 -201 -351 -232 -84 -623 407 492 -27 427 724 503 339 -778 21 -350 489 -548 716 849 -22 -554 -55 731 650 -300 -437 484 -54 250 -165 -126 -791 -444 981 -317 856 774 -828 37 -28 -156 -220 925 113 -701 320 297 -486 -881 29 194 902 918 -382 -990 -41 194 -443 65 636 804 -37 660 272 233 460 -105 -265 39 -266 -549 -145 468 202 712 -267 -393 -663 29 384 -584 -192 554 -156 551 -3 -843 824 -42 903 -226 809 515 -273 840 661 -914 -806
|
||||
581 660 111 640 122 162 -683 967 6 -452 -638 491 594 -575 108 225 -392 -600 899 -493 741 -869 992 343 -518 -79 -310 -744 -460 -79 -794 -830 -985 251 643 -332 -974 248 -493 -660 -850 456 819 446 -53 -411 67 326 211 -745 -801 -905 181 -618 571 -30 -161 54 -470 -998 828 31 893 -813 185 323 -900 -785 -311 -837 -773 368 -616 247 610 997 880 341 52 -121 -400 -940 398 607 393 -424 -741 100 -21 -586 -704 489 -640 -507 -176 565 662 224 -537 -98 -572 -884 -598 817 -18 411 -84 108 -84 -7 947 817 -226 -318 -858 396 -152 -292 668 -727 -412 -546 827 -557 -287 -427 370 912 -593 -248 493 771 813 425 793 -601 432 524 485 -264 -813 -247 -162 953 65 572 -881 -284 713 -867
|
||||
-969 -768 175 240 -803 440 792 93 734 -428 -167 -890 49 489 60 331 -588 -291 978 -1000 -488 196 -442 -482 -349 -984 -505 455 230 -677 -345 -546 -497 755 -951 -520 -643 -277 -612 905 -907 -12 338 419 115 973 -236 569 -700 866 599 -162 -251 955 456 -187 840 -864 569 255 -21 96 665 310 57 -739 -577 244 -434 -513 534 417 -925 -224 756 -618 -752 822 -235 -212 -871 -810 -648 -939 741 -652 338 971 549 -863 856 -96 -278 -101 199 -326 -595 777 405 -614 -402 -805 -835 475 -641 -330 -42 -80 771 -563 234 648 -405 246 279 660 -408 -490 753 895 -234 -726 -837 604 806 468 -519 258 51 897 -7 611 -866 -467 911 -369 -955 590 -805 -172 -319 -301 410 -987 -150 209 404 -410 147 -507
|
||||
46 553 511 115 707 -924 291 359 -784 -893 -88 -572 -195 -169 -108 -969 215 273 -1 -138 -110 -567 -774 -541 15 886 431 -149 -780 879 -745 568 94 -549 -684 -234 683 569 337 -541 90 954 897 -976 667 364 533 244 -96 -135 -193 -837 -264 -698 515 940 -799 918 227 -396 -116 -380 235 265 796 906 -335 299 -499 -247 157 267 509 231 -820 388 988 -386 466 955 -380 -18 -569 940 967 542 -736 653 406 -290 -499 4 -227 578 980 556 -311 304 903 -322 502 546 -794 878 962 -559 455 625 914 -328 514 995 55 -536 301 -175 -841 140 515 -716 447 59 -391 -940 252 -113 364 474 -723 -188 -502 256 780 451 -310 -528 616 -485 690 640 441 941 -855 -928 -792 -626 102 897 -277 620
|
||||
-389 -409 -640 -305 88 -63 -45 -375 228 -264 -779 732 42 145 12 -995 -685 802 137 97 -673 192 -312 -818 329 611 -794 883 697 -442 -254 13 245 -892 299 -160 -364 569 -847 931 -389 -753 352 238 -732 -339 -477 -923 -719 602 -708 -850 162 -391 745 -726 264 -340 -135 -14 409 -865 572 -990 -213 -829 -694 418 427 -918 739 321 -443 721 287 -949 -199 180 906 379 -260 -290 -75 -123 -320 139 -302 -564 909 398 496 -182 467 151 0 -825 -428 -528 -474 -131 217 965 -936 -824 -914 -17 622 -561 -656 -689 622 -195 743 388 -645 443 902 -408 -104 625 -801 942 -836 -587 14 -919 306 -231 750 -422 -161 472 310 -319 240 190 -489 457 -702 -717 -180 292 586 -305 912 -82 -256 -579 -896 500
|
||||
772 -881 660 -510 63 -829 574 493 -557 215 -603 -1000 701 313 -884 -544 293 291 790 -814 -679 -461 141 521 871 984 -69 824 -960 956 -958 -109 345 -708 727 -712 886 -632 654 -316 -175 131 -754 -669 692 -791 541 -952 306 -645 -407 -911 618 564 -747 -949 -384 -377 757 -807 -115 375 -825 287 108 296 -84 864 468 178 584 469 -930 54 859 -238 39 133 673 -286 972 820 564 -635 -748 -659 116 735 -307 -150 356 496 -173 -607 586 -463 -849 -972 -346 -894 -222 366 857 -190 -204 -70 -616 -701 -968 816 -486 483 -977 934 -71 913 -485 -156 -539 -214 508 935 875 516 -718 -175 -860 -484 654 -259 859 -22 695 -223 -862 -841 274 -576 269 -936 -334 372 219 608 260 216 -797 574 249 918
|
||||
545 -476 91 -25 -249 -107 196 137 585 409 179 -644 244 475 174 -107 29 -843 1000 693 27 -166 243 -902 665 557 -568 -629 960 -332 960 278 138 -600 -998 30 -775 -614 754 53 -857 -402 -557 -921 905 104 836 906 -675 -213 991 -51 -259 -736 -215 487 608 -90 -745 -76 121 351 -557 817 -591 167 -678 -972 743 465 -341 477 -726 -85 -987 259 135 -854 -840 14 279 227 -58 -713 -387 -448 -954 -286 865 409 350 -22 -784 -756 749 -469 42 -834 -808 280 -14 -645 -298 752 -287 -269 -653 786 67 183 7 -363 169 1 135 -150 191 -492 196 995 450 -341 112 365 34 92 436 858 -210 -87 -537 -94 -717 6 -596 -942 407 549 8 -514 209 641 -866 824 289 -955 712 -695 572 970
|
||||
-346 -41 4 795 716 -275 858 -381 -534 -240 -554 -880 -680 -637 -389 -447 -870 886 810 683 909 60 604 244 563 -753 -737 -693 487 815 554 428 -233 -242 -881 -141 653 493 888 -249 381 -272 -988 -102 813 756 -38 198 909 -646 -915 -607 -491 -153 216 97 -60 -552 454 720 -309 283 483 473 -274 163 -28 261 157 912 173 -494 4 72 -938 64 590 -400 -390 -781 773 -679 128 -424 -384 266 -678 -570 264 111 -621 140 -25 200 -352 -681 -508 -907 116 -372 166 -526 -848 -708 -477 146 -514 -10 -64 -284 626 171 -214 213 -939 858 -225 23 874 -700 -584 723 -776 -479 -838 -127 309 814 848 -304 768 -730 440 87 217 -726 822 -999 -197 618 -231 -993 -190 -659 -649 -80 -726 -285 -648 -862
|
||||
984 -792 -735 451 -26 512 -105 976 3 198 981 -50 -193 -6 -697 -201 790 414 -882 686 492 76 -623 -336 -885 -404 805 454 -351 -859 -877 -921 -593 -124 -907 394 176 -455 586 444 -248 -565 -710 706 112 532 763 678 729 -102 -96 649 -847 239 -759 974 -87 751 -292 -361 -882 -820 -790 819 360 -624 -910 -530 493 976 -943 -989 440 937 -124 528 -180 -287 -944 598 21 257 -11 -484 -670 256 320 -575 -462 675 -86 930 498 954 -483 609 -371 503 239 259 -260 324 -516 948 -893 -844 69 -541 721 357 11 -193 699 860 982 981 832 812 787 -691 737 89 19 -276 715 -812 136 -746 553 -181 -416 946 807 -843 861 326 380 507 -667 935 -756 -640 860 639 -836 242 575 -697 266 -67
|
||||
254 349 467 -869 697 -137 501 910 842 -691 336 -802 -455 492 -302 289 50 -288 549 -212 97 199 -214 871 -771 -95 -127 230 -653 -767 695 153 613 -767 163 -768 -501 -972 -185 -702 420 908 -664 -98 657 -387 -390 714 -122 662 493 170 755 -212 965 987 910 -517 942 -788 833 91 -276 -249 -134 -233 -568 -9 -266 554 -755 628 -627 326 962 -947 -713 -502 -271 -295 -242 592 -150 143 -26 -464 439 -750 -767 -945 -951 308 -630 467 531 245 -688 902 -63 -49 -815 967 630 -99 229 426 -841 537 116 -294 502 866 230 486 776 -996 698 468 963 717 -732 -445 715 53 299 -995 605 50 -26 67 -149 -54 -446 698 878 508 127 -535 114 -572 -976 817 -548 -729 -330 -301 772 795 -525 -46
|
||||
-329 840 537 -962 -286 -621 -319 -577 158 -603 102 512 370 -560 147 -957 -105 -45 -180 115 317 -370 -715 -678 186 -95 -950 -556 -716 -636 -772 636 637 143 -985 828 -635 -876 -66 515 -821 592 -930 -599 -174 526 83 600 664 505 -227 -730 707 954 273 -966 861 311 785 115 288 -612 -665 -383 305 56 308 -83 584 -295 942 -513 720 -519 -744 -752 -853 -942 -310 947 707 384 180 932 535 -522 -333 -516 -795 -798 134 -204 592 1 -621 90 825 -448 -530 929 -266 -250 598 651 -256 -699 337 -736 -584 140 138 23 -47 -435 -150 -423 25 -778 -31 347 -313 774 45 -659 -600 -161 904 807 959 797 302 224 670 -220 -722 474 822 -223 -945 316 345 784 -194 -566 774 -925 -420 -2 -492 273
|
||||
-313 221 764 -526 -144 -398 -483 -731 -281 602 -569 -417 -460 -383 871 245 -304 913 389 475 -254 271 -870 768 -140 -924 213 -114 -750 -711 238 333 -652 -977 440 800 615 345 -758 -260 -455 -252 205 783 -19 928 -480 940 -311 167 242 -361 -534 -511 540 181 -605 -448 -388 73 424 506 623 835 301 -234 -24 -963 -960 148 -343 -365 -906 -234 -134 -734 -215 -857 463 175 420 524 288 -561 -295 443 921 37 -678 78 740 331 300 -993 233 388 964 580 924 651 294 602 476 -965 -882 693 -351 -149 -296 421 724 455 316 320 -840 884 -448 -87 -146 76 683 933 -831 -20 -620 -289 -652 622 -857 -706 -856 533 -851 956 222 -948 952 745 407 -865 -487 99 427 -510 541 823 174 -226 6 -108
|
||||
-345 480 754 259 -689 780 -77 100 69 865 -226 170 611 -924 -230 -857 446 682 -448 -143 936 514 868 248 -513 604 191 481 911 412 655 -95 -991 -136 349 -86 717 -87 -972 993 781 621 849 673 166 893 212 -471 32 314 -536 -847 269 468 -142 42 830 -921 -5 384 -572 -695 -631 236 -641 -465 660 105 588 -377 491 410 453 837 135 908 -322 -933 71 81 515 -510 536 -170 -900 -18 788 931 -291 147 -253 -858 -297 912 113 786 967 16 -613 183 -894 -837 848 67 -265 279 -724 -796 -753 531 943 -417 -562 -724 -549 326 -106 -689 -828 503 -353 -766 -377 301 585 24 672 381 871 -33 205 106 634 -957 990 25 272 995 955 903 -152 -730 -384 -522 -935 220 31 -236 -906 510
|
||||
649 129 27 617 101 -994 32 856 -542 -164 -62 -111 -916 -601 -208 147 -262 -150 -596 -735 -71 -420 -659 -402 655 728 823 -858 267 369 -380 103 33 -666 429 -743 236 186 376 -680 -849 -352 -643 883 653 700 634 414 -26 770 310 -20 196 -455 -879 -833 -661 211 -25 -898 -734 341 275 12 -49 649 758 952 -345 83 49 589 -84 905 532 339 471 -634 806 672 657 -760 792 406 -658 19 -888 791 -759 598 -842 -155 738 -138 -340 972 -431 843 -15 -787 264 246 298 93 519 -789 20 -350 -295 -360 -881 -129 -450 -716 990 172 834 740 977 651 -671 -662 -963 -597 162 -210 638 -530 608 -241 -697 290 450 797 450 -713 -61 801 574 -644 182 -931 420 -600 -635 -22 -540 240 -118 916
|
||||
525 -883 -399 -579 -300 -662 -805 -944 -661 -628 18 688 -776 -752 -747 -333 775 -770 -370 858 -729 -553 648 965 642 -780 602 -5 821 -616 640 315 91 -177 942 41 591 -227 837 -942 480 -638 121 -285 574 -12 -608 -77 24 -286 -151 -345 504 15 -801 527 678 -927 766 -417 92 -20 -854 972 -684 -671 -851 -56 924 572 640 -933 -811 -915 428 309 629 -588 222 712 -323 -725 -614 -184 363 -622 565 153 -842 295 -460 -459 677 -525 -221 936 968 825 877 446 336 -150 93 97 555 325 253 -216 -330 -269 -526 934 -714 -827 922 292 -141 414 -420 24 -285 -158 -52 -873 -501 505 -329 -510 301 79 -773 -290 902 -417 -181 872 -73 -209 96 390 61 967 12 -420 580 -697 -58 262 172 255
|
||||
288 -382 -343 -150 -195 53 -638 -934 877 34 571 -988 7 188 -442 130 -643 -112 -72 194 -578 75 617 -541 583 320 153 -999 578 -49 361 -29 -646 349 474 -983 -350 -669 -517 -370 -518 -491 -718 -969 -86 3 835 17 800 -159 -262 560 209 -205 64 -400 864 -696 -500 -747 368 986 -167 -326 -181 363 975 -94 -798 763 -943 -9 143 -198 -508 204 -498 575 -633 821 -277 310 -7 489 874 -344 727 803 -141 -710 35 628 -961 448 -406 -486 -563 -110 -809 989 -95 864 22 637 242 590 939 -923 -810 -295 -285 910 622 -67 -236 -953 -314 -415 636 554 675 -442 213 251 -6 997 208 -806 -451 233 420 482 -89 846 -388 157 896 830 600 589 -614 793 953 -533 -457 -404 -970 932 -424 283
|
||||
873 -579 570 608 748 -137 -513 753 -505 273 -958 -20 326 472 664 187 142 -649 313 133 760 -185 -660 166 -478 348 170 450 -484 198 545 873 -131 56 185 -443 595 -624 -398 -344 402 440 312 141 -311 635 -613 -743 699 -159 141 -354 589 627 -223 -124 446 266 975 -361 -385 150 15 -119 991 456 362 -235 324 -474 662 -724 241 -97 202 -966 650 374 -780 -521 797 234 918 -200 -427 414 -750 -968 358 -540 752 -670 848 -286 -381 -566 -549 791 -673 969 -624 -952 235 -964 785 -285 -889 -371 716 -695 -663 186 711 579 -619 -935 686 -378 994 278 -691 342 966 -975 -31 -232 637 348 40 454 656 86 989 674 -112 -13 -999 886 -789 -433 -485 270 -562 -821 88 -145 265 -545 -634 89
|
||||
959 -631 499 816 -781 909 191 -990 -484 585 -534 846 -255 -453 764 -208 374 -546 -551 -578 553 596 -284 386 56 368 682 179 487 67 -265 -611 891 -359 -586 124 111 -145 982 -648 415 954 466 205 -103 -803 479 -184 348 141 -227 675 -122 997 11 512 -509 -537 -3 204 680 -877 -50 -552 -254 -34 912 -261 818 -951 -372 934 -199 -587 686 913 -252 -86 -263 -764 -251 -645 905 959 289 906 7 197 -556 269 982 540 824 -969 251 131 334 957 448 -71 426 -623 -114 -130 681 919 -509 831 -593 -409 -380 488 471 -627 -662 -669 -301 -983 -214 -205 338 622 480 796 -672 414 -117 -861 -994 918 -379 974 740 861 -574 210 781 461 -267 -834 -540 827 -667 -705 639 387 882 -454 -677 193
|
||||
499 153 318 25 -48 190 -751 -685 -949 -834 51 -831 -949 -670 -582 652 292 -651 -714 851 -636 239 870 -683 -287 480 -821 349 74 -576 822 755 -871 34 693 -110 454 574 -868 -906 325 649 318 477 -403 981 -959 -961 506 170 395 319 -160 -258 -663 194 540 714 932 122 544 -532 52 449 -438 -378 -519 154 -151 -444 -981 142 889 786 218 -675 531 -98 226 971 899 908 178 -931 385 -941 987 595 -258 -211 120 615 678 -248 -59 -745 813 -937 238 -524 -289 -197 -619 -811 -43 -334 768 -864 -831 917 136 -528 407 307 801 49 821 -419 690 333 -134 398 -394 -471 638 449 850 355 956 585 510 -53 -11 -816 -724 -499 252 -604 112 58 -653 -766 160 -95 -30 -21 988 -222 -163 255
|
||||
-92 -164 -109 60 -479 -516 -410 -835 -101 439 -614 736 -284 -790 865 18 35 683 288 -134 551 -833 431 361 -801 -85 -933 -961 -423 437 788 -891 -539 -97 381 -16 -775 -542 838 881 616 383 -211 229 609 -693 637 245 741 -850 826 -284 815 854 129 -712 -920 -513 762 -381 524 267 -731 -414 709 -835 -258 -104 819 -478 193 279 -595 910 667 -349 338 -734 987 495 265 321 -654 39 -377 -497 119 97 -263 -458 -836 -784 -971 -230 494 18 -503 335 -784 -220 332 -67 300 -251 -633 -975 385 247 -927 -152 11 728 -151 129 278 -787 472 300 58 536 23 -130 996 903 -366 433 -853 636 645 763 -428 781 -980 230 174 -686 -364 -948 390 864 -652 938 -517 963 141 -370 210 693 -518 -476
|
||||
-210 -236 350 -237 177 564 758 -248 261 -278 -603 112 406 -13 -912 368 284 -185 459 955 939 -602 963 30 362 22 94 -884 958 -172 -57 237 -550 -287 220 -224 349 -408 267 370 -581 797 633 -390 888 532 -546 -83 110 277 -355 596 -538 740 85 -850 975 -280 -161 259 885 -753 960 732 992 276 495 -723 -470 810 -499 -192 -458 -473 576 241 663 -442 302 -955 752 125 -924 -61 -122 -128 -839 125 -268 -332 155 -928 448 456 327 -527 -850 -525 84 -536 177 378 -288 869 -937 -961 554 461 167 -540 -846 652 -375 149 317 -404 -763 -651 381 -906 760 558 397 -827 -914 -327 -278 155 -665 -724 218 -28 -88 743 761 986 -266 792 366 -922 333 460 344 -37 999 -166 167 -854 488 -152
|
||||
882 -398 -648 392 223 490 -440 -780 560 -292 -224 -859 -758 35 999 19 -894 -540 557 -288 330 10 890 -951 -645 704 -688 48 999 778 -153 677 354 123 947 -99 -942 -734 998 -546 736 192 771 22 852 9 -20 43 308 30 288 720 886 894 -411 926 -542 675 -619 -997 -151 78 -397 -691 620 -792 625 -314 74 -23 -875 688 212 82 903 193 8 193 -974 -874 -301 191 -789 -593 288 622 -800 951 620 709 161 76 162 406 571 -353 319 -68 -456 396 735 -559 -225 -974 -769 -290 5 -472 -463 -798 931 946 -365 373 -887 -680 184 -272 -872 678 504 -952 -229 39 -108 -58 -711 -886 -597 -523 -625 -474 860 135 -878 619 -909 22 738 475 -705 -473 57 -381 -929 699 -303 -98 147 -255
|
||||
-151 150 -727 -975 -6 -278 627 451 746 -745 513 -771 179 418 -76 -791 300 -912 -562 -958 540 -249 15 445 -792 549 288 420 -534 -387 982 555 941 573 -98 99 -250 -110 -683 -323 -351 696 -821 353 -552 668 -298 -912 448 -777 -249 647 -836 -822 -439 446 486 248 -311 -405 968 -435 664 157 289 -404 471 884 608 452 -142 -427 -64 -551 854 -907 210 339 543 413 -989 363 -422 755 874 -162 783 -792 993 -125 -315 387 -110 -564 591 639 319 -725 -689 269 -859 663 867 -991 446 -657 -980 452 -388 502 397 416 -330 -85 307 -1000 -329 -28 473 -409 335 -759 -904 411 -424 -854 937 344 918 881 -396 -529 -310 893 284 -357 -184 -735 -540 -603 -63 -160 -215 -695 -902 -315 -456 -113 -160 256
|
||||
-755 -57 109 -789 -235 686 -583 -638 691 467 -687 -549 -288 113 561 -677 412 182 -455 -581 -411 721 -124 339 124 -293 118 550 -100 488 889 -249 340 837 547 -474 756 381 656 370 468 194 -632 -958 56 864 693 -833 -87 -392 -349 -782 513 -14 903 709 -398 -902 245 426 -523 773 420 327 -887 -797 -608 218 441 -101 822 -250 -59 -192 421 -888 333 184 -625 305 -818 571 -602 -183 -728 -159 857 587 740 -445 969 710 -119 553 345 -158 396 -112 -361 -848 322 -854 -810 -972 542 668 401 -826 -529 -702 -421 -716 -459 270 -345 -26 427 -904 985 -55 -535 -372 -466 700 -98 388 218 208 687 193 689 32 595 624 -485 144 435 -746 646 -357 704 -461 474 432 -607 643 -92 822 -307 -739
|
||||
-753 -721 -317 -780 562 845 471 -304 237 991 -431 -230 224 -708 -131 652 616 -400 -138 -483 856 -698 -657 341 734 135 399 -507 79 816 -797 -755 106 259 955 -665 850 256 -622 -703 721 938 745 -861 -966 -592 29 -840 -118 -13 -28 -443 668 180 -314 19 -600 -814 -714 477 2 956 543 867 354 988 -201 479 -375 -342 -55 854 -253 353 -460 -610 567 759 -370 -673 -684 -522 528 -953 336 485 -452 628 -90 269 711 -634 748 -457 381 -825 -989 -805 967 -194 722 -729 833 -541 -991 838 507 -398 184 149 -327 -89 498 505 -180 -942 374 33 680 607 673 228 994 598 422 -413 391 170 -785 -123 113 -521 -160 -682 967 -17 709 186 -710 655 371 746 474 6 338 519 -902 510 883 -287
|
||||
569 687 174 -951 232 338 920 -664 -170 -728 773 686 792 667 138 593 -695 -97 471 91 -568 -384 818 478 642 749 -704 -701 -982 -662 728 140 -316 602 -247 -632 -524 -322 -181 -942 438 -464 -301 544 104 421 838 -927 972 -325 -55 -2 167 -813 -640 -894 699 581 -860 874 856 390 605 -101 -649 646 -466 -44 956 120 69 194 200 -886 260 86 -430 -451 998 -845 84 -608 179 -236 148 97 -361 584 593 -156 -892 -221 -245 -220 -153 -842 558 137 -76 277 -829 -721 -820 -333 -777 -970 505 986 718 -959 988 -540 29 -123 748 421 359 958 -563 -149 707 -806 -414 204 -515 923 -11 264 118 -252 725 366 896 867 540 -37 -711 -568 -903 -830 -279 -426 132 -753 -382 337 586 544 118 -458
|
||||
-451 434 -633 886 -72 863 -855 319 -449 13 -182 -118 737 -551 253 549 -550 61 -957 956 -350 -256 -702 129 -151 -488 -413 -178 806 -163 541 837 242 -135 -487 -802 -932 -785 5 632 -953 -848 784 197 -237 852 -654 450 -240 227 -967 147 -101 -105 -5 168 413 -167 958 -920 -525 -840 -196 499 309 821 -201 992 60 814 -795 -606 -560 26 -315 260 -231 -620 614 252 -6 -874 580 -298 -248 -926 571 -548 -332 244 -952 453 95 664 290 -527 506 299 -703 518 662 478 -158 474 -662 224 -427 771 -826 -907 -21 -2 567 -510 733 759 -70 -821 -484 397 -233 -463 -684 -705 -611 -54 -239 607 -917 -421 70 110 326 -554 827 479 374 -66 227 345 -880 -653 973 -287 -365 292 -50 772 362 -33
|
||||
910 -891 -158 832 -383 731 319 -575 -506 253 100 -936 71 -608 645 719 -224 -173 -46 686 -88 620 921 -572 -840 400 919 426 -624 403 -626 924 173 998 -956 157 893 475 -342 529 -123 295 705 175 107 254 -782 -312 -237 277 -608 498 -364 960 337 -313 978 -728 56 782 461 -155 -777 -439 738 976 982 -528 -52 -7 785 515 -75 92 611 85 -135 -908 -863 -513 -960 -667 -293 179 -744 -59 -376 592 -923 313 -838 -481 -965 -31 491 -861 485 941 -242 543 534 854 537 720 265 -199 -990 615 -528 -864 485 -944 -700 621 527 369 -625 948 498 -503 -49 -633 -650 248 -723 33 880 -128 348 176 444 -853 -903 -474 -947 871 -107 -461 265 230 -608 -657 -197 -177 -251 -56 617 -760 -750 -582
|
||||
616 495 947 -672 -357 763 523 203 631 -384 110 -235 425 488 -609 780 949 -582 -312 -705 14 -364 959 451 35 -674 -874 -427 -642 216 -563 11 -581 -373 726 306 751 -13 303 75 277 -914 -188 -978 400 -292 -52 73 -950 751 -301 -512 -924 -388 635 459 -337 245 -917 -577 -108 492 -56 366 266 -171 751 768 -416 686 304 72 -979 537 5 -529 81 146 -536 -29 504 530 122 553 -257 -651 -86 -14 -491 746 -524 89 268 -883 693 594 -518 -669 -146 765 -944 240 -346 184 867 -609 516 338 -665 324 926 494 -405 889 65 -685 -268 356 213 -761 -486 551 -455 -620 102 -184 371 840 659 -8 -198 -766 271 294 442 741 162 365 375 51 -72 718 -789 100 432 -776 -540 961 -201 833
|
||||
-30 -94 724 -272 -802 -950 -694 947 -306 -527 636 414 329 -744 41 609 -449 367 910 139 878 -600 603 557 407 -631 -775 -499 382 633 833 -320 690 200 -566 653 -52 -163 87 -495 -897 815 387 314 281 -45 -509 330 -541 -58 512 -169 619 -52 -26 408 -164 224 960 5 554 -232 866 789 303 -108 716 507 -14 99 -802 946 912 -254 -659 -436 -537 -56 -228 722 -809 -444 -403 965 825 -128 391 670 720 -723 -939 56 953 572 740 558 181 -970 -868 -903 -861 -390 370 856 -686 283 -329 -668 405 -576 53 632 171 -894 853 453 -785 -424 -57 -597 952 -473 -615 462 610 434 -96 153 931 252 893 -184 -541 -327 -870 751 249 -746 -448 958 61 -270 -941 727 492 -81 812 -591 145 -413
|
||||
-666 322 -961 492 226 -203 -765 47 -363 -269 -706 236 955 -794 -130 56 794 588 -554 -971 228 -583 -65 276 813 -492 -276 888 -86 326 -507 667 105 -916 103 449 845 575 335 -316 -24 442 696 -668 516 -757 508 395 485 606 -535 -996 -595 128 245 -517 -982 432 830 -722 323 -669 -191 689 -914 994 287 274 -542 411 796 -203 850 618 -924 477 -856 661 260 -521 -731 -410 -722 395 -102 76 -84 713 405 37 -980 -687 566 619 -899 -128 220 504 491 -666 -645 46 248 -109 -23 -852 -860 469 -42 -981 -577 376 602 70 220 -646 146 -744 -281 237 -775 510 -419 656 348 169 -309 976 37 278 170 -973 711 -891 -369 14 -147 926 -660 -802 614 -32 -735 -575 750 -741 428 385 727 111
|
||||
165 554 155 -507 955 -975 -55 -132 -33 -938 534 -186 -307 -360 -922 744 976 -931 83 -269 -889 -432 -108 -116 -738 837 392 -137 -969 -605 406 319 265 654 219 600 711 780 356 -704 41 -16 -567 -809 638 131 -132 -24 -986 151 890 -668 934 -613 165 6 -254 598 204 449 234 102 -567 -361 -959 -262 -676 655 -298 354 -270 -560 -321 -702 -585 -465 -792 780 -631 660 240 303 556 800 79 506 236 15 -4 -89 -494 -726 -381 -86 -232 -59 920 495 -782 390 369 -643 138 992 -573 442 300 393 -286 -227 964 -583 -252 793 55 301 -426 -20 -987 -42 304 401 809 423 -380 433 -976 -781 -605 -473 -442 182 -50 519 178 -140 -250 565 -428 -510 -659 929 -55 682 -639 -530 587 367 -931 -562
|
||||
813 773 -694 -935 402 695 88 -116 898 -335 350 -395 531 217 -64 364 783 -811 -722 -228 108 -158 893 -524 285 154 39 -528 -504 -580 -359 815 -864 339 602 -252 -705 974 -448 51 -834 89 694 582 -71 -975 -644 -164 -461 908 -734 -787 -696 -984 960 -104 211 824 -51 -191 957 -523 162 -223 35 290 -224 -176 -489 610 60 -839 -520 -824 -119 247 119 501 -295 550 -896 -787 -982 726 -308 217 -971 -555 903 -141 -289 -56 -458 -733 341 370 979 -558 999 552 873 509 -737 -915 -33 361 -223 -812 928 -55 153 7 183 -634 -153 -479 -848 -592 -519 264 489 822 884 -578 -607 697 823 -661 -841 -317 -851 -637 503 831 -723 -735 -965 105 -525 -347 -439 61 -204 574 -898 -764 815 -925 -505 165
|
||||
286 -782 183 362 245 726 -114 303 -760 -555 -703 474 -779 656 387 898 -4 692 -27 211 -629 492 780 -563 -626 190 -14 -635 -920 -645 -584 8 -231 -183 -428 612 -404 -983 224 -985 44 -742 8 768 291 86 623 107 -704 269 977 -803 -89 -394 -431 144 -694 -580 -942 -701 -829 55 -322 -73 -405 474 -814 -842 -405 -452 644 361 388 870 432 517 -447 -188 -913 507 -646 676 -751 972 -669 58 370 -834 -121 428 431 -938 853 -86 644 963 640 -583 502 739 -247 -253 -776 -439 -643 276 953 -365 -796 -928 411 858 -250 823 -288 711 750 551 -893 1 192 503 -983 -418 662 -150 592 -420 -166 -47 -331 -447 -113 -671 528 -503 -549 602 552 918 -810 -642 -36 126 423 -991 -358 -470 993 83
|
||||
-963 464 -744 -299 -603 847 -79 400 -7 809 -472 846 557 534 56 -170 581 -359 -505 -559 366 923 742 -874 -203 -63 -933 -831 -488 13 -240 632 -298 436 -998 -59 469 -821 782 76 153 891 784 16 -259 -499 -252 -751 716 669 -452 -995 -206 902 142 -340 663 139 32 -243 43 337 -289 -97 -485 743 -784 961 314 857 860 758 -809 430 131 341 542 972 249 -854 332 120 -588 -71 -909 -350 753 82 391 855 -234 797 -72 -886 -13 -357 -891 132 717 537 -421 459 -466 8 -566 872 139 505 -489 -929 -492 -408 968 162 -286 -911 250 816 -809 -750 -860 -914 585 -171 -570 779 -539 604 818 -278 121 161 380 823 -765 -955 -15 526 -108 -945 816 -292 238 272 230 -449 -669 694 204 698
|
||||
234 -756 384 -203 -5 -582 602 -980 185 352 -422 -237 -861 567 -379 -795 108 846 -587 789 332 5 797 -132 -28 -565 -75 -81 -263 52 -93 722 -45 -862 611 53 -800 -557 583 -474 -911 -448 -284 411 -362 -782 -603 79 847 720 -76 -337 350 43 -911 -398 80 135 -115 232 -80 601 733 -454 -884 -472 -169 -702 -19 -455 -191 727 -45 -415 634 890 230 708 129 221 680 299 907 -884 -257 173 326 248 511 -143 348 852 -447 182 152 923 591 -326 913 -259 148 882 347 427 482 -954 -727 999 -91 872 501 -792 680 -991 -509 -247 165 -366 -801 -502 885 -440 -334 -947 33 174 -712 59 -303 236 866 229 195 -196 -15 -386 509 -967 -629 -103 -989 940 -956 691 234 -492 -380 682 -978 -179
|
||||
674 -215 467 -474 -852 772 -613 915 689 -134 876 561 -520 -220 944 -260 -823 -1000 147 483 -875 404 265 -240 215 -395 -666 -818 871 909 -704 80 623 772 -996 -710 -288 -554 -492 491 402 -667 295 171 809 14 -456 -64 395 623 871 -556 400 -211 421 -275 -703 -16 -441 205 -45 941 -327 87 523 -496 320 644 545 -45 -202 313 786 713 -337 142 870 84 -257 690 995 173 -829 922 414 399 203 -542 865 931 383 591 654 -923 487 64 -897 267 575 -740 -317 -635 -803 241 485 -320 928 -594 -74 383 246 845 -35 -254 -760 -593 624 -227 -942 848 308 149 237 519 887 -917 341 614 -912 -682 -22 -506 709 -454 -99 483 247 -902 268 946 507 468 441 378 -80 -175 370 935 495 812
|
||||
8 -233 602 448 815 -437 -799 443 -966 818 -534 -336 512 -106 953 334 -326 401 -85 -311 -846 71 780 693 -83 -574 -126 873 799 787 -330 -485 119 579 -369 563 942 -609 470 189 643 -803 -974 -184 742 -355 -663 25 890 384 499 512 -533 176 -707 -107 -188 660 377 -364 -248 183 167 -903 435 -363 -941 -11 -695 441 -796 -279 361 -925 -73 622 49 -638 -413 -286 -743 886 344 -528 600 -731 163 579 617 61 643 892 383 495 -53 -528 -283 256 -813 51 -856 -802 -301 654 -987 -453 926 193 211 172 -382 100 -920 -237 -53 -403 -717 695 -534 -80 687 509 -911 -180 -625 -358 770 -334 -616 206 -325 -731 -410 -508 712 -537 -163 568 916 83 761 945 -4 608 99 518 -564 -394 634 -503
|
||||
-122 170 381 -755 120 -174 178 634 -359 -498 -245 -929 366 501 -917 -964 730 298 -426 -475 -476 -198 268 456 -230 824 119 -246 946 -822 -784 -472 752 63 -919 10 413 -545 871 639 -398 -67 -49 70 -647 -986 30 549 863 -328 -534 -670 -849 244 -835 -1000 151 737 572 -349 -330 655 -672 -630 933 -951 236 568 -886 360 973 740 -692 -399 973 415 -616 -487 338 -834 179 -887 551 -527 952 -870 540 246 382 56 -327 -226 118 -197 -433 -855 -382 572 383 929 817 -352 23 -467 347 999 -124 -222 -500 706 707 59 796 978 845 -302 245 -496 655 27 -540 -766 -814 -648 806 544 -193 357 -563 -837 748 -785 -836 -765 809 -859 -965 -563 862 709 -770 728 947 -684 -945 -922 -959 -760 534 -122
|
||||
159 -25 561 -853 132 -588 346 -364 46 922 -384 657 -559 432 -799 867 224 -98 -650 -772 848 -410 693 -428 -682 702 383 -869 679 804 -392 278 -349 -486 -390 803 763 701 -398 418 -49 198 -456 71 692 707 -643 403 542 -185 828 403 714 -505 449 181 134 -953 -582 -343 636 849 121 -101 70 643 993 674 -481 -404 -262 -618 -398 -418 -363 335 764 -837 -320 -252 68 -315 966 -209 -876 -293 709 532 -993 233 978 88 797 472 184 631 -436 -355 -165 920 -417 -227 -138 -762 -626 -745 -603 -642 425 779 -672 -598 -840 -97 256 -179 -363 -526 823 271 827 488 290 9 -535 35 -963 957 477 62 -365 -538 -227 -970 -693 -187 -948 -334 -171 -405 -941 -525 -713 -51 -801 660 902 925 -728 546
|
||||
-441 -101 764 -354 -681 -340 -518 556 -989 -385 964 226 253 583 -592 523 501 892 689 798 954 -563 652 398 -298 -737 -484 389 -308 -950 -465 114 928 -277 -834 -613 -427 193 -119 250 656 -770 124 -839 -891 849 -789 184 -792 239 -242 -731 752 966 476 780 92 299 -738 531 540 832 -837 461 283 -639 -379 267 977 -143 -797 10 -976 -993 867 886 -235 146 -729 858 665 147 518 57 -45 784 421 -445 -113 749 -595 -998 -121 -232 -167 -400 676 -197 -497 974 -853 608 -923 690 942 -89 997 807 -99 942 545 -563 748 -90 577 -793 110 -178 747 7 -241 702 857 582 -397 -266 -707 -468 572 29 1000 -443 321 -612 -478 -952 740 -892 -124 260 416 -244 -726 -845 -44 -250 214 -936 -708 -432
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user