Compare commits

..

122 Commits

Author SHA1 Message Date
7547d34598 [midend-IVE]参考libdivide库,实现了魔数的正确求解,如果后续出错直接用API或者不要除法强度削弱了 2025-08-14 05:12:54 +08:00
06a368db39 [midend]修复创建新归纳变量的错误逻辑,避免生成悬空phi节点的现象 2025-08-13 20:00:43 +08:00
48865fa805 [midend-IVE]增加无用归纳变量消除遍 2025-08-13 17:42:34 +08:00
8b5123460b [midend-Loop-InductionVarStrengthReduction]支持了对部分除法运算取模运算的归纳变量的强度削弱策略。(mulh+魔数,负数2的幂次除法符号修正,2的幂次取模运算and优化)。增加了了Printer对移位指令的打印支持 2025-08-13 17:41:41 +08:00
cd27f5fda9 [midend]增加部分逻辑位移指令 2025-08-13 15:28:37 +08:00
60cb8d6e49 [midend]重命名Sra指令的kind标识 2025-08-13 14:55:46 +08:00
ea944f6ba0 [midend-Loop-InductionVarStrengthReduction]增加循环规约变量强度削弱优化 2025-08-13 01:13:01 +08:00
0c8a156485 [midend-LoopCharacteristics]强化归纳变量的识别 2025-08-12 22:33:16 +08:00
debda205cc [testdata]将官方提供的RV错误样例输入替换成了ARM中正确的输入 2025-08-12 16:24:24 +08:00
baef82677b [midend-LICM]将能够外提的循环不变量进行Kanh拓扑排序保证外提后的计算顺序正确。 2025-08-12 16:18:00 +08:00
f634273852 [midend-LICM]优化了特征分析中对循环不变量的识别,实现了LICM遍,格式化副作用分析代码 2025-08-12 15:53:57 +08:00
70f6a25ebc [midend-LoopAnalysis]修复循环规范遍bug,修正部分打印格式, 2025-08-12 12:34:07 +08:00
8cb807c8b9 [midend-LoopAnalysis]修复phi指令缺失的getIncomingValues方法调用 2025-08-11 21:20:38 +08:00
1fab6a43f9 Merge branch 'midend' into midend-LoopAnalysis 2025-08-11 21:20:34 +08:00
1e3791a801 [midend-LoopNormalization]消除不必要的循环特征分析结果使用。优化phi指令处理逻辑 2025-08-11 20:51:55 +08:00
a1cca3c95a [midend-llvmirprint]修改i1类型不存在引入的临时寄存器保存比较结果重命名的逻辑,减少冲突的可能性 2025-08-11 19:10:11 +08:00
1361156b0d [midend-CFGOpt]修复上一次提交的漏洞 2025-08-11 18:46:07 +08:00
46179e3866 [midend-CFGOpt]修复部分指令删除逻辑错误 2025-08-11 18:40:58 +08:00
038552f58b [midend-SCCP]修复了函数参数没有正确初始化为Bottom的问题,现在f/64样例可以-O1通过 2025-08-11 16:47:03 +08:00
4d0e2d73ea [midend-LATG]将调试信息改为DEBUG生效 2025-08-10 17:32:45 +08:00
ad19a6715f [midend]删除了错误的sra指令生成逻辑 2025-08-10 16:57:40 +08:00
d1ba140657 [midend-llvnirprint]修改浮点为字面值打印,修复assign的类型推断 2025-08-10 16:12:09 +08:00
2c5e4cead1 [midend-llvmirprint]修复部分打印逻辑,修复生成IR时的基本块错误的前后驱关系链接 2025-08-10 15:19:24 +08:00
6b92020bc4 [midend-llvmirprint]修复全局数组打印格式问题 2025-08-09 22:41:32 +08:00
c867bda9b4 [midend]解决部分变量重命名问题 2025-08-09 22:30:09 +08:00
6b9ad0566d [midend-llvmirprint]修复进度(162/199),修复若干打印问题,修复若干ir生成逻辑问题 2025-08-09 21:28:44 +08:00
6a7355ed28 [midend-Loop]初步构建循环规范遍 2025-08-09 17:53:41 +08:00
be9ac89584 [midend-LoopAnalysis]将前置分析结果指针保存到循环特征分析类中消除冗余的分析指针传递 2025-08-09 16:42:31 +08:00
ac3358d7e3 [midend-LoopAnalysis]移除基本循环特征分析中的向量化并行化内容,增加循环向量化并行化特征分析遍,TODO:构建循环优化遍验证分析遍正确性 2025-08-09 13:53:00 +08:00
bd23f6154d [midend-SideEffect]将副作用分析遍重构为Module级别,更新其他优化遍用法,注册到PassMananger中,修改CMakeLists。 2025-08-08 16:25:41 +08:00
126c38a1d9 [midend-CallGraph]增加调用图分析遍 2025-08-08 16:24:13 +08:00
c4c91412d1 [midend]修改一点逻辑和注释,删除无用文件 2025-08-08 15:31:35 +08:00
f17e44f8d4 [midend-Alias]针对sysy语言设计了保守和激进的别名优化策略,设计了通过接口设置选项,后续需要验证。保留了一些激进策略接口置空待后续增加。 2025-08-08 15:08:49 +08:00
a406e44df3 [midend-Alias]应用别名分析结果,sccp现在能简单传播数组元素了 2025-08-08 02:12:32 +08:00
b1a46b7d58 [midend-LoopAnalysis]为项目添加别名分析遍,副作用分析遍,循环分析遍,循环特征分析遍 2025-08-08 00:56:50 +08:00
bd02f5f1eb [midend-LoopAnalysis]为phi指令添加新的方法供外部遍历(目前不是顺序遍历) 2025-08-08 00:55:01 +08:00
c507b98199 [midend-llvmprint]更新脚本,支持-eir执行IR测试 2025-08-07 23:45:26 +08:00
ba21bb3203 [midend]修复内存泄漏和Heap-buffer-overflow问题(getexternalfunction中及其隐秘的错误),修复全局常量标量访问的错误 2025-08-07 02:53:36 +08:00
8aa5ba692f [midend]初步修复内存泄漏问题(仍然剩余11处) 2025-08-07 01:34:00 +08:00
d732800149 [midend-llvmprint]更新脚本,禁用内存泄漏检查 2025-08-07 00:36:43 +08:00
f083e38615 [midend-Loop]循环分析构建,增加很多统计方法和循环信息方法 2025-08-06 22:29:39 +08:00
37f2a01783 [midend-llvmirprint]修复了gep指令对不含维度信息的数组指针的处理逻辑,修复若干打印bug,在-s ir/ird -o <llvmir.ll file>的参数下最终会打印ir到file中,优化过程中的打印逻辑待更改。 2025-08-06 15:28:54 +08:00
5d343f42a5 [midend-llvmirprint]检查并修复了初始值的打印逻辑 2025-08-06 02:02:05 +08:00
a4406e0112 [midend]增加了指令重命名逻辑。 2025-08-06 01:31:23 +08:00
08fcda939b [midend-llvmirprint]实现了大部分函数的print方法,TODO:需要完善func和module的print方法以及重命名的逻辑 2025-08-06 01:02:11 +08:00
5f63554ca3 [midend]修正合并基本块链会将entry块纳入考虑范围的问题。上次commit同时修改了alloca创建的逻辑保证了alloca的声明全部在entry块中 2025-08-04 18:56:57 +08:00
4db3cc3fb5 Merge branch 'midend' into backend 2025-08-04 16:48:30 +08:00
17f1bed310 Merge branch 'backend-lag' into backend 2025-08-04 16:43:43 +08:00
b848ffca5a [midend]在生成IR时引进了简单的CSE(二元一元loadgep的cse) 2025-08-04 16:38:12 +08:00
603506d142 Merge branch 'backend' of gitee.com:lixuanwang/mysysy into backend 2025-08-04 16:34:22 +08:00
0179c13cf4 [backend]添加了一些工具函数 2025-08-04 16:32:54 +08:00
7e5f6800b7 [backend]修复寄存器分配算法死循环bug,89通过 2025-08-04 16:04:35 +08:00
64ba25a77e [backend]移除了冗余的keepalive伪指令 2025-08-04 14:11:27 +08:00
208d5528b5 Merge branch 'midend' into backend 2025-08-04 02:37:27 +08:00
a269366ac5 [backend]修复了较小全零全局数组未显示初始化导致未定义行为的问题 2025-08-04 02:31:18 +08:00
1b9a7a4827 [backend]修复了函数序言处理错误且与尾声栈不匹配的bug 2025-08-04 01:57:34 +08:00
b2c2f3289d [backend]修改了编译器后端 RISCv64ISel.cpp,在 kFtoI 的处理逻辑中,用一段指令序列模拟了正确的“向零取整”行为。95 h35 h37 h38通过。 2025-08-04 01:35:26 +08:00
0ecd47f0ac 修复IR打印器中浮点比较指令的类型错误,确保生成正确的LLVM IR代码 2025-08-04 01:35:26 +08:00
6550c8a25b [backend-LAG]添加新的LargeArrayToGlobal中端Pass,以及栈保护逻辑 2025-08-04 01:01:29 +08:00
f24cc7ec88 [midend]修复replaceAllUsesWith中由于setOperand 间接调用 removeUse 或 addUse导致的迭代器失效问题 2025-08-04 00:59:39 +08:00
c8a8bf9a37 [backend]修复了溢出位置错误的问题 2025-08-03 23:28:38 +08:00
446a6a6fcb [midend]修复phi指令接口,优化遍适配 2025-08-03 22:18:00 +08:00
d8b004e5e5 [midend]修改use关系相关的函数,使其能自动的正确维护,修改了phi指令的各种接口 2025-08-03 22:16:40 +08:00
cd814de495 Merge commit 'e4ad23a1a594a9da6b96655d4256352d5f6d277d' into midend 2025-08-03 18:37:36 +08:00
e4ad23a1a5 [backend]修复了寄存器分配器在处理全物理寄存器操作数时的bug 2025-08-03 18:37:08 +08:00
58c8cd53f5 Merge branch 'midend' of gitee.com:lixuanwang/mysysy into midend 2025-08-03 17:26:38 +08:00
ec91a4e259 [backend]更新脚本,现在会拷贝.sy文件到tmp目录 2025-08-03 17:26:09 +08:00
91f755959b [midend]修改中端流水线 2025-08-03 17:25:05 +08:00
92c89f7616 [midend]修正了脚本错误 2025-08-03 17:12:39 +08:00
66047dc6a3 Merge branch 'buildcfg' into midend 2025-08-03 16:40:48 +08:00
22cf18a1d6 [midend-BuildCFG]修复逻辑 2025-08-03 16:14:31 +08:00
19a433c94f [midend]为脚本添加了-O1参数,支持测试性能 2025-08-03 15:41:29 +08:00
45dfbc8d59 Merge branch 'backend' into midend 2025-08-03 15:25:51 +08:00
ef9d7c4d03 [midend-LoopAnalysis]增加维护循环层级的逻辑,修改父子循环关系求解的逻辑。 2025-08-03 15:22:18 +08:00
f8e423f579 合并backend、backend-IRC到midend 2025-08-03 15:18:52 +08:00
5b43f208ac Merge branch 'backend-divopt' into midend 2025-08-03 14:53:22 +08:00
845f969c2e [backend-IRC]修复了现场管理与溢出处理的栈偏移量错误问题 2025-08-03 14:42:19 +08:00
9c5d9ea78c [optimize]删除多余测试文件 2025-08-03 14:38:27 +08:00
0ce742a86e [optimize]添加更为通用的除法强度削减Pass, 不受除数限制替换div指令,不影响当前分数 2025-08-03 14:37:33 +08:00
1c7c85dd2f Merge commit 'f879a0f521e3033d3f928a5976ac095af6905942' into midend-LoopAnalysis 2025-08-03 14:30:32 +08:00
f312792fe9 [optimze]添加基础的除法指令优化,目前只对除以2的幂数生效 2025-08-03 13:46:42 +08:00
32ea24df56 [midend]修复entryBB和funcBodyEntry的初始化,Dom计算引进逆后续遍历和LT算法,Pass先默认关掉CFGOpt 2025-08-03 00:51:49 +08:00
a1cf60c420 [midend-BuildCFG]新增BuildCFG优化通道,实现控制流图的构建与分析 2025-08-02 22:48:21 +08:00
f879a0f521 [midend]修复了后端不适配中端全局变量定义的问题 2025-08-02 22:06:37 +08:00
aa7f2bb0f5 [midend]loop分析构建 2025-08-02 17:42:43 +08:00
004ef82488 [backend-IRC]修复了后端不适配中端全局变量定义的问题 2025-08-02 15:10:19 +08:00
8f1d592d4e Merge branch 'midend' into backend-IRC 2025-08-02 12:47:27 +08:00
537533ee43 Merge branch 'midend' into backend-IRC 2025-08-02 12:43:18 +08:00
bfe218be07 [midend]非全0初始化数组情况下,检查0初始值个数,超过阈值(目前为16)则生成menset减少大量store操作 2025-08-02 02:33:25 +08:00
384f7c548b [backend-IRC]添加了三级调试打印逻辑 2025-08-01 23:18:53 +08:00
57fe17dc21 [backend-IRC]为虚拟寄存器与物理寄存器之间添加冲突 2025-08-01 21:20:04 +08:00
e48cddab9f [midend]修复多维数组维度信息的计算值(理论上计算结果一定是常量),TODO:修复类似问题 2025-08-01 19:19:05 +08:00
aef10b48e8 [midend]删除前驱后继移除时不存在的检查,phi增加llvm风格接口,重构CFGOpt特别是空块删除的逻辑(待验证) 2025-08-01 18:34:43 +08:00
373726b02f [backend-IRC]修复了极其隐蔽的寄存器分配问题 2025-08-01 17:29:18 +08:00
a0b69f20fb [midend]合并了SCCP和backend,修复了支配树的错误求解,修复了Mem2Reg的重命名alloca的栈管理 2025-08-01 15:18:33 +08:00
999f2c6615 Merge remote-tracking branch 'origin/backend' into midend 2025-08-01 14:06:20 +08:00
1eedb55ca0 Merge branch 'midend-SCCP' into midend 2025-08-01 14:02:14 +08:00
8fe9867f33 [backend-IRC]修复了keepalive伪指令处理缺失的问题 2025-08-01 12:15:03 +08:00
166d0fc372 [backend-IRC]修复了栈传递参数逻辑 2025-08-01 05:21:37 +08:00
873dbf64d0 [backend-IRC]基本构建了IRC 2025-08-01 04:44:13 +08:00
f387aecc03 [backend-IRC]进一步构建寄存器分配逻辑 2025-08-01 02:47:40 +08:00
c268191826 [midend-SCCP]修改BaiscBlock的析构逻辑,将CFG修改的职责交给优化遍,注释Mem2Reg的调试信息。 2025-08-01 01:44:33 +08:00
03e88eee70 [backend-IRC]初步构建新的寄存器分配器 2025-07-31 23:02:53 +08:00
0f1fcc835d [midend-SCCP]删除User的析构函数,usedelete增加逻辑通知inst所使用的value移除对应的use关系(一般在这之前会替换使用inst的uses为其他值),TODO:仍然存在bug需要调试 2025-07-31 22:32:04 +08:00
c5af4f1c49 [midend-SCCP]bug修复,增加不可达指令(理论来说后端不会出现这条指令,只是为了IR完整性添加),添加相关方法,phi指令方法修复;目前能够跑完所有优化,但是User的析构函数重定义导致全局析构不能正确完成,需要修复 2025-07-31 22:03:35 +08:00
9a53e1b917 [midend]适应上一次commit修改已有优化遍中相关指令删除的代码 2025-07-31 21:10:59 +08:00
ef09bc70d4 [midend]修改了removeinst方法,应对不同的使用情况,增加user析构函数使得user对象销毁顺带销毁其use关系销毁,重构usedelete方法封装指令删除和use关系删除 2025-07-31 21:10:20 +08:00
aed4577490 [midend]同上,删除了打印函数对维度信息的错误访问 2025-07-31 19:57:19 +08:00
35b421b60b [midend]修改原因同上一次commit 2025-07-31 19:38:43 +08:00
f3f603a032 [midend]消除冗余维度信息记录,适配IR生成器,TODO:其他优化遍生成指令修改,或者后端的访问 2025-07-31 19:36:39 +08:00
de0f8422e9 [midend-SCCP]没有编译报错但是Segmemtation falut 2025-07-31 17:29:34 +08:00
35691ab7bc [midend-SCCP]为跳转指令增加getSuccessors方法 2025-07-31 17:19:57 +08:00
61768fa180 [midend-SCCP]头文件构架完毕,cpp文件部分报错暂时不commit 2025-07-31 17:00:02 +08:00
520ebd96f0 [midend-SCCP]增加不可达指令,修改跳转指令参数(基本块args已弃用默认为{}) 2025-07-31 16:59:22 +08:00
6868f638d7 [midend-SCCP]增加基本块对的哈希值计算方法,增加删除use关系和指令的函数 2025-07-31 16:57:47 +08:00
e8699d6d25 [backend]更新脚本和库以支持性能测试用例 2025-07-31 16:42:41 +08:00
0727d5a6d8 Merge commit 'fc7afdbb359e71e799ea50ac71ac21ce233aeaac' into backend 2025-07-31 15:01:06 +08:00
bfe2b248cd Merge branch 'backend-float' into backend 2025-07-31 12:16:11 +08:00
807fb3f560 [backend]微优化与可读性维护不影响原逻辑和分数 2025-07-31 11:23:17 +08:00
b3cf3cba29 [backend]修复了多参数传递的错误 2025-07-30 22:16:37 +08:00
03b62b138f [backend]修复了一个栈管理问题 2025-07-30 20:40:56 +08:00
206a0af424 [midend-SCCP]暂存1 2025-07-30 16:33:56 +08:00
242 changed files with 627617 additions and 3095 deletions

1
.gitignore vendored
View File

@ -36,6 +36,7 @@ doxygen
!/testdata/functional/*.out
!/testdata/h_functional/*.out
!/testdata/performance/*.out
build/
.antlr
.vscode/

View File

@ -14,10 +14,387 @@
Mem2Reg 遍的主要目标是将那些不必要的、只用于局部标量变量的内存分配 (alloca 指令) 消除,并将这些变量的值转换为 SSA 形式。这有助于减少内存访问,提高代码效率,并为后续的优化创造更好的条件。
通过Mem2Reg理解删除指令时对use关系的维护
`Mem2Reg` 优化遍中,当 `load``store` 指令被删除时,其 `use` 关系(即它们作为操作数与其他 `Value` 对象之间的连接)的正确消除是一个关键问题,尤其涉及到 `AllocaInst`
结合您提供的 `Mem2RegContext::renameVariables` 代码和我们之前讨论的 `usedelete` 逻辑,下面是 `use` 关系如何被正确消除的详细过程:
### 问题回顾:`Use` 关系的双向性
在您的 IR 设计中,`Use` 对象扮演着连接 `User`(使用者,如 `LoadInst`)和 `Value`(被使用者,如 `AllocaInst`)的双向角色:
* 一个 `User` 持有对其操作数 `Value``Use` 对象(通过 `User::operands` 列表)。
* 一个 `Value` 持有所有使用它的 `User``Use` 对象(通过 `Value::uses` 列表)。
原始问题是:当一个 `LoadInst``StoreInst` 被删除时,如果不对其作为操作数与 `AllocaInst` 之间的 `Use` 关系进行明确清理,`AllocaInst``uses` 列表中就会留下指向已删除 `LoadInst` / `StoreInst``Use` 对象,导致内部的 `User*` 指针悬空,在后续访问时引发 `segmentation fault`
### `Mem2Reg` 中 `load`/`store` 指令的删除行为
`Mem2RegContext::renameVariables` 函数中,`load``store` 指令被处理时,其行为如下:
1. **处理 `LoadInst`**
当找到一个指向可提升 `AllocaInst``LoadInst` 时,其用途会被 `replaceAllUsesWith(allocaToValueStackMap[alloca].top())` 替换。这意味着任何原本使用 `LoadInst` 本身计算结果的指令,现在都直接使用 SSA 值栈顶部的 `Value`
**重点:** 这一步处理的是 `LoadInst` 作为**被使用的值 (Value)** 时,其 `uses` 列表的清理。即,将 `LoadInst` 的所有使用者重定向到新的 SSA 值,并把这些 `Use` 对象从 `LoadInst``uses` 列表中移除。
2. **处理 `StoreInst`**
当找到一个指向可提升 `AllocaInst``StoreInst` 时,`StoreInst` 存储的值会被压入值栈。`StoreInst` 本身并不产生可被其他指令直接使用的值(其类型是 `void`),所以它没有 `uses` 列表需要替换。
**重点:** `StoreInst` 的主要作用是更新内存状态,在 SSA 形式下,它被移除后需要清理它作为**使用者 (User)** 时的操作数关系。
在这两种情况下,一旦 `load``store` 指令的 SSA 转换完成,它们都会通过 `instIter = SysYIROptUtils::usedelete(instIter)` 被显式删除。
### `SysYIROptUtils::usedelete` 如何正确消除 `Use` 关系
关键在于对 `SysYIROptUtils::usedelete` 函数的修改,使其在删除指令时,同时处理该指令作为 `User``Value` 的两种 `Use` 关系:
1. **清理指令作为 `Value` 时的 `uses` 列表 (由 `replaceAllUsesWith` 完成)**
`usedelete` 函数中,`inst->replaceAllUsesWith(UndefinedValue::get(inst->getType()))` 的调用至关重要。这确保了:
* 如果被删除的 `Instruction`(例如 `LoadInst`)产生了结果值并被其他指令使用,所有这些使用者都会被重定向到 `UndefinedValue`(或者 `Mem2Reg` 中具体的 SSA 值)。
* 这个过程会遍历 `LoadInst``uses` 列表,并将这些 `Use` 对象从 `LoadInst``uses` 列表中移除。这意味着 `LoadInst` 自己不再被任何其他指令使用。
2. **清理指令作为 `User` 时其操作数的 `uses` 列表 (由 `RemoveUserOperandUses` 完成)**
这是您提出的、并已集成到 `usedelete` 中的关键改进点。对于一个被删除的 `Instruction`(它同时也是 `User`),我们需要清理它**自己使用的操作数**所维护的 `use` 关系。
* 例如,`LoadInst %op1` 使用了 `%op1`(一个 `AllocaInst`)。当 `LoadInst` 被删除时,`AllocaInst``uses` 列表中有一个 `Use` 对象指向这个 `LoadInst`
* `RemoveUserOperandUses` 函数会遍历被删除 `User`(即 `LoadInst``StoreInst`)的 `operands` 列表。
* 对于 `operands` 列表中的每个 `std::shared_ptr<Use> use_ptr`,它会获取 `Use` 对象内部指向的 `Value`(例如 `AllocaInst*`),然后调用 `value->removeUse(use_ptr)`
* 这个 `removeUse` 调用会负责将 `use_ptr``AllocaInst``uses` 列表中删除。
### 总结
通过在 `SysYIROptUtils::usedelete` 中同时执行这两个步骤:
* `replaceAllUsesWith`:处理被删除指令**作为结果被使用**时的 `use` 关系。
* `RemoveUserOperandUses`:处理被删除指令**作为使用者User其操作数**的 `use` 关系。
这就确保了当 `Mem2Reg` 遍历并删除 `load``store` 指令时,无论是它们作为 `Value` 的使用者,还是它们作为 `User` 的操作数,所有相关的 `Use` 对象都能被正确地从 `Value``uses` 列表中移除,从而避免了悬空指针和后续的 `segmentation fault`
最后,当所有指向某个 `AllocaInst``load``store` 指令都被移除后,`AllocaInst``uses` 列表将变得干净(只包含 Phi 指令,如果它们在 SSA 转换中需要保留 Alloca 作为操作数),这时在 `Mem2RegContext::cleanup()` 阶段,`SysYIROptUtils::usedelete(alloca)` 就可以安全地删除 `AllocaInst` 本身了。
## Reg2Mem
我们的Reg2Mem 遍的主要目标是作为 Mem2Reg 的一种逆操作,但更具体是解决后端无法识别 PhiInst 指令的问题。主要的速录是将函数参数和 PhiInst 指令的结果从 SSA 形式转换回内存形式,通过插入 alloca、load 和 store 指令来实现。其他非 Phi 的指令结果将保持 SSA 形式。
## SCCP
SCCP稀疏条件常量传播是一种编译器优化技术它结合了常量传播和死代码消除。其核心思想是在程序执行过程中尝试识别并替换那些在编译时就能确定其值的变量常量同时移除那些永远不会被执行到的代码块不可达代码
以下是 SCCP 的实现思路:
1. 核心数据结构与工作列表:
Lattice 值Lattice Value: SCCP 使用三值格Three-Valued Lattice来表示变量的状态
Top (T): 初始状态,表示变量的值未知,但可能是一个常量。
Constant (C): 表示变量的值已经确定为一个具体的常量。
Bottom (⊥): 表示变量的值不确定或不是一个常量(例如,它可能在运行时有多个不同的值,或者从内存中加载)。一旦变量状态变为 Bottom它就不能再变回 Constant 或 Top。
SSAPValue: 封装了 Lattice 值和常量具体值(如果状态是 Constant
*valState (map<Value, SSAPValue>):** 存储程序中每个 Value变量、指令结果等的当前 SCCP Lattice 状态。
*ExecutableBlocks (set<BasicBlock>):** 存储在分析过程中被确定为可执行的基本块。
工作列表 (Worklists):
cfgWorkList (queue<pair<BasicBlock, BasicBlock>>):** 存储待处理的控制流图CFG边。当一个块被标记为可执行时它的后继边会被添加到这个列表。
*ssaWorkList (queue<Instruction>):** 存储待处理的 SSA (Static Single Assignment) 指令。当一个指令的任何操作数的状态发生变化时,该指令就会被添加到这个列表,需要重新评估。
2. 初始化:
所有 Value 的状态都被初始化为 Top。
所有基本块都被初始化为不可执行。
函数的入口基本块被标记为可执行,并且该块中的所有指令被添加到 ssaWorkList。
3. 迭代过程 (Fixed-Point Iteration)
SCCP 的核心是一个迭代过程,它交替处理 CFG 工作列表和 SSA 工作列表,直到达到一个不动点(即没有更多的状态变化)。
处理 cfgWorkList:
从 cfgWorkList 中取出一个边 (prev, next)。
如果 next 块之前是不可执行的,现在通过 prev 块可达,则将其标记为可执行 (markBlockExecutable)。
一旦 next 块变为可执行,其内部的所有指令(特别是 Phi 指令)都需要被重新评估,因此将它们添加到 ssaWorkList。
处理 ssaWorkList:
从 ssaWorkList 中取出一个指令 inst。
重要: 只有当 inst 所在的块是可执行的,才处理该指令。不可执行块中的指令不参与常量传播。
计算新的 Lattice 值 (computeLatticeValue): 根据指令类型和其操作数的当前 Lattice 状态,计算 inst 的新的 Lattice 状态。
常量折叠: 如果所有操作数都是常量,则可以直接执行运算并得到一个新的常量结果。
Bottom 传播: 如果任何操作数是 Bottom或者运算规则导致不确定例如除以零则结果为 Bottom。
Phi 指令的特殊处理: Phi 指令的值取决于其所有可执行的前驱块传入的值。
如果所有可执行前驱都提供了相同的常量 C则 Phi 结果为 C。
如果有任何可执行前驱提供了 Bottom或者不同的可执行前驱提供了不同的常量则 Phi 结果为 Bottom。
如果所有可执行前驱都提供了 Top则 Phi 结果仍为 Top。
更新状态: 如果 inst 的新计算出的 Lattice 值与它当前存储的值不同,则更新 valState[inst]。
传播变化: 如果 inst 的状态发生变化,那么所有使用 inst 作为操作数的指令都可能受到影响,需要重新评估。因此,将 inst 的所有使用者添加到 ssaWorkList。
处理终结符指令 (BranchInst, ReturnInst):
对于条件分支 BranchInst如果其条件操作数变为常量
如果条件为真,则只有真分支的目标块是可达的,将该边添加到 cfgWorkList。
如果条件为假,则只有假分支的目标块是可达的,将该边添加到 cfgWorkList。
如果条件不是常量Top 或 Bottom则两个分支都可能被执行将两边的边都添加到 cfgWorkList。
这会影响 CFG 的可达性分析,可能导致新的块被标记为可执行。
4. 应用优化 (Transformation)
当两个工作列表都为空,达到不动点后,程序代码开始进行实际的修改:
常量替换:
遍历所有指令。如果指令的 valState 为 Constant则用相应的 ConstantValue 替换该指令的所有用途 (replaceAllUsesWith)。
将该指令标记为待删除。
对于指令的操作数,如果其 valState 为 Constant则直接将操作数替换为对应的 ConstantValue常量折叠
删除死指令: 遍历所有标记为待删除的指令,并从其父基本块中删除它们。
删除不可达基本块: 遍历函数中的所有基本块。如果一个基本块没有被标记为可执行 (ExecutableBlocks 中不存在),则将其从函数中删除。但入口块不能删除。
简化分支指令:
遍历所有可执行的基本块的终结符指令。
对于条件分支 BranchInst如果其条件操作数在 valState 中是 Constant
如果条件为真,则将该条件分支替换为一个无条件跳转到真分支目标块的指令。
如果条件为假,则将该条件分支替换为一个无条件跳转到假分支目标块的指令。
更新 CFG移除不可达的分支边和其前驱信息。
computeLatticeValue 的具体逻辑:
这个函数是 SCCP 的核心逻辑,它定义了如何根据指令类型和操作数的当前 Lattice 状态来计算指令结果的 Lattice 状态。
二元运算 (Add, Sub, Mul, Div, Rem, ICmp, And, Or):
如果任何一个操作数是 Bottom结果就是 Bottom。
如果任何一个操作数是 Top结果就是 Top。
如果两个操作数都是 Constant执行实际的常量运算结果是一个新的 Constant。
一元运算 (Neg, Not):
如果操作数是 Bottom结果就是 Bottom。
如果操作数是 Top结果就是 Top。
如果操作数是 Constant执行实际的常量运算结果是一个新的 Constant。
Load 指令: 通常情况下Load 的结果会被标记为 Bottom因为内存内容通常在编译时无法确定。但如果加载的是已知的全局常量可能可以确定。在提供的代码中它通常返回 Bottom。
Store 指令: Store 不产生值,所以其 SSAPValue 保持 Top 或不关心。
Call 指令: 大多数 Call 指令(尤其是对外部或有副作用的函数)的结果都是 Bottom。对于纯函数如果所有参数都是常量理论上可以折叠但这需要额外的分析。
GetElementPtr (GEP) 指令: GEP 计算内存地址。如果所有索引都是常量,地址本身是常量。但 SCCP 关注的是数据值,因此这里通常返回 Bottom除非有特定的指针常量跟踪。
Phi 指令: 如上所述,基于所有可执行前驱的传入值进行聚合。
Alloc 指令: Alloc 分配内存,返回一个指针。其内容通常是 Bottom。
Branch 和 Return 指令: 这些是终结符指令,不产生一个可用于其他指令的值,通常 SSAPValue 保持 Top 或不关心。
类型转换 (ZExt, SExt, Trunc, FtoI, ItoF): 如果操作数是 Constant则执行相应的类型转换结果仍为 Constant。对于浮点数转换由于 SSAPValue 的 constantVal 为 int 类型,所以对浮点数的操作会保守地返回 Bottom。
未处理的指令: 默认情况下,任何未明确处理的指令都被保守地假定为产生 Bottom 值。
浮点数处理的注意事项:
在提供的代码中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位范围时及时发现
智能回退:使用已验证的标准值保证正确性
保持通用性:对于没有预设值的除数仍然可以工作
# 后续优化可能涉及的改动
@ -25,4 +402,12 @@ Mem2Reg 遍的主要目标是将那些不必要的、只用于局部标量变量
好处优化友好性方便mem2reg提升
目前没有实现这个机制,如果想要实现首先解决同一函数不同域的同名变量命名区分
需要保证符号表能正确维护域中的局部变量
需要保证符号表能正确维护域中的局部变量
# 关于中端优化提升编译器性能的TODO
## usedelete_withinstdelte方法
这个方法删除了use关系并移除了指令逻辑是根据Instruction* inst去find对应的迭代器并erase
有些情况下外部持有迭代器和inst,可以省略find过程

Binary file not shown.

View File

@ -60,11 +60,7 @@ display_file_content() {
# 清理临时文件的函数
clean_tmp() {
echo "正在清理临时目录: ${TMP_DIR}"
rm -rf "${TMP_DIR}"/*.s \
"${TMP_DIR}"/*_sysyc_riscv64 \
"${TMP_DIR}"/*_sysyc_riscv64.actual_out \
"${TMP_DIR}"/*_sysyc_riscv64.expected_stdout \
"${TMP_DIR}"/*_sysyc_riscv64.o
rm -rf "${TMP_DIR}"/*
echo "清理完成。"
}

View File

@ -2,64 +2,67 @@
# runit-single.sh - 用于编译和测试单个或少量 SysY 程序的脚本
# 模仿 runit.sh 的功能,但以具体文件路径作为输入。
# 此脚本应该位于 mysysy/script/
export ASAN_OPTIONS=detect_leaks=0
# --- 配置区 ---
# 请根据你的环境修改这些路径
# 假设此脚本位于你的项目根目录或一个脚本目录中
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
# 默认寻找项目根目录下的 build 和 lib
BUILD_BIN_DIR="${SCRIPT_DIR}/../build/bin"
LIB_DIR="${SCRIPT_DIR}/../lib"
# 临时文件会存储在脚本所在目录的 tmp 子目录中
TMP_DIR="${SCRIPT_DIR}/tmp"
# 定义编译器和模拟器
SYSYC="${BUILD_BIN_DIR}/sysyc"
LLC_CMD="llc-19" # 新增
GCC_RISCV64="riscv64-linux-gnu-gcc"
QEMU_RISCV64="qemu-riscv64"
# --- 初始化变量 ---
EXECUTE_MODE=false
IR_EXECUTE_MODE=false # 新增
CLEAN_MODE=false
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
EXEC_TIMEOUT=5 # qemu 自动化执行超时 (秒)
MAX_OUTPUT_LINES=50 # 对比失败时显示的最大行数
SY_FILES=() # 存储用户提供的 .sy 文件列表
OPTIMIZE_FLAG=""
SYSYC_TIMEOUT=30
LLC_TIMEOUT=10 # 新增
GCC_TIMEOUT=10
EXEC_TIMEOUT=30
MAX_OUTPUT_LINES=20
SY_FILES=()
PASSED_CASES=0
FAILED_CASES_LIST=""
INTERRUPTED=false # 新增
# =================================================================
# --- 函数定义 ---
# =================================================================
show_help() {
echo "用法: $0 [文件1.sy] [文件2.sy] ... [选项]"
echo "编译并测试指定的 .sy 文件。"
echo ""
echo "如果找到对应的 .in/.out 文件,则进行自动化测试。否则,进入交互模式。"
echo "编译并测试指定的 .sy 文件。必须提供 -e 或 -eir 之一。"
echo ""
echo "选项:"
echo " -e, --executable 编译为可执行文件并运行测试 (必须)。"
echo " -e 通过汇编运行测试 (sysyc -> gcc -> qemu)。"
echo " -eir 通过IR运行测试 (sysyc -> llc -> gcc -> qemu)。"
echo " -c, --clean 清理 tmp 临时目录下的所有文件。"
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 10)。"
echo " -O1 启用 sysyc 的 -O1 优化。"
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 30)。"
echo " -lct N 设置 llc-19 编译超时为 N 秒 (默认: 10)。"
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
echo " -et N 设置 qemu 自动化执行超时为 N 秒 (默认: 5)。"
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 50)。"
echo " -et N 设置 qemu 自动化执行超时为 N 秒 (默认: 30)。"
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 20)。"
echo " -h, --help 显示此帮助信息并退出。"
echo ""
echo "可在任何时候按 Ctrl+C 来中断测试并显示当前已完成的测例总结。"
}
# --- 新增功能: 显示文件内容并根据行数截断 ---
display_file_content() {
local file_path="$1"
local title="$2"
local max_lines="$3"
if [ ! -f "$file_path" ]; then
return
fi
if [ ! -f "$file_path" ]; then return; fi
echo -e "$title"
local line_count
line_count=$(wc -l < "$file_path")
if [ "$line_count" -gt "$max_lines" ]; then
head -n "$max_lines" "$file_path"
echo -e "\e[33m[... 输出已截断,共 ${line_count} 行 ...]\e[0m"
@ -68,78 +71,103 @@ display_file_content() {
fi
}
# --- 新增:总结报告函数 ---
print_summary() {
local total_cases=${#SY_FILES[@]}
echo ""
echo "======================================================================"
if [ "$INTERRUPTED" = true ]; then
echo -e "\e[33m测试被中断。正在汇总已完成的结果...\e[0m"
else
echo "所有测试完成"
fi
local failed_count
if [ -n "$FAILED_CASES_LIST" ]; then
failed_count=$(echo -e -n "${FAILED_CASES_LIST}" | wc -l)
else
failed_count=0
fi
local executed_count=$((PASSED_CASES + failed_count))
echo "测试结果: [通过: ${PASSED_CASES}, 失败: ${failed_count}, 已执行: ${executed_count}/${total_cases}]"
if [ -n "$FAILED_CASES_LIST" ]; then
echo ""
echo -e "\e[31m未通过的测例:\e[0m"
printf "%b" "${FAILED_CASES_LIST}"
fi
echo "======================================================================"
if [ "$failed_count" -gt 0 ]; then
exit 1
else
exit 0
fi
}
# --- 新增SIGINT 信号处理函数 ---
handle_sigint() {
INTERRUPTED=true
print_summary
}
# =================================================================
# --- 主逻辑开始 ---
# =================================================================
# --- 新增:设置 trap 来捕获 SIGINT ---
trap handle_sigint SIGINT
# --- 参数解析 ---
# 从参数中分离出 .sy 文件和选项
for arg in "$@"; do
case "$arg" in
-e|--executable)
EXECUTE_MODE=true
;;
-c|--clean)
CLEAN_MODE=true
shift
;;
-sct|-gct|-et|-ml|--max-lines)
# 选项和其值将在下一个循环中处理
;;
-h|--help)
show_help
exit 0
;;
-*)
# 检查是否是带值的选项
if ! [[ ${args_processed+x} ]]; then
args_processed=true # 标记已处理过参数
# 重新处理所有参数
while [[ "$#" -gt 0 ]]; do
case "$1" in
-sct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi ;;
-gct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi ;;
-et) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi ;;
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
*.sy) SY_FILES+=("$1") ;;
-e|--executable) ;; # 已在外部处理
*) if ! [[ "$1" =~ ^[0-9]+$ ]]; then echo "未知选项或无效文件: $1"; show_help; exit 1; fi ;;
esac
shift
done
fi
;;
*.sy)
if [[ -f "$arg" ]]; then
SY_FILES+=("$arg")
else
echo "警告: 文件不存在,已忽略: $arg"
fi
;;
esac
while [[ "$#" -gt 0 ]]; do
case "$1" in
-e|--executable) EXECUTE_MODE=true; shift ;;
-eir) IR_EXECUTE_MODE=true; shift ;; # 新增
-c|--clean) CLEAN_MODE=true; shift ;;
-O1) OPTIMIZE_FLAG="-O1"; shift ;;
-lct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then LLC_TIMEOUT="$2"; shift 2; else echo "错误: -lct 需要一个正整数参数。" >&2; exit 1; fi ;; # 新增
-sct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift 2; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi ;;
-gct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi ;;
-et) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi ;;
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
-h|--help) show_help; exit 0 ;;
-*) echo "未知选项: $1"; show_help; exit 1 ;;
*)
if [[ -f "$1" && "$1" == *.sy ]]; then
SY_FILES+=("$1")
else
echo "警告: 无效文件或不是 .sy 文件,已忽略: $1"
fi
shift
;;
esac
done
if ${CLEAN_MODE}; then
echo "检测到 -c/--clean 选项,正在清空 ${TMP_DIR}..."
if [ -d "${TMP_DIR}" ]; then
# 使用 * 而不是 . 来确保只删除内容,不删除目录本身
# 忽略 rm 可能因目录为空而报告的错误
rm -rf "${TMP_DIR}"/* 2>/dev/null
echo "清理完成。"
else
echo "临时目录 ${TMP_DIR} 不存在,无需清理。"
fi
# 如果只提供了 -c 选项而没有其他 .sy 文件,则在清理后退出
if [ ${#SY_FILES[@]} -eq 0 ] && ! ${EXECUTE_MODE}; then
if [ ${#SY_FILES[@]} -eq 0 ] && ! ${EXECUTE_MODE} && ! ${IR_EXECUTE_MODE}; then
exit 0
fi
fi
# --- 主逻辑开始 ---
if ! ${EXECUTE_MODE}; then
echo "错误: 请提供 -e 或 --executable 选项来运行测试。"
if ! ${EXECUTE_MODE} && ! ${IR_EXECUTE_MODE}; then
echo "错误: 请提供 -e 或 -eir 选项来运行测试。"
show_help
exit 1
fi
if ${EXECUTE_MODE} && ${IR_EXECUTE_MODE}; then
echo -e "\e[31m错误: -e 和 -eir 选项不能同时使用。\e[0m" >&2
exit 1
fi
if [ ${#SY_FILES[@]} -eq 0 ]; then
echo "错误: 未提供任何 .sy 文件作为输入。"
show_help
@ -150,18 +178,18 @@ mkdir -p "${TMP_DIR}"
TOTAL_CASES=${#SY_FILES[@]}
echo "SysY 单例测试运行器启动..."
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
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 ""
for sy_file in "${SY_FILES[@]}"; do
is_passed=1
compilation_ok=1
base_name=$(basename "${sy_file}" .sy)
source_dir=$(dirname "${sy_file}")
ir_file="${TMP_DIR}/${base_name}_sysyc_riscv64.ll"
ir_file="${TMP_DIR}/${base_name}.ll"
assembly_file="${TMP_DIR}/${base_name}.s"
assembly_debug_file="${TMP_DIR}/${base_name}_d.s"
executable_file="${TMP_DIR}/${base_name}"
input_file="${source_dir}/${base_name}.in"
output_reference_file="${source_dir}/${base_name}.out"
@ -170,37 +198,39 @@ for sy_file in "${SY_FILES[@]}"; do
echo "======================================================================"
echo "正在处理: ${sy_file}"
# 步骤 1: sysyc 编译
echo " 使用 sysyc 编译 (超时 ${SYSYC_TIMEOUT}s)..."
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" > "${ir_file}"
SYSYC_STATUS=$?
if [ $SYSYC_STATUS -eq 124 ]; then
echo -e "\e[31m错误: SysY 编译 ${sy_file} IR超时\e[0m"
is_passed=0
elif [ $SYSYC_STATUS -ne 0 ]; then
echo -e "\e[31m错误: SysY 编译 ${sy_file} IR失败退出码: ${SYSYC_STATUS}\e[0m"
is_passed=0
fi
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file}"
if [ $? -ne 0 ]; then
echo -e "\e[31m错误: SysY 编译失败或超时。\e[0m"
is_passed=0
fi
# timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s asmd "${sy_file}" > "${assembly_debug_file}" 2>&1
# --- 编译阶段 ---
if ${IR_EXECUTE_MODE}; then
# 路径1: sysyc -> llc -> gcc
echo " [1/3] 使用 sysyc 编译为 IR (超时 ${SYSYC_TIMEOUT}s)..."
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" ${OPTIMIZE_FLAG} -o "${ir_file}"
if [ $? -ne 0 ]; then echo -e "\e[31m错误: SysY (IR) 编译失败或超时。\e[0m"; compilation_ok=0; fi
# 步骤 2: GCC 编译
if [ "$is_passed" -eq 1 ]; then
echo " 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
if [ $? -ne 0 ]; then
echo -e "\e[31m错误: GCC 编译失败或超时。\e[0m"
is_passed=0
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}"
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
if [ $? -ne 0 ]; then echo -e "\e[31m错误: GCC 编译失败或超时。\e[0m"; compilation_ok=0; fi
fi
else # EXECUTE_MODE
# 路径2: sysyc -> gcc
echo " [1/2] 使用 sysyc 编译为汇编 (超时 ${SYSYC_TIMEOUT}s)..."
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" ${OPTIMIZE_FLAG} -o "${assembly_file}"
if [ $? -ne 0 ]; then echo -e "\e[31m错误: SysY (汇编) 编译失败或超时。\e[0m"; compilation_ok=0; fi
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
if [ $? -ne 0 ]; then echo -e "\e[31m错误: GCC 编译失败或超时。\e[0m"; compilation_ok=0; fi
fi
fi
# 步骤 3: 执行与测试
if [ "$is_passed" -eq 1 ]; then
# 检查是自动化测试还是交互模式
# --- 执行与测试阶段 (公共逻辑) ---
if [ "$compilation_ok" -eq 1 ]; then
if [ -f "${input_file}" ] || [ -f "${output_reference_file}" ]; then
# --- 自动化测试模式 ---
echo " 检测到 .in/.out 文件,进入自动化测试模式..."
@ -218,32 +248,31 @@ for sy_file in "${SY_FILES[@]}"; do
is_passed=0
else
if [ -f "${output_reference_file}" ]; then
# 此处逻辑与 runit.sh 相同
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
if [[ "$LAST_LINE_TRIMMED" =~ ^[-+]?[0-9]+$ ]]; then
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
EXPECTED_STDOUT_FILE="${TMP_DIR}/${base_name}.expected_stdout"
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
if [ "$ACTUAL_RETURN_CODE" -ne "$EXPECTED_RETURN_CODE" ]; then echo -e "\e[31m 返回码测试失败: 期望 ${EXPECTED_RETURN_CODE}, 实际 ${ACTUAL_RETURN_CODE}\e[0m"; is_passed=0; fi
# --- 本次修改点: 使用 tr 删除所有空白字符后再比较 ---
ret_ok=1
if [ "$ACTUAL_RETURN_CODE" -ne "$EXPECTED_RETURN_CODE" ]; then echo -e "\e[31m 返回码测试失败: 期望 ${EXPECTED_RETURN_CODE}, 实际 ${ACTUAL_RETURN_CODE}\e[0m"; ret_ok=0; fi
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"
is_passed=0
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}"
echo -e " \e[36m----------------\e[0m"
fi
if [ "$ret_ok" -eq 1 ] && [ "$out_ok" -eq 1 ]; then echo -e "\e[32m 返回码与标准输出测试成功。\e[0m"; else is_passed=0; fi
else
# --- 本次修改点: 使用 tr 删除所有空白字符后再比较 ---
if diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
echo -e "\e[32m 标准输出测试成功。\e[0m"
else
echo -e "\e[31m 标准输出测试失败。\e[0m"
is_passed=0
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}"
echo -e " \e[36m----------------\e[0m"
fi
fi
else
@ -252,20 +281,16 @@ for sy_file in "${SY_FILES[@]}"; do
fi
else
# --- 交互模式 ---
echo -e "\e[33m"
echo " **********************************************************"
echo " ** 未找到 .in 或 .out 文件,进入交互模式。 **"
echo " ** 程序即将运行,你可以直接在终端中输入。 **"
echo " ** 按下 Ctrl+D (EOF) 或以其他方式结束程序以继续。 **"
echo " **********************************************************"
echo -e "\e[0m"
echo -e "\e[33m\n 未找到 .in 或 .out 文件,进入交互模式...\e[0m"
"${QEMU_RISCV64}" "${executable_file}"
INTERACTIVE_RET_CODE=$?
echo -e "\e[33m\n 交互模式执行完毕,程序返回码: ${INTERACTIVE_RET_CODE}\e[0m"
echo " 注意: 交互模式的结果未经验证。"
echo -e "\e[33m\n 交互模式执行完毕,程序返回码: ${INTERACTIVE_RET_CODE} (此结果未经验证)\e[0m"
fi
else
is_passed=0
fi
# --- 状态总结 ---
if [ "$is_passed" -eq 1 ]; then
echo -e "\e[32m状态: 通过\e[0m"
((PASSED_CASES++))
@ -276,20 +301,4 @@ for sy_file in "${SY_FILES[@]}"; do
done
# --- 打印最终总结 ---
echo "======================================================================"
echo "所有测试完成"
echo "测试通过率: [${PASSED_CASES}/${TOTAL_CASES}]"
if [ -n "$FAILED_CASES_LIST" ]; then
echo ""
echo -e "\e[31m未通过的测例:\e[0m"
echo -e "${FAILED_CASES_LIST}"
fi
echo "======================================================================"
if [ "$PASSED_CASES" -eq "$TOTAL_CASES" ]; then
exit 0
else
exit 1
fi
print_summary

View File

@ -1,30 +1,41 @@
#!/bin/bash
# runit.sh - 用于编译和测试 SysY 程序的脚本
# 此脚本应该位于 mysysy/test_script/
# 此脚本应该位于 mysysy/script/
export ASAN_OPTIONS=detect_leaks=0
# 定义相对于脚本位置的目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
TESTDATA_DIR="${SCRIPT_DIR}/../testdata"
BUILD_BIN_DIR="${SCRIPT_DIR}/../build/bin"
LIB_DIR="${SCRIPT_DIR}/../lib"
# TMP_DIR="${SCRIPT_DIR}/tmp"
TMP_DIR="${SCRIPT_DIR}/tmp"
# 定义编译器和模拟器
SYSYC="${BUILD_BIN_DIR}/sysyc"
LLC_CMD="llc-19"
GCC_RISCV64="riscv64-linux-gnu-gcc"
QEMU_RISCV64="qemu-riscv64"
# --- 新增功能: 初始化变量 ---
# --- 状态变量 ---
EXECUTE_MODE=false
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
EXEC_TIMEOUT=5 # qemu 执行超时 (秒)
MAX_OUTPUT_LINES=50 # 对比失败时显示的最大行数
IR_EXECUTE_MODE=false
OPTIMIZE_FLAG=""
SYSYC_TIMEOUT=30
LLC_TIMEOUT=10
GCC_TIMEOUT=10
EXEC_TIMEOUT=30
MAX_OUTPUT_LINES=20
TEST_SETS=()
TOTAL_CASES=0
PASSED_CASES=0
FAILED_CASES_LIST="" # 用于存储未通过的测例列表
FAILED_CASES_LIST=""
INTERRUPTED=false # 新增:用于标记是否被中断
# =================================================================
# --- 函数定义 ---
# =================================================================
# 显示帮助信息的函数
show_help() {
@ -32,29 +43,32 @@ show_help() {
echo "此脚本用于按文件名前缀数字升序编译和测试 .sy 文件。"
echo ""
echo "选项:"
echo " -e, --executable 编译为可执行文件并运行测试。"
echo " -e, --executable 编译为汇编并运行测试 (sysyc -> gcc -> qemu)。"
echo " -eir 通过IR编译为可执行文件并运行测试 (sysyc -> llc -> gcc -> qemu)。"
echo " -c, --clean 清理 'tmp' 目录下的所有生成文件。"
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 10)。"
echo " -O1 启用 sysyc 的 -O1 优化。"
echo " -set [f|h|p|all]... 指定要运行的测试集 (functional, h_functional, performance)。可多选,默认为 all。"
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 30)。"
echo " -lct N 设置 llc-19 编译超时为 N 秒 (默认: 10)。"
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
echo " -et N 设置 qemu 执行超时为 N 秒 (默认: 5)。"
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 50)。"
echo " -et N 设置 qemu 执行超时为 N 秒 (默认: 30)。"
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 20)。"
echo " -h, --help 显示此帮助信息并退出。"
echo ""
echo "注意: 默认行为 (无 -e 或 -eir) 是将 .sy 文件同时编译为 .s (汇编) 和 .ll (IR),不执行。"
echo " 可在任何时候按 Ctrl+C 来中断测试并显示当前已完成的测例总结。"
}
# 显示文件内容并根据行数截断的函数
display_file_content() {
local file_path="$1"
local title="$2"
local max_lines="$3"
if [ ! -f "$file_path" ]; then
return
fi
if [ ! -f "$file_path" ]; then return; fi
echo -e "$title"
local line_count
line_count=$(wc -l < "$file_path")
if [ "$line_count" -gt "$max_lines" ]; then
head -n "$max_lines" "$file_path"
echo -e "\e[33m[... 输出已截断,共 ${line_count} 行 ...]\e[0m"
@ -69,193 +83,360 @@ clean_tmp() {
rm -rf "${TMP_DIR}"/*
}
# 如果临时目录不存在,则创建它
# --- 新增:总结报告函数 ---
print_summary() {
echo "" # 确保从新的一行开始
echo "========================================"
if [ "$INTERRUPTED" = true ]; then
echo -e "\e[33m测试被中断。正在汇总已完成的结果...\e[0m"
else
echo "测试完成"
fi
local failed_count
if [ -n "$FAILED_CASES_LIST" ]; then
# `wc -l` 计算由换行符分隔的列表项数
failed_count=$(echo -e -n "${FAILED_CASES_LIST}" | wc -l)
else
failed_count=0
fi
local executed_count=$((PASSED_CASES + failed_count))
echo "测试结果: [通过: ${PASSED_CASES}, 失败: ${failed_count}, 已执行: ${executed_count}/${TOTAL_CASES}]"
if [ -n "$FAILED_CASES_LIST" ]; then
echo ""
echo -e "\e[31m未通过的测例:\e[0m"
# 使用 printf 保证原样输出
printf "%b" "${FAILED_CASES_LIST}"
fi
echo "========================================"
if [ "$failed_count" -gt 0 ]; then
exit 1
else
exit 0
fi
}
# --- 新增SIGINT 信号处理函数 ---
handle_sigint() {
INTERRUPTED=true
print_summary
}
# =================================================================
# --- 主逻辑开始 ---
# =================================================================
# --- 新增:设置 trap 来捕获 SIGINT ---
trap handle_sigint SIGINT
mkdir -p "${TMP_DIR}"
# 解析命令行参数
while [[ "$#" -gt 0 ]]; do
case "$1" in
-e|--executable)
EXECUTE_MODE=true
;;
-c|--clean)
clean_tmp
exit 0
;;
-sct)
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi
;;
-gct)
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi
;;
-et)
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi
;;
-ml|--max-lines)
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi
;;
-h|--help)
show_help
exit 0
;;
*)
echo "未知选项: $1"
show_help
exit 1
-e|--executable) EXECUTE_MODE=true; shift ;;
-eir) IR_EXECUTE_MODE=true; shift ;;
-c|--clean) clean_tmp; exit 0 ;;
-O1) OPTIMIZE_FLAG="-O1"; shift ;;
-set)
shift
while [[ "$#" -gt 0 && ! "$1" =~ ^- ]]; do TEST_SETS+=("$1"); shift; done
;;
-sct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift 2; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi ;;
-lct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then LLC_TIMEOUT="$2"; shift 2; else echo "错误: -lct 需要一个正整数参数。" >&2; exit 1; fi ;;
-gct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi ;;
-et) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi ;;
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
-h|--help) show_help; exit 0 ;;
*) echo "未知选项: $1"; show_help; exit 1 ;;
esac
shift
done
if ${EXECUTE_MODE} && ${IR_EXECUTE_MODE}; then
echo -e "\e[31m错误: -e 和 -eir 选项不能同时使用。\e[0m" >&2
exit 1
fi
declare -A SET_MAP
SET_MAP[f]="functional"
SET_MAP[h]="h_functional"
SET_MAP[p]="performance"
SEARCH_PATHS=()
if [ ${#TEST_SETS[@]} -eq 0 ] || [[ " ${TEST_SETS[@]} " =~ " all " ]]; then
SEARCH_PATHS+=("${TESTDATA_DIR}")
else
for set in "${TEST_SETS[@]}"; do
if [[ -v SET_MAP[$set] ]]; then
SEARCH_PATHS+=("${TESTDATA_DIR}/${SET_MAP[$set]}")
else
echo -e "\e[33m警告: 未知的测试集 '$set',已忽略。\e[0m"
fi
done
fi
if [ ${#SEARCH_PATHS[@]} -eq 0 ]; then
echo -e "\e[31m错误: 没有找到有效的测试集目录,测试中止。\e[0m"
exit 1
fi
echo "SysY 测试运行器启动..."
echo "输入目录: ${TESTDATA_DIR}"
if [ -n "$OPTIMIZE_FLAG" ]; then echo "优化等级: ${OPTIMIZE_FLAG}"; fi
echo "输入目录: ${SEARCH_PATHS[@]}"
echo "临时目录: ${TMP_DIR}"
echo "执行模式: ${EXECUTE_MODE}"
if ${EXECUTE_MODE}; then
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
RUN_MODE_INFO=""
if ${IR_EXECUTE_MODE}; then
RUN_MODE_INFO="IR执行模式 (-eir)"
TIMEOUT_INFO="超时设置: sysyc=${SYSYC_TIMEOUT}s, llc=${LLC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
elif ${EXECUTE_MODE}; then
RUN_MODE_INFO="直接执行模式 (-e)"
TIMEOUT_INFO="超时设置: sysyc=${SYSYC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
else
RUN_MODE_INFO="编译模式 (默认)"
TIMEOUT_INFO="超时设置: sysyc=${SYSYC_TIMEOUT}s"
fi
echo "运行模式: ${RUN_MODE_INFO}"
echo "${TIMEOUT_INFO}"
if ${EXECUTE_MODE} || ${IR_EXECUTE_MODE}; then
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
fi
echo ""
# --- 修改点: 查找所有 .sy 文件并按文件名前缀数字排序 ---
sy_files=$(find "${TESTDATA_DIR}" -name "*.sy" | sort -V)
sy_files=$(find "${SEARCH_PATHS[@]}" -name "*.sy" | sort -V)
if [ -z "$sy_files" ]; then
echo "在指定目录中未找到任何 .sy 文件。"
exit 0
fi
TOTAL_CASES=$(echo "$sy_files" | wc -w)
# --- 修复: 使用 here-string (<<<) 代替管道 (|) 来避免子 shell 问题 ---
while IFS= read -r sy_file; do
is_passed=1 # 1 表示通过, 0 表示失败
is_passed=0 # 0 表示失败, 1 表示通过
relative_path_no_ext=$(realpath --relative-to="${TESTDATA_DIR}" "${sy_file%.*}")
output_base_name=$(echo "${relative_path_no_ext}" | tr '/' '_')
assembly_file="${TMP_DIR}/${output_base_name}_sysyc_riscv64.s"
executable_file="${TMP_DIR}/${output_base_name}_sysyc_riscv64"
assembly_file_S="${TMP_DIR}/${output_base_name}_sysyc_S.s"
executable_file_S="${TMP_DIR}/${output_base_name}_sysyc_S"
output_actual_file_S="${TMP_DIR}/${output_base_name}_sysyc_S.actual_out"
ir_file="${TMP_DIR}/${output_base_name}_sysyc_ir.ll"
assembly_file_from_ir="${TMP_DIR}/${output_base_name}_from_ir.s"
executable_file_from_ir="${TMP_DIR}/${output_base_name}_from_ir"
output_actual_file_from_ir="${TMP_DIR}/${output_base_name}_from_ir.actual_out"
input_file="${sy_file%.*}.in"
output_reference_file="${sy_file%.*}.out"
output_actual_file="${TMP_DIR}/${output_base_name}_sysyc_riscv64.actual_out"
echo "正在处理: $(basename "$sy_file") (路径: ${relative_path_no_ext}.sy)"
# 步骤 1: 使用 sysyc 编译 .sy 到 .s
echo " 使用 sysyc 编译 (超时 ${SYSYC_TIMEOUT}s)..."
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file}"
SYSYC_STATUS=$?
if [ $SYSYC_STATUS -eq 124 ]; then
echo -e "\e[31m错误: SysY 编译 ${sy_file} 超时\e[0m"
is_passed=0
elif [ $SYSYC_STATUS -ne 0 ]; then
echo -e "\e[31m错误: SysY 编译 ${sy_file} 失败,退出码: ${SYSYC_STATUS}\e[0m"
is_passed=0
fi
# --- 模式 1: IR 执行模式 (-eir) ---
if ${IR_EXECUTE_MODE}; then
step_failed=0
test_logic_passed=0
# 只有当 EXECUTE_MODE 为 true 且上一步成功时才继续
if ${EXECUTE_MODE} && [ "$is_passed" -eq 1 ]; then
# 步骤 2: 使用 riscv64-linux-gnu-gcc 编译 .s 到可执行文件
echo " 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
GCC_STATUS=$?
if [ $GCC_STATUS -eq 124 ]; then
echo -e "\e[31m错误: GCC 编译 ${assembly_file} 超时\e[0m"
is_passed=0
elif [ $GCC_STATUS -ne 0 ]; then
echo -e "\e[31m错误: GCC 编译 ${assembly_file} 失败,退出码: ${GCC_STATUS}\e[0m"
is_passed=0
echo " [1/4] 使用 sysyc 编译为 IR (超时 ${SYSYC_TIMEOUT}s)..."
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" -o "${ir_file}" ${OPTIMIZE_FLAG}
SYSYC_STATUS=$?
if [ $SYSYC_STATUS -ne 0 ]; then
[ $SYSYC_STATUS -eq 124 ] && echo -e "\e[31m错误: SysY (IR) 编译超时\e[0m" || echo -e "\e[31m错误: SysY (IR) 编译失败,退出码: ${SYSYC_STATUS}\e[0m"
step_failed=1
fi
elif ! ${EXECUTE_MODE}; then
echo " 跳过执行模式。仅生成汇编文件。"
if [ "$is_passed" -eq 1 ]; then
((PASSED_CASES++))
else
FAILED_CASES_LIST+="${relative_path_no_ext}.sy\n"
fi
echo ""
continue
fi
# 步骤 3, 4, 5: 只有当编译都成功时才执行
if [ "$is_passed" -eq 1 ]; then
echo " 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
exec_cmd="${QEMU_RISCV64} \"${executable_file}\""
if [ -f "${input_file}" ]; then
exec_cmd+=" < \"${input_file}\""
fi
exec_cmd+=" > \"${output_actual_file}\""
eval "timeout -s KILL ${EXEC_TIMEOUT} ${exec_cmd}"
ACTUAL_RETURN_CODE=$?
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
echo -e "\e[31m 执行超时: ${sy_file} 运行超过 ${EXEC_TIMEOUT} 秒\e[0m"
is_passed=0
else
if [ -f "${output_reference_file}" ]; then
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
if [[ "$LAST_LINE_TRIMMED" =~ ^[-+]?[0-9]+$ ]]; then
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
EXPECTED_STDOUT_FILE="${TMP_DIR}/${output_base_name}_sysyc_riscv64.expected_stdout"
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
if [ "$ACTUAL_RETURN_CODE" -eq "$EXPECTED_RETURN_CODE" ]; then
echo -e "\e[32m 返回码测试成功: (${ACTUAL_RETURN_CODE}) 与期望值 (${EXPECTED_RETURN_CODE}) 匹配\e[0m"
else
echo -e "\e[31m 返回码测试失败: 期望: ${EXPECTED_RETURN_CODE}, 实际: ${ACTUAL_RETURN_CODE}\e[0m"
is_passed=0
fi
# --- 本次修改点: 使用 tr 删除所有空白字符后再比较 ---
if ! diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
echo -e "\e[31m 标准输出测试失败\e[0m"
is_passed=0
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}"
echo -e " \e[36m------------------------------\e[0m"
fi
else
if [ $ACTUAL_RETURN_CODE -ne 0 ]; then
echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"
fi
# --- 本次修改点: 使用 tr 删除所有空白字符后再比较 ---
if diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
else
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}"
echo -e " \e[36m------------------------------\e[0m"
fi
fi
else
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
if [ "$step_failed" -eq 0 ]; then
echo " [2/4] 使用 llc-19 编译为汇编 (超时 ${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_from_ir}"
LLC_STATUS=$?
if [ $LLC_STATUS -ne 0 ]; then
[ $LLC_STATUS -eq 124 ] && echo -e "\e[31m错误: llc-19 编译超时\e[0m" || echo -e "\e[31m错误: llc-19 编译失败,退出码: ${LLC_STATUS}\e[0m"
step_failed=1
fi
fi
if [ "$step_failed" -eq 0 ]; then
echo " [3/4] 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file_from_ir}" -o "${executable_file_from_ir}" -L"${LIB_DIR}" -lsysy_riscv -static
GCC_STATUS=$?
if [ $GCC_STATUS -ne 0 ]; then
[ $GCC_STATUS -eq 124 ] && echo -e "\e[31m错误: GCC 编译超时\e[0m" || echo -e "\e[31m错误: GCC 编译失败,退出码: ${GCC_STATUS}\e[0m"
step_failed=1
fi
fi
if [ "$step_failed" -eq 0 ]; then
echo " [4/4] 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
exec_cmd="${QEMU_RISCV64} \"${executable_file_from_ir}\""
[ -f "${input_file}" ] && exec_cmd+=" < \"${input_file}\""
exec_cmd+=" > \"${output_actual_file_from_ir}\""
eval "timeout -s KILL ${EXEC_TIMEOUT} ${exec_cmd}"
ACTUAL_RETURN_CODE=$?
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
echo -e "\e[31m 执行超时: 运行超过 ${EXEC_TIMEOUT} 秒\e[0m"
else
if [ -f "${output_reference_file}" ]; then
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
test_logic_passed=1
if [[ "$LAST_LINE_TRIMMED" =~ ^[-+]?[0-9]+$ ]]; then
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
EXPECTED_STDOUT_FILE="${TMP_DIR}/${output_base_name}_from_ir.expected_stdout"
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
if [ "$ACTUAL_RETURN_CODE" -eq "$EXPECTED_RETURN_CODE" ]; then
echo -e "\e[32m 返回码测试成功: (${ACTUAL_RETURN_CODE}) 与期望值 (${EXPECTED_RETURN_CODE}) 匹配\e[0m"
else
echo -e "\e[31m 返回码测试失败: 期望: ${EXPECTED_RETURN_CODE}, 实际: ${ACTUAL_RETURN_CODE}\e[0m"
test_logic_passed=0
fi
if diff -q <(tr -d '[:space:]' < "${output_actual_file_from_ir}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
[ "$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}"
test_logic_passed=0
fi
else
if [ $ACTUAL_RETURN_CODE -ne 0 ]; then echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"; fi
if diff -q <(tr -d '[:space:]' < "${output_actual_file_from_ir}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
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}"
test_logic_passed=0
fi
fi
else
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
test_logic_passed=1
fi
fi
fi
[ "$step_failed" -eq 0 ] && [ "$test_logic_passed" -eq 1 ] && is_passed=1
# --- 模式 2: 直接执行模式 (-e) ---
elif ${EXECUTE_MODE}; then
step_failed=0
test_logic_passed=0
echo " [1/3] 使用 sysyc 编译为汇编 (超时 ${SYSYC_TIMEOUT}s)..."
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file_S}" ${OPTIMIZE_FLAG}
SYSYC_STATUS=$?
if [ $SYSYC_STATUS -ne 0 ]; then
[ $SYSYC_STATUS -eq 124 ] && echo -e "\e[31m错误: SysY (汇编) 编译超时\e[0m" || echo -e "\e[31m错误: SysY (汇编) 编译失败,退出码: ${SYSYC_STATUS}\e[0m"
step_failed=1
fi
if [ "$step_failed" -eq 0 ]; then
echo " [2/3] 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file_S}" -o "${executable_file_S}" -L"${LIB_DIR}" -lsysy_riscv -static
GCC_STATUS=$?
if [ $GCC_STATUS -ne 0 ]; then
[ $GCC_STATUS -eq 124 ] && echo -e "\e[31m错误: GCC 编译超时\e[0m" || echo -e "\e[31m错误: GCC 编译失败,退出码: ${GCC_STATUS}\e[0m"
step_failed=1
fi
fi
if [ "$step_failed" -eq 0 ]; then
echo " [3/3] 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
exec_cmd="${QEMU_RISCV64} \"${executable_file_S}\""
[ -f "${input_file}" ] && exec_cmd+=" < \"${input_file}\""
exec_cmd+=" > \"${output_actual_file_S}\""
eval "timeout -s KILL ${EXEC_TIMEOUT} ${exec_cmd}"
ACTUAL_RETURN_CODE=$?
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
echo -e "\e[31m 执行超时: 运行超过 ${EXEC_TIMEOUT} 秒\e[0m"
else
if [ -f "${output_reference_file}" ]; then
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
test_logic_passed=1
if [[ "$LAST_LINE_TRIMMED" =~ ^[-+]?[0-9]+$ ]]; then
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
EXPECTED_STDOUT_FILE="${TMP_DIR}/${output_base_name}_sysyc_S.expected_stdout"
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
if [ "$ACTUAL_RETURN_CODE" -eq "$EXPECTED_RETURN_CODE" ]; then
echo -e "\e[32m 返回码测试成功: (${ACTUAL_RETURN_CODE}) 与期望值 (${EXPECTED_RETURN_CODE}) 匹配\e[0m"
else
echo -e "\e[31m 返回码测试失败: 期望: ${EXPECTED_RETURN_CODE}, 实际: ${ACTUAL_RETURN_CODE}\e[0m"
test_logic_passed=0
fi
if diff -q <(tr -d '[:space:]' < "${output_actual_file_S}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
[ "$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}"
test_logic_passed=0
fi
else
if [ $ACTUAL_RETURN_CODE -ne 0 ]; then echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"; fi
if diff -q <(tr -d '[:space:]' < "${output_actual_file_S}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
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}"
test_logic_passed=0
fi
fi
else
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
test_logic_passed=1
fi
fi
fi
[ "$step_failed" -eq 0 ] && [ "$test_logic_passed" -eq 1 ] && is_passed=1
# --- 模式 3: 默认编译模式 ---
else
s_compile_ok=0
ir_compile_ok=0
echo " [1/2] 使用 sysyc 编译为汇编 (超时 ${SYSYC_TIMEOUT}s)..."
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file_S}" ${OPTIMIZE_FLAG}
SYSYC_S_STATUS=$?
if [ $SYSYC_S_STATUS -eq 0 ]; then
s_compile_ok=1
echo -e " \e[32m-> ${assembly_file_S} [成功]\e[0m"
else
[ $SYSYC_S_STATUS -eq 124 ] && echo -e " \e[31m-> [编译超时]\e[0m" || echo -e " \e[31m-> [编译失败, 退出码: ${SYSYC_S_STATUS}]\e[0m"
fi
echo " [2/2] 使用 sysyc 编译为 IR (超时 ${SYSYC_TIMEOUT}s)..."
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" -o "${ir_file}" ${OPTIMIZE_FLAG}
SYSYC_IR_STATUS=$?
if [ $SYSYC_IR_STATUS -eq 0 ]; then
ir_compile_ok=1
echo -e " \e[32m-> ${ir_file} [成功]\e[0m"
else
[ $SYSYC_IR_STATUS -eq 124 ] && echo -e " \e[31m-> [编译超时]\e[0m" || echo -e " \e[31m-> [编译失败, 退出码: ${SYSYC_IR_STATUS}]\e[0m"
fi
if [ "$s_compile_ok" -eq 1 ] && [ "$ir_compile_ok" -eq 1 ]; then
is_passed=1
fi
fi
# --- 统计结果 ---
if [ "$is_passed" -eq 1 ]; then
((PASSED_CASES++))
else
# 确保 FAILED_CASES_LIST 的每一项都以换行符结尾
FAILED_CASES_LIST+="${relative_path_no_ext}.sy\n"
fi
echo ""
done <<< "$sy_files"
echo "========================================"
echo "测试完成"
echo "测试通过率: [${PASSED_CASES}/${TOTAL_CASES}]"
if [ -n "$FAILED_CASES_LIST" ]; then
echo ""
echo -e "\e[31m未通过的测例:\e[0m"
echo -e "${FAILED_CASES_LIST}"
fi
echo "========================================"
if [ "$PASSED_CASES" -eq "$TOTAL_CASES" ]; then
exit 0
else
exit 1
fi
# --- 修改:调用总结函数 ---
print_summary

View File

@ -8,9 +8,11 @@ add_library(riscv64_backend_lib STATIC
Handler/CalleeSavedHandler.cpp
Handler/LegalizeImmediates.cpp
Handler/PrologueEpilogueInsertion.cpp
Handler/EliminateFrameIndices.cpp
Optimize/Peephole.cpp
Optimize/PostRA_Scheduler.cpp
Optimize/PreRA_Scheduler.cpp
Optimize/DivStrengthReduction.cpp
)
# 包含后端模块所需的头文件路径

View File

@ -1,8 +1,8 @@
#include "CalleeSavedHandler.h"
#include <set>
#include <vector> //
#include <vector>
#include <algorithm>
#include <iterator> //
#include <iterator>
namespace sysy {
@ -14,149 +14,38 @@ bool CalleeSavedHandler::runOnFunction(Function *F, AnalysisManager& AM) {
}
void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
// 此 Pass 负责分析、分配栈空间并插入 callee-saved 寄存器的保存/恢复指令。
// 它通过与 FrameInfo 协作,确保为 callee-saved 寄存器分配的空间与局部变量/溢出槽的空间不冲突。
StackFrameInfo& frame_info = mfunc->getFrameInfo();
// [修改] 分别记录被使用的整数和浮点被调用者保存寄存器
std::set<PhysicalReg> used_int_callee_saved;
std::set<PhysicalReg> used_fp_callee_saved;
const std::set<PhysicalReg>& used_callee_saved = frame_info.used_callee_saved_regs;
// 1. 扫描所有指令找出被使用的s寄存器 (s1-s11) 和 fs寄存器 (fs0-fs11)
for (auto& mbb : mfunc->getBlocks()) {
for (auto& instr : mbb->getInstructions()) {
for (auto& op : instr->getOperands()) {
auto check_and_insert_reg = [&](RegOperand* reg_op) {
if (!reg_op->isVirtual()) {
PhysicalReg preg = reg_op->getPReg();
// [修改] 区分整数和浮点被调用者保存寄存器
// s0 由序言/尾声处理器专门处理,这里不计入
if (preg >= PhysicalReg::S1 && preg <= PhysicalReg::S11) {
used_int_callee_saved.insert(preg);
}
// fs0-fs11 在我们的枚举中对应 f8,f9,f18-f27
else if ((preg >= PhysicalReg::F8 && preg <= PhysicalReg::F9) || (preg >= PhysicalReg::F18 && preg <= PhysicalReg::F27)) {
used_fp_callee_saved.insert(preg);
}
}
};
if (op->getKind() == MachineOperand::KIND_REG) {
check_and_insert_reg(static_cast<RegOperand*>(op.get()));
} else if (op->getKind() == MachineOperand::KIND_MEM) {
check_and_insert_reg(static_cast<MemOperand*>(op.get())->getBase());
}
}
}
}
// 如果没有使用任何需要处理的 callee-saved 寄存器,则直接返回
if (used_int_callee_saved.empty() && used_fp_callee_saved.empty()) {
frame_info.callee_saved_size = 0; // 确保大小被初始化
if (used_callee_saved.empty()) {
frame_info.callee_saved_size = 0;
frame_info.callee_saved_regs_to_store.clear();
return;
}
// 2. 计算为 callee-saved 寄存器分配的栈空间大小
// 每个寄存器在RV64中都占用8字节
int callee_saved_size = (used_int_callee_saved.size() + used_fp_callee_saved.size()) * 8;
frame_info.callee_saved_size = callee_saved_size;
// 3. 在函数序言中插入保存指令
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
auto& entry_instrs = entry_block->getInstructions();
// 插入点通常在函数入口标签之后
auto insert_pos = entry_instrs.begin();
if (!entry_instrs.empty() && entry_instrs.front()->getOpcode() == RVOpcodes::LABEL) {
insert_pos = std::next(insert_pos);
// 1. 计算被调用者保存寄存器所需的总空间大小
// s0 总是由 PEI Pass 单独处理,这里不计入大小,但要确保它在列表中
int size = 0;
std::set<PhysicalReg> regs_to_save = used_callee_saved;
if (regs_to_save.count(PhysicalReg::S0)) {
regs_to_save.erase(PhysicalReg::S0);
}
// 为了布局确定性,对寄存器进行排序并按序保存
std::vector<PhysicalReg> sorted_int_regs(used_int_callee_saved.begin(), used_int_callee_saved.end());
std::vector<PhysicalReg> sorted_fp_regs(used_fp_callee_saved.begin(), used_fp_callee_saved.end());
std::sort(sorted_int_regs.begin(), sorted_int_regs.end());
std::sort(sorted_fp_regs.begin(), sorted_fp_regs.end());
std::vector<std::unique_ptr<MachineInstr>> save_instrs;
int current_offset = -16; // ra和s0已占用-8和-16从-24开始分配
size = regs_to_save.size() * 8; // 每个寄存器占8字节 (64-bit)
frame_info.callee_saved_size = size;
// 准备整数保存指令 (sd)
for (PhysicalReg reg : sorted_int_regs) {
current_offset -= 8;
auto sd = std::make_unique<MachineInstr>(RVOpcodes::SD);
sd->addOperand(std::make_unique<RegOperand>(reg));
sd->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0), // 基址为帧指针 s0
std::make_unique<ImmOperand>(current_offset)
));
save_instrs.push_back(std::move(sd));
}
// 准备浮点保存指令 (fsd)
for (PhysicalReg reg : sorted_fp_regs) {
current_offset -= 8;
auto fsd = std::make_unique<MachineInstr>(RVOpcodes::FSD); // 使用浮点保存指令
fsd->addOperand(std::make_unique<RegOperand>(reg));
fsd->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(current_offset)
));
save_instrs.push_back(std::move(fsd));
}
// 2. 创建一个有序的、需要保存的寄存器列表,以便后续 Pass 确定地生成代码
// s0 不应包含在此列表中,因为它由 PEI Pass 特殊处理
std::vector<PhysicalReg> sorted_regs(regs_to_save.begin(), regs_to_save.end());
std::sort(sorted_regs.begin(), sorted_regs.end(), [](PhysicalReg a, PhysicalReg b){
return static_cast<int>(a) < static_cast<int>(b);
});
frame_info.callee_saved_regs_to_store = sorted_regs;
// 一次性插入所有保存指令
if (!save_instrs.empty()) {
entry_instrs.insert(insert_pos,
std::make_move_iterator(save_instrs.begin()),
std::make_move_iterator(save_instrs.end()));
}
// 4. 在函数结尾ret之前插入恢复指令
for (auto& mbb : mfunc->getBlocks()) {
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
if ((*it)->getOpcode() == RVOpcodes::RET) {
std::vector<std::unique_ptr<MachineInstr>> restore_instrs;
current_offset = -16; // 重置偏移量用于恢复
// 准备恢复整数寄存器 (ld) - 以与保存时相同的顺序
for (PhysicalReg reg : sorted_int_regs) {
current_offset -= 8;
auto ld = std::make_unique<MachineInstr>(RVOpcodes::LD);
ld->addOperand(std::make_unique<RegOperand>(reg));
ld->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(current_offset)
));
restore_instrs.push_back(std::move(ld));
}
// 准备恢复浮点寄存器 (fld)
for (PhysicalReg reg : sorted_fp_regs) {
current_offset -= 8;
auto fld = std::make_unique<MachineInstr>(RVOpcodes::FLD); // 使用浮点加载指令
fld->addOperand(std::make_unique<RegOperand>(reg));
fld->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(current_offset)
));
restore_instrs.push_back(std::move(fld));
}
// 一次性插入所有恢复指令
if (!restore_instrs.empty()) {
mbb->getInstructions().insert(it,
std::make_move_iterator(restore_instrs.begin()),
std::make_move_iterator(restore_instrs.end()));
}
// 处理完一个基本块的RET后迭代器已失效需跳出当前块的循环
goto next_block_label;
}
}
next_block_label:;
}
// 3. 更新栈帧总大小。
// 这是初步计算PEI Pass 会进行最终的对齐。
frame_info.total_size = frame_info.locals_size +
frame_info.spill_size +
frame_info.callee_saved_size;
}
} // namespace sysy
} // namespace sysy

View File

@ -0,0 +1,235 @@
#include "EliminateFrameIndices.h"
#include "RISCv64ISel.h"
#include <cassert>
#include <vector>
namespace sysy {
// getTypeSizeInBytes 是一个通用辅助函数,保持不变
unsigned EliminateFrameIndicesPass::getTypeSizeInBytes(Type* type) {
if (!type) {
assert(false && "Cannot get size of a null type.");
return 0;
}
switch (type->getKind()) {
case Type::kInt:
case Type::kFloat:
return 4;
case Type::kPointer:
return 8;
case Type::kArray: {
auto arrayType = type->as<ArrayType>();
return arrayType->getNumElements() * getTypeSizeInBytes(arrayType->getElementType());
}
default:
assert(false && "Unsupported type for size calculation.");
return 0;
}
}
void EliminateFrameIndicesPass::runOnMachineFunction(MachineFunction* mfunc) {
StackFrameInfo& frame_info = mfunc->getFrameInfo();
Function* F = mfunc->getFunc();
RISCv64ISel* isel = mfunc->getISel();
// 在这里处理栈传递的参数以便在寄存器分配前就将数据流显式化修复溢出逻辑的BUG。
// 2. 只为局部变量(AllocaInst)分配栈空间和计算偏移量
// 局部变量从 s0 下方(负偏移量)开始分配,紧接着为 ra 和 s0 预留的16字节之后
int local_var_offset = 16;
if(F) { // 确保函数指针有效
for (auto& bb : F->getBasicBlocks()) {
for (auto& inst : bb->getInstructions()) {
if (auto alloca = dynamic_cast<AllocaInst*>(inst.get())) {
Type* allocated_type = alloca->getType()->as<PointerType>()->getBaseType();
int size = getTypeSizeInBytes(allocated_type);
// 优化栈帧大小对于大数组使用4字节对齐小对象使用8字节对齐
if (size >= 256) { // 大数组优化
size = (size + 3) & ~3; // 4字节对齐
} else {
size = (size + 7) & ~7; // 8字节对齐
}
if (size == 0) size = 4; // 最小4字节
local_var_offset += size;
unsigned alloca_vreg = isel->getVReg(alloca);
// 局部变量使用相对于s0的负向偏移
frame_info.alloca_offsets[alloca_vreg] = -local_var_offset;
}
}
}
}
// 记录仅由AllocaInst分配的局部变量的总大小
frame_info.locals_size = local_var_offset - 16;
// 记录局部变量区域分配结束的最终偏移量
frame_info.locals_end_offset = -local_var_offset;
// 在函数入口为所有栈传递的参数插入load指令
// 这个步骤至关重要它在寄存器分配之前为这些参数的vreg创建了明确的“定义(def)”指令。
// 这解决了在高寄存器压力下当这些vreg被溢出时`rewriteProgram`找不到其定义点而崩溃的问题。
if (F && isel && !mfunc->getBlocks().empty()) {
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
std::vector<std::unique_ptr<MachineInstr>> arg_load_instrs;
// 步骤 3.1: 生成所有加载栈参数的指令,暂存起来
int arg_idx = 0;
for (Argument* arg : F->getArguments()) {
// 根据ABI前8个整型/指针参数通过寄存器传递,这里只处理超出部分。
if (arg_idx >= 8) {
// 计算参数在调用者栈帧中的位置该位置相对于被调用者的帧指针s0是正向偏移。
// 第9个参数(arg_idx=8)位于 0(s0)第10个(arg_idx=9)位于 8(s0),以此类推。
int offset = (arg_idx - 8) * 8;
unsigned arg_vreg = isel->getVReg(arg);
Type* arg_type = arg->getType();
// 根据参数类型选择正确的加载指令
RVOpcodes load_op;
if (arg_type->isFloat()) {
load_op = RVOpcodes::FLW; // 单精度浮点
} else if (arg_type->isPointer()) {
load_op = RVOpcodes::LD; // 64位指针
} else {
load_op = RVOpcodes::LW; // 32位整数
}
// 创建加载指令: lw/ld/flw vreg, offset(s0)
auto load_instr = std::make_unique<MachineInstr>(load_op);
load_instr->addOperand(std::make_unique<RegOperand>(arg_vreg));
load_instr->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0), // 基址为帧指针
std::make_unique<ImmOperand>(offset)
));
arg_load_instrs.push_back(std::move(load_instr));
}
arg_idx++;
}
//仅当有需要加载的栈参数时,才执行插入逻辑
if (!arg_load_instrs.empty()) {
auto& entry_instrs = entry_block->getInstructions();
auto insertion_point = entry_instrs.begin(); // 默认插入点为块的开头
auto last_arg_save_it = entry_instrs.end();
// 步骤 3.2: 寻找一个安全的插入点。
// 遍历入口块的指令,找到最后一条保存“寄存器传递参数”的伪指令。
// 这样可以确保我们在所有 a0-a7 参数被保存之后,才执行可能覆盖它们的加载指令。
for (auto it = entry_instrs.begin(); it != entry_instrs.end(); ++it) {
MachineInstr* instr = it->get();
// 寻找代表保存参数到栈的伪指令
if (instr->getOpcode() == RVOpcodes::FRAME_STORE_W ||
instr->getOpcode() == RVOpcodes::FRAME_STORE_D ||
instr->getOpcode() == RVOpcodes::FRAME_STORE_F) {
// 检查被保存的值是否是寄存器参数 (arg_no < 8)
auto& operands = instr->getOperands();
if (operands.empty() || operands[0]->getKind() != MachineOperand::KIND_REG) continue;
unsigned src_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
Value* ir_value = isel->getVRegValueMap().count(src_vreg) ? isel->getVRegValueMap().at(src_vreg) : nullptr;
if (auto ir_arg = dynamic_cast<Argument*>(ir_value)) {
if (ir_arg->getIndex() < 8) {
last_arg_save_it = it; // 找到了一个保存寄存器参数的指令,更新位置
}
}
}
}
// 如果找到了这样的保存指令,我们的插入点就在它之后
if (last_arg_save_it != entry_instrs.end()) {
insertion_point = std::next(last_arg_save_it);
}
// 步骤 3.3: 在计算出的安全位置,一次性插入所有新创建的参数加载指令
entry_instrs.insert(insertion_point,
std::make_move_iterator(arg_load_instrs.begin()),
std::make_move_iterator(arg_load_instrs.end()));
}
}
// 4. 遍历所有机器指令,将访问局部变量的伪指令展开为真实指令
for (auto& mbb : mfunc->getBlocks()) {
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
for (auto& instr_ptr : mbb->getInstructions()) {
RVOpcodes opcode = instr_ptr->getOpcode();
if (opcode == RVOpcodes::FRAME_LOAD_W || opcode == RVOpcodes::FRAME_LOAD_D || opcode == RVOpcodes::FRAME_LOAD_F) {
RVOpcodes real_load_op;
if (opcode == RVOpcodes::FRAME_LOAD_W) real_load_op = RVOpcodes::LW;
else if (opcode == RVOpcodes::FRAME_LOAD_D) real_load_op = RVOpcodes::LD;
else real_load_op = RVOpcodes::FLW;
auto& operands = instr_ptr->getOperands();
unsigned dest_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
int offset = frame_info.alloca_offsets.at(alloca_vreg);
auto addr_vreg = isel->getNewVReg(Type::getPointerType(Type::getIntType()));
// 展开为: addi addr_vreg, s0, offset
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
addi->addOperand(std::make_unique<RegOperand>(addr_vreg));
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
addi->addOperand(std::make_unique<ImmOperand>(offset));
new_instructions.push_back(std::move(addi));
// 展开为: lw/ld/flw dest_vreg, 0(addr_vreg)
auto load_instr = std::make_unique<MachineInstr>(real_load_op);
load_instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
load_instr->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(addr_vreg),
std::make_unique<ImmOperand>(0)));
new_instructions.push_back(std::move(load_instr));
} else if (opcode == RVOpcodes::FRAME_STORE_W || opcode == RVOpcodes::FRAME_STORE_D || opcode == RVOpcodes::FRAME_STORE_F) {
RVOpcodes real_store_op;
if (opcode == RVOpcodes::FRAME_STORE_W) real_store_op = RVOpcodes::SW;
else if (opcode == RVOpcodes::FRAME_STORE_D) real_store_op = RVOpcodes::SD;
else real_store_op = RVOpcodes::FSW;
auto& operands = instr_ptr->getOperands();
unsigned src_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
int offset = frame_info.alloca_offsets.at(alloca_vreg);
auto addr_vreg = isel->getNewVReg(Type::getPointerType(Type::getIntType()));
// 展开为: addi addr_vreg, s0, offset
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
addi->addOperand(std::make_unique<RegOperand>(addr_vreg));
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
addi->addOperand(std::make_unique<ImmOperand>(offset));
new_instructions.push_back(std::move(addi));
// 展开为: sw/sd/fsw src_vreg, 0(addr_vreg)
auto store_instr = std::make_unique<MachineInstr>(real_store_op);
store_instr->addOperand(std::make_unique<RegOperand>(src_vreg));
store_instr->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(addr_vreg),
std::make_unique<ImmOperand>(0)));
new_instructions.push_back(std::move(store_instr));
} else if (instr_ptr->getOpcode() == RVOpcodes::FRAME_ADDR) {
auto& operands = instr_ptr->getOperands();
unsigned dest_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
int offset = frame_info.alloca_offsets.at(alloca_vreg);
// 将 `frame_addr rd, rs` 展开为 `addi rd, s0, offset`
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
addi->addOperand(std::make_unique<RegOperand>(dest_vreg));
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
addi->addOperand(std::make_unique<ImmOperand>(offset));
new_instructions.push_back(std::move(addi));
} else {
new_instructions.push_back(std::move(instr_ptr));
}
}
mbb->getInstructions() = std::move(new_instructions);
}
}
} // namespace sysy

View File

@ -1,6 +1,9 @@
#include "PrologueEpilogueInsertion.h"
#include "RISCv64LLIR.h" // 假设包含了 PhysicalReg, RVOpcodes 等定义
#include "RISCv64ISel.h"
#include "RISCv64RegAlloc.h" // 需要访问RegAlloc的结果
#include <algorithm>
#include <vector>
#include <set>
namespace sysy {
@ -11,35 +14,72 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
Function* F = mfunc->getFunc();
RISCv64ISel* isel = mfunc->getISel();
// [关键] 获取寄存器分配的结果 (vreg -> preg 的映射)
// RegAlloc Pass 必须已经运行过
// 1. 清理 KEEPALIVE 伪指令
for (auto& mbb : mfunc->getBlocks()) {
auto& instrs = mbb->getInstructions();
instrs.erase(
std::remove_if(instrs.begin(), instrs.end(),
[](const std::unique_ptr<MachineInstr>& instr) {
return instr->getOpcode() == RVOpcodes::PSEUDO_KEEPALIVE;
}
),
instrs.end()
);
}
// 2. 确定需要保存的被调用者保存寄存器 (callee-saved)
auto& vreg_to_preg_map = frame_info.vreg_to_preg_map;
std::set<PhysicalReg> used_callee_saved_regs_set;
const auto& callee_saved_int = getCalleeSavedIntRegs();
const auto& callee_saved_fp = getCalleeSavedFpRegs();
// 完全遵循 AsmPrinter 中的计算逻辑
for (const auto& pair : vreg_to_preg_map) {
PhysicalReg preg = pair.second;
bool is_int_cs = std::find(callee_saved_int.begin(), callee_saved_int.end(), preg) != callee_saved_int.end();
bool is_fp_cs = std::find(callee_saved_fp.begin(), callee_saved_fp.end(), preg) != callee_saved_fp.end();
if ((is_int_cs && preg != PhysicalReg::S0) || is_fp_cs) {
used_callee_saved_regs_set.insert(preg);
}
}
frame_info.callee_saved_regs_to_store.assign(
used_callee_saved_regs_set.begin(), used_callee_saved_regs_set.end()
);
std::sort(frame_info.callee_saved_regs_to_store.begin(), frame_info.callee_saved_regs_to_store.end());
frame_info.callee_saved_size = frame_info.callee_saved_regs_to_store.size() * 8;
// 3. 计算最终的栈帧总大小,包含栈溢出保护
int total_stack_size = frame_info.locals_size +
frame_info.spill_size +
frame_info.callee_saved_size +
16; // 为 ra 和 s0 固定的16字节
16;
// 栈溢出保护:增加最大栈帧大小以容纳大型数组
const int MAX_STACK_FRAME_SIZE = 8192; // 8KB to handle large arrays like 256*4*2 = 2048 bytes
if (total_stack_size > MAX_STACK_FRAME_SIZE) {
// 如果仍然超过限制,尝试优化对齐方式
std::cerr << "Warning: Stack frame size " << total_stack_size
<< " exceeds recommended limit " << MAX_STACK_FRAME_SIZE << " for function "
<< mfunc->getName() << std::endl;
}
// 优化减少对齐开销使用16字节对齐而非更大的对齐
int aligned_stack_size = (total_stack_size + 15) & ~15;
frame_info.total_size = aligned_stack_size;
// 只有在需要分配栈空间时才生成指令
if (aligned_stack_size > 0) {
// --- 1. 插入序言 ---
// --- 4. 插入完整的序言 ---
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
auto& entry_instrs = entry_block->getInstructions();
std::vector<std::unique_ptr<MachineInstr>> prologue_instrs;
// 1. addi sp, sp, -aligned_stack_size
// 4.1. 分配栈帧
auto alloc_stack = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
alloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
alloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
alloc_stack->addOperand(std::make_unique<ImmOperand>(-aligned_stack_size));
prologue_instrs.push_back(std::move(alloc_stack));
// 2. sd ra, (aligned_stack_size - 8)(sp)
// 4.2. 保存 ra 和 s0
auto save_ra = std::make_unique<MachineInstr>(RVOpcodes::SD);
save_ra->addOperand(std::make_unique<RegOperand>(PhysicalReg::RA));
save_ra->addOperand(std::make_unique<MemOperand>(
@ -47,8 +87,6 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
std::make_unique<ImmOperand>(aligned_stack_size - 8)
));
prologue_instrs.push_back(std::move(save_ra));
// 3. sd s0, (aligned_stack_size - 16)(sp)
auto save_fp = std::make_unique<MachineInstr>(RVOpcodes::SD);
save_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
save_fp->addOperand(std::make_unique<MemOperand>(
@ -57,85 +95,55 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
));
prologue_instrs.push_back(std::move(save_fp));
// 4. addi s0, sp, aligned_stack_size
// 4.3. 设置新的帧指针 s0
auto set_fp = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
set_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
set_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
set_fp->addOperand(std::make_unique<ImmOperand>(aligned_stack_size));
prologue_instrs.push_back(std::move(set_fp));
// --- [正确逻辑] 在s0设置完毕后使用物理寄存器加载栈参数 ---
if (F && isel) {
// 定义暂存寄存器
const PhysicalReg INT_SCRATCH_REG = PhysicalReg::T5;
const PhysicalReg FP_SCRATCH_REG = PhysicalReg::F7;
int arg_idx = 0;
for (Argument* arg : F->getArguments()) {
if (arg_idx >= 8) {
unsigned vreg = isel->getVReg(arg);
// 确认RegAlloc已经为这个vreg计算了偏移量并且分配了物理寄存器
if (frame_info.alloca_offsets.count(vreg) && vreg_to_preg_map.count(vreg)) {
int offset = frame_info.alloca_offsets.at(vreg);
PhysicalReg dest_preg = vreg_to_preg_map.at(vreg);
Type* arg_type = arg->getType();
// 根据类型执行不同的加载序列
if (arg_type->isFloat()) {
// 1. flw ft7, offset(s0)
auto load_arg = std::make_unique<MachineInstr>(RVOpcodes::FLW);
load_arg->addOperand(std::make_unique<RegOperand>(FP_SCRATCH_REG));
load_arg->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(offset)
));
prologue_instrs.push_back(std::move(load_arg));
// 2. fmv.s dest_preg, ft7
auto move_arg = std::make_unique<MachineInstr>(RVOpcodes::FMV_S);
move_arg->addOperand(std::make_unique<RegOperand>(dest_preg));
move_arg->addOperand(std::make_unique<RegOperand>(FP_SCRATCH_REG));
prologue_instrs.push_back(std::move(move_arg));
} else {
// 确定是加载32位(lw)还是64位(ld)
RVOpcodes load_op = arg_type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW;
// 1. lw/ld t5, offset(s0)
auto load_arg = std::make_unique<MachineInstr>(load_op);
load_arg->addOperand(std::make_unique<RegOperand>(INT_SCRATCH_REG));
load_arg->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(offset)
));
prologue_instrs.push_back(std::move(load_arg));
// 2. mv dest_preg, t5
auto move_arg = std::make_unique<MachineInstr>(RVOpcodes::MV);
move_arg->addOperand(std::make_unique<RegOperand>(dest_preg));
move_arg->addOperand(std::make_unique<RegOperand>(INT_SCRATCH_REG));
prologue_instrs.push_back(std::move(move_arg));
}
}
}
arg_idx++;
}
}
// 确定插入点
auto insert_pos = entry_instrs.begin();
// 一次性将所有序言指令插入
if (!prologue_instrs.empty()) {
entry_instrs.insert(insert_pos,
std::make_move_iterator(prologue_instrs.begin()),
std::make_move_iterator(prologue_instrs.end()));
// 4.4. 保存所有使用到的被调用者保存寄存器
int next_available_offset = -(16 + frame_info.locals_size + frame_info.spill_size);
for (const auto& reg : frame_info.callee_saved_regs_to_store) {
// 改为“先更新,后使用”逻辑
next_available_offset -= 8; // 先为当前寄存器分配下一个可用槽位
RVOpcodes store_op = isFPR(reg) ? RVOpcodes::FSD : RVOpcodes::SD;
auto save_cs_reg = std::make_unique<MachineInstr>(store_op);
save_cs_reg->addOperand(std::make_unique<RegOperand>(reg));
save_cs_reg->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(next_available_offset) // 使用新计算出的正确偏移
));
prologue_instrs.push_back(std::move(save_cs_reg));
// 不再需要在循环末尾递减
}
// --- 2. 插入尾声 (此部分逻辑保持不变) ---
// 4.5. 将所有生成的序言指令一次性插入到函数入口
entry_instrs.insert(entry_instrs.begin(),
std::make_move_iterator(prologue_instrs.begin()),
std::make_move_iterator(prologue_instrs.end()));
// --- 5. 插入完整的尾声 ---
for (auto& mbb : mfunc->getBlocks()) {
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
if ((*it)->getOpcode() == RVOpcodes::RET) {
std::vector<std::unique_ptr<MachineInstr>> epilogue_instrs;
// 5.1. 恢复被调用者保存寄存器
int next_available_offset_restore = -(16 + frame_info.locals_size + frame_info.spill_size);
for (const auto& reg : frame_info.callee_saved_regs_to_store) {
next_available_offset_restore -= 8; // 为下一个寄存器准备偏移
RVOpcodes load_op = isFPR(reg) ? RVOpcodes::FLD : RVOpcodes::LD;
auto restore_cs_reg = std::make_unique<MachineInstr>(load_op);
restore_cs_reg->addOperand(std::make_unique<RegOperand>(reg));
restore_cs_reg->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(next_available_offset_restore) // 使用当前偏移
));
epilogue_instrs.push_back(std::move(restore_cs_reg));
}
// 1. ld ra
// 5.2. 恢复 ra 和 s0
auto restore_ra = std::make_unique<MachineInstr>(RVOpcodes::LD);
restore_ra->addOperand(std::make_unique<RegOperand>(PhysicalReg::RA));
restore_ra->addOperand(std::make_unique<MemOperand>(
@ -143,8 +151,6 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
std::make_unique<ImmOperand>(aligned_stack_size - 8)
));
epilogue_instrs.push_back(std::move(restore_ra));
// 2. ld s0
auto restore_fp = std::make_unique<MachineInstr>(RVOpcodes::LD);
restore_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
restore_fp->addOperand(std::make_unique<MemOperand>(
@ -153,18 +159,18 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
));
epilogue_instrs.push_back(std::move(restore_fp));
// 3. addi sp, sp, aligned_stack_size
// 5.3. 释放栈帧
auto dealloc_stack = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
dealloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
dealloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
dealloc_stack->addOperand(std::make_unique<ImmOperand>(aligned_stack_size));
epilogue_instrs.push_back(std::move(dealloc_stack));
if (!epilogue_instrs.empty()) {
mbb->getInstructions().insert(it,
std::make_move_iterator(epilogue_instrs.begin()),
std::make_move_iterator(epilogue_instrs.end()));
}
// 将尾声指令插入到 RET 指令之前
mbb->getInstructions().insert(it,
std::make_move_iterator(epilogue_instrs.begin()),
std::make_move_iterator(epilogue_instrs.end()));
goto next_block;
}
}

View File

@ -0,0 +1,282 @@
#include "DivStrengthReduction.h"
#include <cmath>
#include <cstdint>
namespace sysy {
char DivStrengthReduction::ID = 0;
bool DivStrengthReduction::runOnFunction(Function *F, AnalysisManager& AM) {
// This pass works on MachineFunction level, not IR level
return false;
}
void DivStrengthReduction::runOnMachineFunction(MachineFunction *mfunc) {
if (!mfunc)
return;
bool debug = false; // Set to true for debugging
if (debug)
std::cout << "Running DivStrengthReduction optimization..." << std::endl;
int next_temp_reg = 1000;
auto createTempReg = [&]() -> int {
return next_temp_reg++;
};
struct MagicInfo {
int64_t magic;
int shift;
};
auto computeMagic = [](int64_t d, bool is_32bit) -> MagicInfo {
int word_size = is_32bit ? 32 : 64;
uint64_t ad = std::abs(d);
if (ad == 0) return {0, 0};
int l = std::floor(std::log2(ad));
if ((ad & (ad - 1)) == 0) { // power of 2
l = 0; // special case for power of 2, shift will be calculated differently
}
__int128_t one = 1;
__int128_t num;
int total_shift;
if (is_32bit) {
total_shift = 31 + l;
num = one << total_shift;
} else {
total_shift = 63 + l;
num = one << total_shift;
}
__int128_t den = ad;
int64_t magic = (num / den) + 1;
return {magic, total_shift};
};
auto isPowerOfTwo = [](int64_t n) -> bool {
return n > 0 && (n & (n - 1)) == 0;
};
auto getPowerOfTwoExponent = [](int64_t n) -> int {
if (n <= 0 || (n & (n - 1)) != 0) return -1;
int shift = 0;
while (n > 1) {
n >>= 1;
shift++;
}
return shift;
};
struct InstructionReplacement {
size_t index;
size_t count_to_erase;
std::vector<std::unique_ptr<MachineInstr>> newInstrs;
};
for (auto &mbb_uptr : mfunc->getBlocks()) {
auto &mbb = *mbb_uptr;
auto &instrs = mbb.getInstructions();
std::vector<InstructionReplacement> replacements;
for (size_t i = 0; i < instrs.size(); ++i) {
auto *instr = instrs[i].get();
bool is_32bit = (instr->getOpcode() == RVOpcodes::DIVW);
if (instr->getOpcode() != RVOpcodes::DIV && !is_32bit) {
continue;
}
if (instr->getOperands().size() != 3) {
continue;
}
auto *dst_op = instr->getOperands()[0].get();
auto *src1_op = instr->getOperands()[1].get();
auto *src2_op = instr->getOperands()[2].get();
int64_t divisor = 0;
bool const_divisor_found = false;
size_t instructions_to_replace = 1;
if (src2_op->getKind() == MachineOperand::KIND_IMM) {
divisor = static_cast<ImmOperand *>(src2_op)->getValue();
const_divisor_found = true;
} else if (src2_op->getKind() == MachineOperand::KIND_REG) {
if (i > 0) {
auto *prev_instr = instrs[i - 1].get();
if (prev_instr->getOpcode() == RVOpcodes::LI && prev_instr->getOperands().size() == 2) {
auto *li_dst_op = prev_instr->getOperands()[0].get();
auto *li_imm_op = prev_instr->getOperands()[1].get();
if (li_dst_op->getKind() == MachineOperand::KIND_REG && li_imm_op->getKind() == MachineOperand::KIND_IMM) {
auto *div_reg_op = static_cast<RegOperand *>(src2_op);
auto *li_dst_reg_op = static_cast<RegOperand *>(li_dst_op);
if (div_reg_op->isVirtual() && li_dst_reg_op->isVirtual() &&
div_reg_op->getVRegNum() == li_dst_reg_op->getVRegNum()) {
divisor = static_cast<ImmOperand *>(li_imm_op)->getValue();
const_divisor_found = true;
instructions_to_replace = 2;
}
}
}
}
}
if (!const_divisor_found) {
continue;
}
auto *dst_reg = static_cast<RegOperand *>(dst_op);
auto *src1_reg = static_cast<RegOperand *>(src1_op);
if (divisor == 0) continue;
std::vector<std::unique_ptr<MachineInstr>> newInstrs;
if (divisor == 1) {
auto moveInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::ADDW : RVOpcodes::ADD);
moveInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
moveInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
moveInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
newInstrs.push_back(std::move(moveInstr));
}
else if (divisor == -1) {
auto negInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SUBW : RVOpcodes::SUB);
negInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
negInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
negInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
newInstrs.push_back(std::move(negInstr));
}
else if (isPowerOfTwo(std::abs(divisor))) {
int shift = getPowerOfTwoExponent(std::abs(divisor));
int temp_reg = createTempReg();
auto sraSignInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SRAIW : RVOpcodes::SRAI);
sraSignInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
sraSignInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
sraSignInstr->addOperand(std::make_unique<ImmOperand>(is_32bit ? 31 : 63));
newInstrs.push_back(std::move(sraSignInstr));
auto srlInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SRLIW : RVOpcodes::SRLI);
srlInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
srlInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
srlInstr->addOperand(std::make_unique<ImmOperand>((is_32bit ? 32 : 64) - shift));
newInstrs.push_back(std::move(srlInstr));
auto addInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::ADDW : RVOpcodes::ADD);
addInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
addInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
addInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
newInstrs.push_back(std::move(addInstr));
auto sraInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SRAIW : RVOpcodes::SRAI);
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
sraInstr->addOperand(std::make_unique<ImmOperand>(shift));
newInstrs.push_back(std::move(sraInstr));
if (divisor < 0) {
auto negInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SUBW : RVOpcodes::SUB);
negInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
negInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
negInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
newInstrs.push_back(std::move(negInstr));
} else {
auto moveInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::ADDW : RVOpcodes::ADD);
moveInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
moveInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
moveInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
newInstrs.push_back(std::move(moveInstr));
}
}
else {
auto magic_info = computeMagic(divisor, is_32bit);
int magic_reg = createTempReg();
int temp_reg = createTempReg();
auto loadInstr = std::make_unique<MachineInstr>(RVOpcodes::LI);
loadInstr->addOperand(std::make_unique<RegOperand>(magic_reg));
loadInstr->addOperand(std::make_unique<ImmOperand>(magic_info.magic));
newInstrs.push_back(std::move(loadInstr));
if (is_32bit) {
auto mulInstr = std::make_unique<MachineInstr>(RVOpcodes::MUL);
mulInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
mulInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
mulInstr->addOperand(std::make_unique<RegOperand>(magic_reg));
newInstrs.push_back(std::move(mulInstr));
auto sraInstr = std::make_unique<MachineInstr>(RVOpcodes::SRAI);
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
sraInstr->addOperand(std::make_unique<ImmOperand>(magic_info.shift));
newInstrs.push_back(std::move(sraInstr));
} else {
auto mulhInstr = std::make_unique<MachineInstr>(RVOpcodes::MULH);
mulhInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
mulhInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
mulhInstr->addOperand(std::make_unique<RegOperand>(magic_reg));
newInstrs.push_back(std::move(mulhInstr));
int post_shift = magic_info.shift - 63;
if (post_shift > 0) {
auto sraInstr = std::make_unique<MachineInstr>(RVOpcodes::SRAI);
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
sraInstr->addOperand(std::make_unique<ImmOperand>(post_shift));
newInstrs.push_back(std::move(sraInstr));
}
}
int sign_reg = createTempReg();
auto sraSignInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SRAIW : RVOpcodes::SRAI);
sraSignInstr->addOperand(std::make_unique<RegOperand>(sign_reg));
sraSignInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
sraSignInstr->addOperand(std::make_unique<ImmOperand>(is_32bit ? 31 : 63));
newInstrs.push_back(std::move(sraSignInstr));
auto subInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SUBW : RVOpcodes::SUB);
subInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
subInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
subInstr->addOperand(std::make_unique<RegOperand>(sign_reg));
newInstrs.push_back(std::move(subInstr));
if (divisor < 0) {
auto negInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SUBW : RVOpcodes::SUB);
negInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
negInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
negInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
newInstrs.push_back(std::move(negInstr));
} else {
auto moveInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::ADDW : RVOpcodes::ADD);
moveInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
moveInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
moveInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
newInstrs.push_back(std::move(moveInstr));
}
}
if (!newInstrs.empty()) {
size_t start_index = i;
if (instructions_to_replace == 2) {
start_index = i - 1;
}
replacements.push_back({start_index, instructions_to_replace, std::move(newInstrs)});
}
}
for (auto it = replacements.rbegin(); it != replacements.rend(); ++it) {
instrs.erase(instrs.begin() + it->index, instrs.begin() + it->index + it->count_to_erase);
instrs.insert(instrs.begin() + it->index,
std::make_move_iterator(it->newInstrs.begin()),
std::make_move_iterator(it->newInstrs.end()));
}
}
}
} // namespace sysy

View File

@ -1,7 +1,8 @@
#include "RISCv64AsmPrinter.h"
#include "RISCv64ISel.h"
#include <stdexcept>
#include <sstream>
#include <iostream>
namespace sysy {
// 检查是否为内存加载/存储指令,以处理特殊的打印格式
@ -60,7 +61,7 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
case RVOpcodes::ADD: *OS << "add "; break; case RVOpcodes::ADDI: *OS << "addi "; break;
case RVOpcodes::ADDW: *OS << "addw "; break; case RVOpcodes::ADDIW: *OS << "addiw "; break;
case RVOpcodes::SUB: *OS << "sub "; break; case RVOpcodes::SUBW: *OS << "subw "; break;
case RVOpcodes::MUL: *OS << "mul "; break; case RVOpcodes::MULW: *OS << "mulw "; break;
case RVOpcodes::MUL: *OS << "mul "; break; case RVOpcodes::MULW: *OS << "mulw "; break; case RVOpcodes::MULH: *OS << "mulh "; break;
case RVOpcodes::DIV: *OS << "div "; break; case RVOpcodes::DIVW: *OS << "divw "; break;
case RVOpcodes::REM: *OS << "rem "; break; case RVOpcodes::REMW: *OS << "remw "; break;
case RVOpcodes::XOR: *OS << "xor "; break; case RVOpcodes::XORI: *OS << "xori "; break;
@ -104,7 +105,7 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
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::CALL: { // [核心修改] 为CALL指令添加特殊处理逻辑
case RVOpcodes::CALL: { // 为CALL指令添加特殊处理逻辑
*OS << "call ";
// 遍历所有操作数,只寻找并打印函数名标签
for (const auto& op : instr->getOperands()) {
@ -144,6 +145,9 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
case RVOpcodes::FRAME_STORE_F:
if (!debug) throw std::runtime_error("FRAME_STORE_F not eliminated before AsmPrinter");
*OS << "frame_store_f "; break;
case RVOpcodes::PSEUDO_KEEPALIVE:
if (!debug) throw std::runtime_error("PSEUDO_KEEPALIVE not eliminated before AsmPrinter");
*OS << "keepalive "; break;
default:
throw std::runtime_error("Unknown opcode in AsmPrinter");
}
@ -233,4 +237,30 @@ std::string RISCv64AsmPrinter::regToString(PhysicalReg reg) {
}
}
std::string RISCv64AsmPrinter::formatInstr(const MachineInstr* instr) {
if (!instr) return "(null instr)";
// 使用 stringstream 作为临时的输出目标
std::stringstream ss;
// 关键: 临时将类成员 'OS' 指向我们的 stringstream
std::ostream* old_os = this->OS;
this->OS = &ss;
// 修正: 调用正确的内部打印函数 printMachineInstr
printInstruction(const_cast<MachineInstr*>(instr), false);
// 恢复旧的 ostream 指针
this->OS = old_os;
// 获取stringstream的内容并做一些清理
std::string result = ss.str();
size_t endpos = result.find_last_not_of(" \t\n\r");
if (std::string::npos != endpos) {
result = result.substr(0, endpos + 1);
}
return result;
}
} // namespace sysy

View File

@ -12,28 +12,96 @@ std::string RISCv64CodeGen::code_gen() {
return module_gen();
}
// 模块级代码生成
unsigned RISCv64CodeGen::getTypeSizeInBytes(Type* type) {
if (!type) {
assert(false && "Cannot get size of a null type.");
return 0;
}
switch (type->getKind()) {
// 对于SysY语言基本类型int和float都占用4字节
case Type::kInt:
case Type::kFloat:
return 4;
// 指针类型在RISC-V 64位架构下占用8字节
// 虽然SysY没有'int*'语法但数组变量在IR层面本身就是指针类型
case Type::kPointer:
return 8;
// 数组类型的总大小 = 元素数量 * 单个元素的大小
case Type::kArray: {
auto arrayType = type->as<ArrayType>();
// 递归调用以计算元素大小
return arrayType->getNumElements() * getTypeSizeInBytes(arrayType->getElementType());
}
// 其他类型如Void, Label等不占用栈空间或者不应该出现在这里
default:
// 如果遇到未处理的类型,触发断言,方便调试
// assert(false && "Unsupported type for size calculation.");
return 0; // 对于像Label或Void这样的类型返回0是合理的
}
}
void printInitializer(std::stringstream& ss, const ValueCounter& init_values) {
for (size_t i = 0; i < init_values.getValues().size(); ++i) {
auto val = init_values.getValues()[i];
auto count = init_values.getNumbers()[i];
if (auto constant = dynamic_cast<ConstantValue*>(val)) {
for (unsigned j = 0; j < count; ++j) {
if (constant->isInt()) {
ss << " .word " << constant->getInt() << "\n";
} else {
float f = constant->getFloat();
uint32_t float_bits = *(uint32_t*)&f;
ss << " .word " << float_bits << "\n";
}
}
}
}
}
std::string RISCv64CodeGen::module_gen() {
std::stringstream ss;
// --- 步骤1将全局变量分为.data和.bss两组 ---
// --- 步骤1将全局变量(GlobalValue)分为.data和.bss两组 ---
std::vector<GlobalValue*> data_globals;
std::vector<GlobalValue*> bss_globals;
for (const auto& global_ptr : module->getGlobals()) {
GlobalValue* global = global_ptr.get();
// 使用更健壮的逻辑来判断是否为大型零初始化数组
bool is_all_zeros = true;
const auto& init_values = global->getInitValues();
// 判断是否为大型零初始化数组,以便放入.bss段
bool is_large_zero_array = false;
if (init_values.getValues().size() == 1) {
if (auto const_val = dynamic_cast<ConstantValue*>(init_values.getValues()[0])) {
if (const_val->isInt() && const_val->getInt() == 0 && init_values.getNumbers()[0] > 16) {
is_large_zero_array = true;
// 检查初始化值是否全部为0
if (init_values.getValues().empty()) {
// 如果 ValueCounter 为空GlobalValue 的构造函数会确保它是零初始化的
is_all_zeros = true;
} else {
for (auto val : init_values.getValues()) {
if (auto const_val = dynamic_cast<ConstantValue*>(val)) {
if (!const_val->isZero()) {
is_all_zeros = false;
break;
}
} else {
// 如果初始值包含非常量(例如,另一个全局变量的地址),则不认为是纯零初始化
is_all_zeros = false;
break;
}
}
}
// 使用 getTypeSizeInBytes 检查总大小是否超过阈值 (16个整数 = 64字节)
Type* allocated_type = global->getType()->as<PointerType>()->getBaseType();
unsigned total_size = getTypeSizeInBytes(allocated_type);
bool is_large_zero_array = is_all_zeros && (total_size > 64);
if (is_large_zero_array) {
bss_globals.push_back(global);
} else {
@ -45,8 +113,8 @@ std::string RISCv64CodeGen::module_gen() {
if (!bss_globals.empty()) {
ss << ".bss\n";
for (GlobalValue* global : bss_globals) {
unsigned count = global->getInitValues().getNumbers()[0];
unsigned total_size = count * 4; // 假设元素都是4字节
Type* allocated_type = global->getType()->as<PointerType>()->getBaseType();
unsigned total_size = getTypeSizeInBytes(allocated_type);
ss << " .align 3\n";
ss << ".globl " << global->getName() << "\n";
@ -58,60 +126,66 @@ std::string RISCv64CodeGen::module_gen() {
}
// --- 步骤3生成 .data 段的代码 ---
if (!data_globals.empty()) {
ss << ".data\n"; // 切换到 .data 段
if (!data_globals.empty() || !module->getConsts().empty()) {
ss << ".data\n";
// a. 处理普通的全局变量 (GlobalValue)
for (GlobalValue* global : data_globals) {
Type* allocated_type = global->getType()->as<PointerType>()->getBaseType();
unsigned total_size = getTypeSizeInBytes(allocated_type);
ss << " .align 3\n";
ss << ".globl " << global->getName() << "\n";
ss << ".type " << global->getName() << ", @object\n";
ss << ".size " << global->getName() << ", " << total_size << "\n";
ss << global->getName() << ":\n";
bool is_all_zeros = true;
const auto& init_values = global->getInitValues();
for (size_t i = 0; i < init_values.getValues().size(); ++i) {
auto val = init_values.getValues()[i];
auto count = init_values.getNumbers()[i];
if (auto constant = dynamic_cast<ConstantValue*>(val)) {
for (unsigned j = 0; j < count; ++j) {
if (constant->isInt()) {
ss << " .word " << constant->getInt() << "\n";
} else {
float f = constant->getFloat();
uint32_t float_bits = *(uint32_t*)&f;
ss << " .word " << float_bits << "\n";
if (init_values.getValues().empty()) {
is_all_zeros = true;
} else {
for (auto val : init_values.getValues()) {
if (auto const_val = dynamic_cast<ConstantValue*>(val)) {
if (!const_val->isZero()) {
is_all_zeros = false;
break;
}
} else {
is_all_zeros = false;
break;
}
}
}
if (is_all_zeros) {
ss << " .zero " << total_size << "\n";
} else {
// 对于有非零初始值的变量,保持原有的打印逻辑。
printInitializer(ss, global->getInitValues());
}
}
// b. [新增] 再处理全局常量 (ConstantVariable)
// b. 处理全局常量 (ConstantVariable)
for (const auto& const_ptr : module->getConsts()) {
ConstantVariable* cnst = const_ptr.get();
Type* allocated_type = cnst->getType()->as<PointerType>()->getBaseType();
unsigned total_size = getTypeSizeInBytes(allocated_type);
ss << " .align 3\n";
ss << ".globl " << cnst->getName() << "\n";
ss << ".type " << cnst->getName() << ", @object\n";
ss << ".size " << cnst->getName() << ", " << total_size << "\n";
ss << cnst->getName() << ":\n";
const auto& init_values = cnst->getInitValues();
// 这部分逻辑和处理 GlobalValue 完全相同
for (size_t i = 0; i < init_values.getValues().size(); ++i) {
auto val = init_values.getValues()[i];
auto count = init_values.getNumbers()[i];
if (auto constant = dynamic_cast<ConstantValue*>(val)) {
for (unsigned j = 0; j < count; ++j) {
if (constant->isInt()) {
ss << " .word " << constant->getInt() << "\n";
} else {
float f = constant->getFloat();
uint32_t float_bits = *(uint32_t*)&f;
ss << " .word " << float_bits << "\n";
}
}
}
}
printInitializer(ss, cnst->getInitValues());
}
}
// --- 处理函数 (.text段) ---
// --- 步骤4处理函数 (.text段) 的逻辑 ---
if (!module->getFunctions().empty()) {
ss << ".text\n";
for (const auto& func_pair : module->getFunctions()) {
if (func_pair.second.get()) {
if (func_pair.second.get() && !func_pair.second->getBasicBlocks().empty()) {
ss << function_gen(func_pair.second.get());
if (DEBUG) std::cerr << "Function: " << func_pair.first << " generated.\n";
}
}
}
@ -122,15 +196,43 @@ 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 ss1;
RISCv64AsmPrinter printer1(mfunc.get());
printer1.run(ss1, true);
std::stringstream ss_after_isel;
RISCv64AsmPrinter printer_isel(mfunc.get());
printer_isel.run(ss_after_isel, true);
if (DEBUG) {
std::cout << ss_after_isel.str();
}
if (DEBUG) {
std::cerr << "====== Intermediate Representation after Instruction Selection ======\n"
<< ss_after_isel.str();
}
// 阶段 2: 消除帧索引 (展开伪指令,计算局部变量偏移)
// 这个Pass必须在寄存器分配之前运行
EliminateFrameIndicesPass efi_pass;
efi_pass.runOnMachineFunction(mfunc.get());
// 阶段 2: 指令调度 (Instruction Scheduling)
if (DEBUG) {
std::cerr << "====== stack info after eliminate frame indices ======\n";
mfunc->dumpStackFrameInfo(std::cerr);
std::stringstream ss_after_eli;
printer_isel.run(ss_after_eli, true);
std::cerr << "====== LLIR after eliminate frame indices ======\n"
<< ss_after_eli.str();
}
// 阶段 2: 除法强度削弱优化 (Division Strength Reduction)
DivStrengthReduction div_strength_reduction;
div_strength_reduction.runOnMachineFunction(mfunc.get());
// 阶段 2.1: 指令调度 (Instruction Scheduling)
PreRA_Scheduler scheduler;
scheduler.runOnMachineFunction(mfunc.get());
@ -138,10 +240,20 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
RISCv64RegAlloc reg_alloc(mfunc.get());
reg_alloc.run();
if (DEBUG) {
std::cerr << "====== stack info after reg alloc ======\n";
mfunc->dumpStackFrameInfo(std::cerr);
}
// 阶段 3.1: 处理被调用者保存寄存器
CalleeSavedHandler callee_handler;
callee_handler.runOnMachineFunction(mfunc.get());
if (DEBUG) {
std::cerr << "====== stack info after callee handler ======\n";
mfunc->dumpStackFrameInfo(std::cerr);
}
// 阶段 4: 窥孔优化 (Peephole Optimization)
PeepholeOptimizer peephole;
peephole.runOnMachineFunction(mfunc.get());
@ -154,7 +266,7 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
PrologueEpilogueInsertionPass pei_pass;
pei_pass.runOnMachineFunction(mfunc.get());
// 阶段 3.3: 清理产生的大立即数
// 阶段 3.3: 大立即数合法化
LegalizeImmediatesPass legalizer;
legalizer.runOnMachineFunction(mfunc.get());
@ -162,8 +274,9 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
std::stringstream ss;
RISCv64AsmPrinter printer(mfunc.get());
printer.run(ss);
if (DEBUG) ss << "\n" << ss1.str(); // 将指令选择阶段的结果也包含在最终输出中
return ss.str();
}
} // namespace sysy

View File

@ -1,9 +1,10 @@
#include "RISCv64ISel.h"
#include "IR.h" // For GlobalValue
#include <stdexcept>
#include <set>
#include <functional>
#include <cmath> // For std::fabs
#include <limits> // For std::numeric_limits
#include <cmath>
#include <limits>
#include <iostream>
namespace sysy {
@ -152,17 +153,18 @@ void RISCv64ISel::selectBasicBlock(BasicBlock* bb) {
for (const auto& inst_ptr : bb->getInstructions()) {
DAGNode* node_to_select = nullptr;
if (value_to_node.count(inst_ptr.get())) {
node_to_select = value_to_node.at(inst_ptr.get());
auto it = value_to_node.find(inst_ptr.get());
if (it != value_to_node.end()) {
node_to_select = it->second;
} else {
for(const auto& node : dag) {
if(node->value == inst_ptr.get()) {
node_to_select = node.get();
break;
}
for(const auto& node : dag) {
if(node->value == inst_ptr.get()) {
node_to_select = node.get();
break;
}
}
if(node_to_select) {
}
if(node_to_select) {
select_recursive(node_to_select);
}
}
@ -181,8 +183,12 @@ void RISCv64ISel::selectNode(DAGNode* node) {
case DAGNode::CONSTANT:
case DAGNode::ALLOCA_ADDR:
if (node->value) {
// 确保它有一个关联的虚拟寄存器即可,不生成代码。
getVReg(node->value);
// GlobalValue objects (global variables) should not get virtual registers
// since they represent memory addresses, not register-allocated values
if (dynamic_cast<GlobalValue*>(node->value) == nullptr) {
// 确保它有一个关联的虚拟寄存器即可,不生成代码。
getVReg(node->value);
}
}
break;
@ -374,7 +380,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
Value* base = nullptr;
Value* offset = nullptr;
// [修改] 扩展基地址的判断,使其可以识别 AllocaInst 或 GlobalValue
// 扩展基地址的判断,使其可以识别 AllocaInst 或 GlobalValue
if (dynamic_cast<AllocaInst*>(lhs) || dynamic_cast<GlobalValue*>(lhs)) {
base = lhs;
offset = rhs;
@ -393,7 +399,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(li));
}
// 2. [修改] 根据基地址的类型,生成不同的指令来获取基地址
// 2. 根据基地址的类型,生成不同的指令来获取基地址
auto base_addr_vreg = getNewVReg(Type::getIntType()); // 创建一个新的临时vreg来存放基地址
// 情况一:基地址是局部栈变量
@ -424,7 +430,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
}
}
// [V2优点] 在BINARY节点内部按需加载常量操作数。
// 在BINARY节点内部按需加载常量操作数。
auto load_val_if_const = [&](Value* val) {
if (auto c = dynamic_cast<ConstantValue*>(val)) {
if (DEBUG) {
@ -455,7 +461,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
auto dest_vreg = getVReg(bin);
auto lhs_vreg = getVReg(lhs);
// [V2优点] 融合 ADDIW 优化。
// 融合 ADDIW 优化。
if (rhs_is_imm_opt) {
auto rhs_const = dynamic_cast<ConstantValue*>(rhs);
auto instr = std::make_unique<MachineInstr>(RVOpcodes::ADDIW);
@ -511,6 +517,15 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(instr));
break;
}
case Instruction::kSra: {
auto rhs_const = dynamic_cast<ConstantInteger*>(rhs);
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SRAIW);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<ImmOperand>(rhs_const->getInt()));
CurMBB->addInstruction(std::move(instr));
break;
}
case BinaryInst::kICmpEQ: { // 等于 (a == b) -> (subw; seqz)
auto sub = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
sub->addOperand(std::make_unique<RegOperand>(dest_vreg));
@ -730,11 +745,83 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(instr));
break;
}
case Instruction::kFtoI: { // 浮点 to 整数
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FCVT_W_S);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg)); // 目标是整数vreg
instr->addOperand(std::make_unique<RegOperand>(src_vreg)); // 源是浮点vreg
CurMBB->addInstruction(std::move(instr));
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());
// 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));
// 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));
// 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));
// 创建标签
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: { // 浮点取负
@ -915,7 +1002,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
// --- 步骤 3: 生成CALL指令 ---
auto call_instr = std::make_unique<MachineInstr>(RVOpcodes::CALL);
// [协议] 如果函数有返回值,将它的目标虚拟寄存器作为第一个操作数
// 如果函数有返回值,将它的目标虚拟寄存器作为第一个操作数
if (!call->getType()->isVoid()) {
unsigned dest_vreg = getVReg(call);
call_instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
@ -992,7 +1079,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
} else {
// --- 处理整数/指针返回值 ---
// 返回值需要被放入 a0
// [V2优点] 在RETURN节点内加载常量返回值
// 在RETURN节点内加载常量返回值
if (auto const_val = dynamic_cast<ConstantValue*>(ret_val)) {
auto li_instr = std::make_unique<MachineInstr>(RVOpcodes::LI);
li_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
@ -1006,7 +1093,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
}
}
}
// [V1设计保留] 函数尾声epilogue不由RETURN节点生成
// 函数尾声epilogue不由RETURN节点生成
// 而是由后续的AsmPrinter或其它Pass统一处理这是一种常见且有效的模块化设计。
auto ret_mi = std::make_unique<MachineInstr>(RVOpcodes::RET);
CurMBB->addInstruction(std::move(ret_mi));
@ -1020,7 +1107,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
auto then_bb_name = cond_br->getThenBlock()->getName();
auto else_bb_name = cond_br->getElseBlock()->getName();
// [优化] 检查分支条件是否为编译期常量
// 检查分支条件是否为编译期常量
if (auto const_cond = dynamic_cast<ConstantValue*>(condition)) {
// 如果条件是常量直接生成一个无条件跳转J而不是BNE
if (const_cond->getInt() != 0) { // 条件为 true
@ -1035,7 +1122,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
}
// 如果条件不是常量,则执行标准流程
else {
// [修复] 为条件变量生成加载指令(如果它是常量的话,尽管上面已经处理了)
// 为条件变量生成加载指令(如果它是常量的话,尽管上面已经处理了)
// 这一步是为了逻辑完整,以防有其他类型的常量没有被捕获
if (auto const_val = dynamic_cast<ConstantValue*>(condition)) {
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
@ -1069,7 +1156,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
}
case DAGNode::MEMSET: {
// [V1设计保留] Memset的核心展开逻辑在虚拟寄存器层面是正确的无需修改。
// Memset的核心展开逻辑在虚拟寄存器层面是正确的无需修改。
// 之前的bug是由于其输入地址、值、大小的虚拟寄存器未被正确初始化。
// 在修复了CONSTANT/ALLOCA_ADDR的加载问题后此处的逻辑现在可以正常工作。
@ -1252,14 +1339,19 @@ void RISCv64ISel::selectNode(DAGNode* node) {
if (stride != 0) {
// --- 为当前索引和步长生成偏移计算指令 ---
auto offset_vreg = getNewVReg();
auto index_vreg = getVReg(indexValue);
// 如果索引是常量,先用 LI 指令加载到虚拟寄存器
// 处理索引 - 区分常量与动态值
unsigned index_vreg;
if (auto const_index = dynamic_cast<ConstantValue*>(indexValue)) {
// 对于常量索引,直接创建新的虚拟寄存器
index_vreg = getNewVReg();
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(index_vreg));
li->addOperand(std::make_unique<ImmOperand>(const_index->getInt()));
CurMBB->addInstruction(std::move(li));
} else {
// 对于动态索引,使用已存在的虚拟寄存器
index_vreg = getVReg(indexValue);
}
// 优化如果步长是1可以直接移动(MV)作为偏移量,无需乘法
@ -1417,7 +1509,7 @@ std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicB
// 依次添加所有索引作为后续的操作数
for (auto index : gep->getIndices()) {
// [修复] 从 Use 对象中获取真正的 Value*
// 从 Use 对象中获取真正的 Value*
gep_node->operands.push_back(get_operand_node(index->getValue(), value_to_node, nodes_storage));
}
} else if (auto load = dynamic_cast<LoadInst*>(inst)) {
@ -1445,7 +1537,7 @@ std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicB
}
}
}
if (bin->getKind() >= Instruction::kFAdd) { // 假设浮点指令枚举值更大
if (bin->isFPBinary()) { // 假设浮点指令枚举值更大
auto fbin_node = create_node(DAGNode::FBINARY, bin, value_to_node, nodes_storage);
fbin_node->operands.push_back(get_operand_node(bin->getLhs(), value_to_node, nodes_storage));
fbin_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
@ -1521,7 +1613,7 @@ unsigned RISCv64ISel::getTypeSizeInBytes(Type* type) {
}
}
// [新] 打印DAG图以供调试的辅助函数
// 打印DAG图以供调试的辅助函数
void RISCv64ISel::print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, const std::string& bb_name) {
// 检查是否有DEBUG宏或者全局变量避免在非调试模式下打印
// if (!DEBUG) return;
@ -1617,4 +1709,8 @@ void RISCv64ISel::print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, co
std::cerr << "======================================\n\n";
}
unsigned int RISCv64ISel::getVRegCounter() const {
return vreg_counter;
}
} // namespace sysy

View File

@ -1,6 +1,122 @@
#include "RISCv64LLIR.h"
#include <vector>
#include <iostream> // 用于 std::ostream 和 std::cerr
#include <string> // 用于 std::string
namespace sysy {
}
// 辅助函数:将 PhysicalReg 枚举转换为可读的字符串
std::string regToString(PhysicalReg reg) {
switch (reg) {
case PhysicalReg::ZERO: return "x0"; case PhysicalReg::RA: return "ra";
case PhysicalReg::SP: return "sp"; case PhysicalReg::GP: return "gp";
case PhysicalReg::TP: return "tp"; case PhysicalReg::T0: return "t0";
case PhysicalReg::T1: return "t1"; case PhysicalReg::T2: return "t2";
case PhysicalReg::S0: return "s0"; case PhysicalReg::S1: return "s1";
case PhysicalReg::A0: return "a0"; case PhysicalReg::A1: return "a1";
case PhysicalReg::A2: return "a2"; case PhysicalReg::A3: return "a3";
case PhysicalReg::A4: return "a4"; case PhysicalReg::A5: return "a5";
case PhysicalReg::A6: return "a6"; case PhysicalReg::A7: return "a7";
case PhysicalReg::S2: return "s2"; case PhysicalReg::S3: return "s3";
case PhysicalReg::S4: return "s4"; case PhysicalReg::S5: return "s5";
case PhysicalReg::S6: return "s6"; case PhysicalReg::S7: return "s7";
case PhysicalReg::S8: return "s8"; case PhysicalReg::S9: return "s9";
case PhysicalReg::S10: return "s10"; case PhysicalReg::S11: return "s11";
case PhysicalReg::T3: return "t3"; case PhysicalReg::T4: return "t4";
case PhysicalReg::T5: return "t5"; case PhysicalReg::T6: return "t6";
case PhysicalReg::F0: return "f0"; case PhysicalReg::F1: return "f1";
case PhysicalReg::F2: return "f2"; case PhysicalReg::F3: return "f3";
case PhysicalReg::F4: return "f4"; case PhysicalReg::F5: return "f5";
case PhysicalReg::F6: return "f6"; case PhysicalReg::F7: return "f7";
case PhysicalReg::F8: return "f8"; case PhysicalReg::F9: return "f9";
case PhysicalReg::F10: return "f10"; case PhysicalReg::F11: return "f11";
case PhysicalReg::F12: return "f12"; case PhysicalReg::F13: return "f13";
case PhysicalReg::F14: return "f14"; case PhysicalReg::F15: return "f15";
case PhysicalReg::F16: return "f16"; case PhysicalReg::F17: return "f17";
case PhysicalReg::F18: return "f18"; case PhysicalReg::F19: return "f19";
case PhysicalReg::F20: return "f20"; case PhysicalReg::F21: return "f21";
case PhysicalReg::F22: return "f22"; case PhysicalReg::F23: return "f23";
case PhysicalReg::F24: return "f24"; case PhysicalReg::F25: return "f25";
case PhysicalReg::F26: return "f26"; case PhysicalReg::F27: return "f27";
case PhysicalReg::F28: return "f28"; case PhysicalReg::F29: return "f29";
case PhysicalReg::F30: return "f30"; case PhysicalReg::F31: return "f31";
default: return "UNKNOWN_REG";
}
}
// 打印栈帧信息的完整实现
void MachineFunction::dumpStackFrameInfo(std::ostream& os) const {
const StackFrameInfo& info = frame_info;
os << "--- Stack Frame Info for function '" << getName() << "' ---\n";
// 打印尺寸信息
os << " Sizes:\n";
os << " Total Size: " << info.total_size << " bytes\n";
os << " Locals Size: " << info.locals_size << " bytes\n";
os << " Spill Size: " << info.spill_size << " bytes\n";
os << " Callee-Saved Size: " << info.callee_saved_size << " bytes\n";
os << "\n";
// 打印 Alloca 变量的偏移量
os << " Alloca Offsets (vreg -> offset from FP):\n";
if (info.alloca_offsets.empty()) {
os << " (None)\n";
} else {
for (const auto& pair : info.alloca_offsets) {
os << " %vreg" << pair.first << " -> " << pair.second << "\n";
}
}
os << "\n";
// 打印溢出变量的偏移量
os << " Spill Offsets (vreg -> offset from FP):\n";
if (info.spill_offsets.empty()) {
os << " (None)\n";
} else {
for (const auto& pair : info.spill_offsets) {
os << " %vreg" << pair.first << " -> " << pair.second << "\n";
}
}
os << "\n";
// 打印使用的被调用者保存寄存器
os << " Used Callee-Saved Registers:\n";
if (info.used_callee_saved_regs.empty()) {
os << " (None)\n";
} else {
os << " { ";
for (const auto& reg : info.used_callee_saved_regs) {
os << regToString(reg) << " ";
}
os << "}\n";
}
os << "\n";
// 打印需要保存/恢复的被调用者保存寄存器 (有序)
os << " Callee-Saved Registers to Store/Restore:\n";
if (info.callee_saved_regs_to_store.empty()) {
os << " (None)\n";
} else {
os << " [ ";
for (const auto& reg : info.callee_saved_regs_to_store) {
os << regToString(reg) << " ";
}
os << "]\n";
}
os << "\n";
// 打印最终的寄存器分配结果
os << " Final Register Allocation Map (vreg -> preg):\n";
if (info.vreg_to_preg_map.empty()) {
os << " (None)\n";
} else {
for (const auto& pair : info.vreg_to_preg_map) {
os << " %vreg" << pair.first << " -> " << regToString(pair.second) << "\n";
}
}
os << "---------------------------------------------------\n";
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,20 @@
#ifndef ELIMINATE_FRAME_INDICES_H
#define ELIMINATE_FRAME_INDICES_H
#include "RISCv64LLIR.h"
namespace sysy {
class EliminateFrameIndicesPass {
public:
// Pass 的主入口函数
void runOnMachineFunction(MachineFunction* mfunc);
private:
// 帮助计算类型大小的辅助函数从原RegAlloc中移出
unsigned getTypeSizeInBytes(Type* type);
};
} // namespace sysy
#endif // ELIMINATE_FRAME_INDICES_H

View File

@ -0,0 +1,30 @@
#ifndef RISCV64_DIV_STRENGTH_REDUCTION_H
#define RISCV64_DIV_STRENGTH_REDUCTION_H
#include "RISCv64LLIR.h"
#include "Pass.h"
namespace sysy {
/**
* @class DivStrengthReduction
* @brief 除法强度削弱优化器
* * 将除法运算转换为乘法运算使用magic number算法
* 适用于除数为常数的情况,可以显著提高性能
*/
class DivStrengthReduction : public Pass {
public:
static char ID;
DivStrengthReduction() : Pass("div-strength-reduction", Granularity::Function, PassKind::Optimization) {}
void *getPassID() const override { return &ID; }
bool runOnFunction(Function *F, AnalysisManager& AM) override;
void runOnMachineFunction(MachineFunction* mfunc);
};
} // namespace sysy
#endif // RISCV64_DIV_STRENGTH_REDUCTION_H

View File

@ -20,6 +20,8 @@ public:
void setStream(std::ostream& os) { OS = &os; }
// 辅助函数
std::string regToString(PhysicalReg reg);
std::string formatInstr(const MachineInstr *instr);
private:
// 打印各个部分
void printBasicBlock(MachineBasicBlock* mbb, bool debug = false);

View File

@ -22,6 +22,9 @@ private:
// 函数级代码生成 (实现新的流水线)
std::string function_gen(Function* func);
// 私有辅助函数,用于根据类型计算其占用的字节数。
unsigned getTypeSizeInBytes(Type* type);
Module* module;
};

View File

@ -3,6 +3,12 @@
#include "RISCv64LLIR.h"
// Forward declarations
namespace sysy {
class GlobalValue;
class Value;
}
extern int DEBUG;
extern int DEEPDEBUG;
@ -17,7 +23,8 @@ public:
// 公开接口以便后续模块如RegAlloc可以查询或创建vreg
unsigned getVReg(Value* val);
unsigned getNewVReg() { return vreg_counter++; }
unsigned getNewVReg(Type* type);
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; }

View File

@ -3,6 +3,7 @@
#include "IR.h" // 确保包含了您自己的IR头文件
#include <string>
#include <iostream>
#include <vector>
#include <memory>
#include <cstdint>
@ -38,14 +39,14 @@ enum class PhysicalReg {
// 用于内部表示物理寄存器在干扰图中的节点ID一个简单的特殊ID确保不与vreg_counter冲突
// 假设 vreg_counter 不会达到这么大的值
PHYS_REG_START_ID = 100000,
PHYS_REG_START_ID = 1000000,
PHYS_REG_END_ID = PHYS_REG_START_ID + 320, // 预留足够的空间
};
// RISC-V 指令操作码枚举
enum class RVOpcodes {
// 算术指令
ADD, ADDI, ADDW, ADDIW, SUB, SUBW, MUL, MULW, DIV, DIVW, REM, REMW,
ADD, ADDI, ADDW, ADDIW, SUB, SUBW, MUL, MULW, MULH, DIV, DIVW, REM, REMW,
// 逻辑指令
XOR, XORI, OR, ORI, AND, ANDI,
// 移位指令
@ -92,7 +93,7 @@ enum class RVOpcodes {
FMV_X_W, // fmv.x.w rd, rs1 (浮点寄存器位模式 -> 整数寄存器)
FNEG_S, // fneg.s rd, rs (浮点取负)
// 新增伪指令,用于解耦栈帧处理
// 伪指令
FRAME_LOAD_W, // 从栈帧加载 32位 Word (对应 lw)
FRAME_LOAD_D, // 从栈帧加载 64位 Doubleword (对应 ld)
FRAME_STORE_W, // 保存 32位 Word 到栈帧 (对应 sw)
@ -100,6 +101,7 @@ enum class RVOpcodes {
FRAME_LOAD_F, // 从栈帧加载单精度浮点数
FRAME_STORE_F, // 将单精度浮点数存入栈帧
FRAME_ADDR, // 获取栈帧变量的地址
PSEUDO_KEEPALIVE, // 保持寄存器活跃,防止优化器删除
};
inline bool isGPR(PhysicalReg reg) {
@ -194,6 +196,11 @@ public:
preg = new_preg;
is_virtual = false;
}
void setVRegNum(unsigned new_vreg_num) {
vreg_num = new_vreg_num;
is_virtual = true; // 确保设置vreg时操作数状态正确
}
private:
unsigned vreg_num = 0;
PhysicalReg preg = PhysicalReg::ZERO;
@ -273,13 +280,15 @@ private:
// 栈帧信息
struct StackFrameInfo {
int locals_size = 0; // 仅为AllocaInst分配的大小
int locals_end_offset = 0; // 记录局部变量分配结束后的偏移量(相对于s0为负)
int spill_size = 0; // 仅为溢出分配的大小
int total_size = 0; // 总大小
int callee_saved_size = 0; // 保存寄存器的大小
std::map<unsigned, int> alloca_offsets; // <AllocaInst的vreg, 栈偏移>
std::map<unsigned, int> spill_offsets; // <溢出vreg, 栈偏移>
std::set<PhysicalReg> used_callee_saved_regs; // 使用的保存寄存器
std::map<unsigned, PhysicalReg> vreg_to_preg_map;
std::map<unsigned, PhysicalReg> vreg_to_preg_map; // RegAlloc最终的分配结果
std::vector<PhysicalReg> callee_saved_regs_to_store; // 已排序的、需要存取的被调用者保存寄存器
};
// 机器函数
@ -293,7 +302,7 @@ public:
StackFrameInfo& getFrameInfo() { return frame_info; }
const std::vector<std::unique_ptr<MachineBasicBlock>>& getBlocks() const { return blocks; }
std::vector<std::unique_ptr<MachineBasicBlock>>& getBlocks() { return blocks; }
void dumpStackFrameInfo(std::ostream& os = std::cerr) const;
void addBlock(std::unique_ptr<MachineBasicBlock> block) {
blocks.push_back(std::move(block));
}

View File

@ -8,7 +8,10 @@
#include "CalleeSavedHandler.h"
#include "LegalizeImmediates.h"
#include "PrologueEpilogueInsertion.h"
#include "EliminateFrameIndices.h"
#include "Pass.h"
#include "DivStrengthReduction.h"
namespace sysy {

View File

@ -3,9 +3,15 @@
#include "RISCv64LLIR.h"
#include "RISCv64ISel.h" // 包含 RISCv64ISel.h 以访问 ISel 和 Value 类型
#include <set>
#include <vector>
#include <map>
#include <stack>
extern int DEBUG;
extern int DEEPDEBUG;
extern int DEBUGLENGTH; // 用于限制调试输出的长度
extern int DEEPERDEBUG; // 用于更深层次的调试输出
namespace sysy {
@ -17,58 +23,98 @@ public:
void run();
private:
using LiveSet = std::set<unsigned>; // 活跃虚拟寄存器集合
using InterferenceGraph = std::map<unsigned, std::set<unsigned>>;
// 类型定义与Python版本对应
using VRegSet = std::set<unsigned>;
using InterferenceGraph = std::map<unsigned, VRegSet>;
using VRegStack = std::vector<unsigned>; // 使用vector模拟栈方便遍历
using MoveList = std::map<unsigned, std::set<const MachineInstr*>>;
using AliasMap = std::map<unsigned, unsigned>;
using ColorMap = std::map<unsigned, PhysicalReg>;
using VRegMoveSet = std::set<const MachineInstr*>;
// 栈帧管理
void eliminateFrameIndices();
// 活跃性分析
// --- 核心算法流程 ---
void initialize();
void build();
void makeWorklist();
void simplify();
void coalesce();
void freeze();
void selectSpill();
void assignColors();
void rewriteProgram();
bool doAllocation();
void applyColoring();
void dumpState(const std::string &stage);
void precolorByCallingConvention();
// --- 辅助函数 ---
void getInstrUseDef(const MachineInstr* instr, VRegSet& use, VRegSet& def);
void getInstrUseDef_Liveness(const MachineInstr *instr, VRegSet &use, VRegSet &def);
void addEdge(unsigned u, unsigned v);
VRegSet adjacent(unsigned n);
VRegMoveSet nodeMoves(unsigned n);
bool moveRelated(unsigned n);
void decrementDegree(unsigned m);
void enableMoves(const VRegSet& nodes);
unsigned getAlias(unsigned n);
void addWorklist(unsigned u);
bool briggsHeuristic(unsigned u, unsigned v);
bool georgeHeuristic(unsigned u, unsigned v);
void combine(unsigned u, unsigned v);
void freezeMoves(unsigned u);
void collectUsedCalleeSavedRegs();
bool isFPVReg(unsigned vreg) const;
std::string regToString(PhysicalReg reg);
std::string regIdToString(unsigned id);
// --- 活跃性分析 ---
void analyzeLiveness();
// 构建干扰图
void buildInterferenceGraph();
// 图着色分配寄存器
void colorGraph();
// 重写函数替换vreg并插入溢出代码
void rewriteFunction();
// 辅助函数获取指令的Use/Def集合
void getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def);
// 辅助函数,处理调用约定
void handleCallingConvention();
MachineFunction* MFunc;
// 活跃性分析结果
std::map<const MachineInstr*, LiveSet> live_in_map;
std::map<const MachineInstr*, LiveSet> live_out_map;
RISCv64ISel* ISel;
// 干扰图
InterferenceGraph interference_graph;
// 图着色结果
std::map<unsigned, PhysicalReg> color_map; // vreg -> preg
std::set<unsigned> spilled_vregs; // 被溢出的vreg集合
// 可用的物理寄存器池
// --- 算法数据结构 ---
// 寄存器池
std::vector<PhysicalReg> allocable_int_regs;
std::vector<PhysicalReg> allocable_fp_regs;
int K_int; // 整数寄存器数量
int K_fp; // 浮点寄存器数量
// 存储vreg到IR Value*的反向映射
// 这个map将在run()函数开始时被填充并在rewriteFunction()中使用。
std::map<unsigned, Value*> vreg_to_value_map;
std::map<PhysicalReg, unsigned> preg_to_vreg_id_map; // 物理寄存器到特殊vreg ID的映射
// 用于计算类型大小的辅助函数
unsigned getTypeSizeInBytes(Type* type);
// 节点集合
VRegSet precolored; // 预着色的节点 (物理寄存器)
VRegSet initial; // 初始的、所有待处理的虚拟寄存器节点
VRegSet simplifyWorklist;
VRegSet freezeWorklist;
VRegSet spillWorklist;
VRegSet spilledNodes;
VRegSet coalescedNodes;
VRegSet coloredNodes;
VRegStack selectStack;
// 辅助函数,用于打印集合
static void printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os);
// Move指令相关
std::set<const MachineInstr*> coalescedMoves;
std::set<const MachineInstr*> constrainedMoves;
std::set<const MachineInstr*> frozenMoves;
std::set<const MachineInstr*> worklistMoves;
std::set<const MachineInstr*> activeMoves;
// 数据结构
InterferenceGraph adjSet;
std::map<unsigned, VRegSet> adjList; // 邻接表
std::map<unsigned, int> degree;
MoveList moveList;
AliasMap alias;
ColorMap color_map;
// 活跃性分析结果
std::map<const MachineInstr*, VRegSet> live_in_map;
std::map<const MachineInstr*, VRegSet> live_out_map;
// VReg -> Value* 和 VReg -> Type* 的映射
const std::map<unsigned, Value*>& vreg_to_value_map;
const std::map<unsigned, Type*>& vreg_type_map;
};
} // namespace sysy

View File

@ -20,6 +20,10 @@
#include <algorithm>
namespace sysy {
// Global cleanup function to release all statically allocated IR objects
void cleanupIRPools();
/**
* \defgroup type Types
* @brief Sysy的类型系统
@ -83,6 +87,7 @@ class Type {
auto as() const -> std::enable_if_t<std::is_base_of_v<Type, T>, T *> {
return dynamic_cast<T *>(const_cast<Type *>(this));
}
virtual void print(std::ostream& os) const;
};
class PointerType : public Type {
@ -94,6 +99,9 @@ class PointerType : public Type {
public:
static PointerType* get(Type *baseType); ///< 获取指向baseType的Pointer类型
// Cleanup method to release all cached pointer types (call at program exit)
static void cleanup();
public:
Type* getBaseType() const { return baseType; } ///< 获取指向的类型
@ -111,6 +119,9 @@ class FunctionType : public Type {
public:
/// 获取返回值类型为returnType 形参类型列表为paramTypes的Function类型
static FunctionType* get(Type *returnType, const std::vector<Type *> &paramTypes = {});
// Cleanup method to release all cached function types (call at program exit)
static void cleanup();
public:
Type* getReturnType() const { return returnType; } ///< 获取返回值类信息
@ -123,6 +134,9 @@ class ArrayType : public Type {
// elements数组的元素类型 (例如int[3] 的 elementType 是 int)
// numElements该维度的大小 (例如int[3] 的 numElements 是 3)
static ArrayType *get(Type *elementType, unsigned numElements);
// Cleanup method to release all cached array types (call at program exit)
static void cleanup();
Type *getElementType() const { return elementType; }
unsigned getNumElements() const { return numElements; }
@ -202,9 +216,11 @@ class Use {
public:
unsigned getIndex() const { return index; } ///< 返回value在User操作数中的位置
void setIndex(int newIndex) { index = newIndex; } ///< 设置value在User操作数中的位置
User* getUser() const { return user; } ///< 返回使用者
Value* getValue() const { return value; } ///< 返回被使用的值
void setValue(Value *newValue) { value = newValue; } ///< 将被使用的值设置为newValue
void print(std::ostream& os) const;
};
//! The base class of all value types
@ -229,7 +245,15 @@ class Value {
std::list<std::shared_ptr<Use>>& getUses() { return uses; } ///< 获取使用关系列表
void addUse(const std::shared_ptr<Use> &use) { uses.push_back(use); } ///< 添加使用关系
void replaceAllUsesWith(Value *value); ///< 将原来使用该value的使用者全变为使用给定参数value并修改相应use关系
void removeUse(const std::shared_ptr<Use> &use) { uses.remove(use); } ///< 删除使用关系use
void removeUse(const std::shared_ptr<Use> &use) {
assert(use != nullptr && "Use cannot be null");
assert(use->getValue() == this && "Use being removed does NOT point to this Value!");
auto it = std::find(uses.begin(), uses.end(), use);
assert(it != uses.end() && "Use not found in Value's uses");
uses.remove(use);
} ///< 删除使用关系use
void removeAllUses();
virtual void print(std::ostream& os) const = 0; ///< 输出值信息到输出流
};
/**
@ -356,6 +380,9 @@ public:
// Static factory method to get a canonical ConstantValue from the pool
static ConstantValue* get(Type* type, ConstantValVariant val);
// Cleanup method to release all cached constants (call at program exit)
static void cleanup();
// Helper methods to access constant values with appropriate casting
int getInt() const {
@ -394,6 +421,7 @@ public:
virtual bool isZero() const = 0;
virtual bool isOne() const = 0;
void print(std::ostream& os) const = 0;
};
class ConstantInteger : public ConstantValue {
@ -420,6 +448,7 @@ public:
bool isZero() const override { return constVal == 0; }
bool isOne() const override { return constVal == 1; }
void print(std::ostream& os) const;
};
class ConstantFloating : public ConstantValue {
@ -446,6 +475,7 @@ public:
bool isZero() const override { return constFVal == 0.0f; }
bool isOne() const override { return constFVal == 1.0f; }
void print(std::ostream& os) const;
};
class UndefinedValue : public ConstantValue {
@ -460,6 +490,9 @@ protected:
public:
static UndefinedValue* get(Type* type);
// Cleanup method to release all cached undefined values (call at program exit)
static void cleanup();
size_t hash() const override {
return std::hash<Type*>{}(getType());
@ -477,6 +510,7 @@ public:
bool isZero() const override { return false; }
bool isOne() const override { return false; }
void print(std::ostream& os) const;
};
// --- End of refactored ConstantValue and related classes ---
@ -514,12 +548,15 @@ public:
explicit BasicBlock(Function *parent, const std::string &name = "")
: Value(Type::getLabelType(), name), parent(parent) {}
~BasicBlock() override {
for (auto pre : predecessors) {
pre->removeSuccessor(this);
}
for (auto suc : successors) {
suc->removePredecessor(this);
}
// for (auto pre : predecessors) {
// pre->removeSuccessor(this);
// }
// for (auto suc : successors) {
// suc->removePredecessor(this);
// }
// 这些关系应该在 BasicBlock 被从 Function 中移除时,
// 由负责 CFG 优化的 Pass (例如 SCCP 的 RemoveDeadBlock) 显式地清理。
// 析构函数只负责清理 BasicBlock 自身拥有的资源(例如,指令列表)。
}
public:
@ -573,7 +610,9 @@ public:
if (iter != predecessors.end()) {
predecessors.erase(iter);
} else {
assert(false);
// 如果没有找到前驱块,可能是因为它已经被移除或不存在
// 这可能是一个错误情况或者是因为在CFG优化过程中已经处理
// assert(false && "Predecessor block not found in BasicBlock");
}
}
void removeSuccessor(BasicBlock *block) {
@ -581,7 +620,9 @@ public:
if (iter != successors.end()) {
successors.erase(iter);
} else {
assert(false);
// 如果没有找到后继块,可能是因为它已经被移除或不存在
// 这可能是一个错误情况或者是因为在CFG优化过程中已经处理
// assert(false && "Successor block not found in BasicBlock");
}
}
void replacePredecessor(BasicBlock *oldBlock, BasicBlock *newBlock) {
@ -599,7 +640,7 @@ public:
prev->addSuccessor(next);
next->addPredecessor(prev);
}
void removeInst(iterator pos) { instructions.erase(pos); }
iterator removeInst(iterator pos) { return instructions.erase(pos); }
void removeInst(Instruction *inst) {
auto pos = std::find_if(instructions.begin(), instructions.end(),
[inst](const std::unique_ptr<Instruction> &i) { return i.get() == inst; });
@ -610,6 +651,11 @@ public:
}
} ///< 移除指定位置的指令
iterator moveInst(iterator sourcePos, iterator targetPos, BasicBlock *block);
/// 清理基本块中的所有使用关系
void cleanup();
void print(std::ostream& os) const;
};
//! User is the abstract base type of `Value` types which use other `Value` as
@ -635,11 +681,7 @@ class User : public Value {
operands.emplace_back(std::make_shared<Use>(operands.size(), this, value));
value->addUse(operands.back());
} ///< 增加操作数
void removeOperand(unsigned index) {
auto value = getOperand(index);
value->removeUse(operands[index]);
operands.erase(operands.begin() + index);
} ///< 移除操作数
void removeOperand(unsigned index);
template <typename ContainerT>
void addOperands(const ContainerT &newoperands) {
for (auto value : newoperands) {
@ -648,6 +690,9 @@ class User : public Value {
} ///< 增加多个操作数
void replaceOperand(unsigned index, Value *value); ///< 替换操作数
void setOperand(unsigned index, Value *value); ///< 设置操作数
/// 清理用户的所有操作数使用关系
void cleanup();
};
/*!
@ -682,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,
@ -695,19 +741,21 @@ class Instruction : public User {
kCondBr = 0x1UL << 30,
kBr = 0x1UL << 31,
kReturn = 0x1UL << 32,
kUnreachable = 0x1UL << 33,
// mem op
kAlloca = 0x1UL << 33,
kLoad = 0x1UL << 34,
kStore = 0x1UL << 35,
kGetElementPtr = 0x1UL << 36,
kMemset = 0x1UL << 37,
// kGetSubArray = 0x1UL << 38,
// Constant Kind removed as Constants are now Values, not Instructions.
// kConstant = 0x1UL << 37, // Conflicts with kMemset if kept as is
kAlloca = 0x1UL << 34,
kLoad = 0x1UL << 35,
kStore = 0x1UL << 36,
kGetElementPtr = 0x1UL << 37,
kMemset = 0x1UL << 38,
// phi
kPhi = 0x1UL << 39,
kBitItoF = 0x1UL << 40,
kBitFtoI = 0x1UL << 41,
kSrl = 0x1UL << 42, // 逻辑右移
kSll = 0x1UL << 43, // 逻辑左移
kSra = 0x1UL << 44, // 算术右移
kMulh = 0x1UL << 45
};
protected:
@ -725,57 +773,57 @@ public:
std::string getKindString() const{
switch (kind) {
case kInvalid:
return "Invalid";
return "invalid";
case kAdd:
return "Add";
return "add";
case kSub:
return "Sub";
return "sub";
case kMul:
return "Mul";
return "mul";
case kDiv:
return "Div";
return "sdiv";
case kRem:
return "Rem";
return "srem";
case kICmpEQ:
return "ICmpEQ";
return "icmp eq";
case kICmpNE:
return "ICmpNE";
return "icmp ne";
case kICmpLT:
return "ICmpLT";
return "icmp slt";
case kICmpGT:
return "ICmpGT";
return "icmp sgt";
case kICmpLE:
return "ICmpLE";
return "icmp sle";
case kICmpGE:
return "ICmpGE";
return "icmp sge";
case kFAdd:
return "FAdd";
return "fadd";
case kFSub:
return "FSub";
return "fsub";
case kFMul:
return "FMul";
return "fmul";
case kFDiv:
return "FDiv";
return "fdiv";
case kFCmpEQ:
return "FCmpEQ";
return "fcmp oeq";
case kFCmpNE:
return "FCmpNE";
return "fcmp one";
case kFCmpLT:
return "FCmpLT";
return "fcmp olt";
case kFCmpGT:
return "FCmpGT";
return "fcmp ogt";
case kFCmpLE:
return "FCmpLE";
return "fcmp ole";
case kFCmpGE:
return "FCmpGE";
return "fcmp oge";
case kAnd:
return "And";
return "and";
case kOr:
return "Or";
return "or";
case kNeg:
return "Neg";
return "neg";
case kNot:
return "Not";
return "not";
case kFNeg:
return "FNeg";
case kFNot:
@ -783,27 +831,41 @@ public:
case kFtoI:
return "FtoI";
case kItoF:
return "IToF";
return "iToF";
case kCall:
return "Call";
return "call";
case kCondBr:
return "CondBr";
return "condBr";
case kBr:
return "Br";
return "br";
case kReturn:
return "Return";
return "return";
case kUnreachable:
return "unreachable";
case kAlloca:
return "Alloca";
return "alloca";
case kLoad:
return "Load";
return "load";
case kStore:
return "Store";
return "store";
case kGetElementPtr:
return "GetElementPtr";
return "getElementPtr";
case kMemset:
return "Memset";
return "memset";
case kPhi:
return "Phi";
return "phi";
case kBitItoF:
return "BitItoF";
case kBitFtoI:
return "BitFtoI";
case kSrl:
return "lshr";
case kSll:
return "shl";
case kSra:
return "ashr";
case kMulh:
return "mulh";
default:
return "Unknown";
}
@ -815,11 +877,15 @@ public:
bool isBinary() const {
static constexpr uint64_t BinaryOpMask =
(kAdd | kSub | kMul | kDiv | kRem | kAnd | kOr) |
(kICmpEQ | kICmpNE | kICmpLT | kICmpGT | kICmpLE | kICmpGE) |
(kAdd | kSub | kMul | kDiv | kRem | kAnd | kOr | kSra | kSrl | kSll | kMulh) |
(kICmpEQ | kICmpNE | kICmpLT | kICmpGT | kICmpLE | kICmpGE);
return kind & BinaryOpMask;
}
bool isFPBinary() const {
static constexpr uint64_t FPBinaryOpMask =
(kFAdd | kFSub | kFMul | kFDiv) |
(kFCmpEQ | kFCmpNE | kFCmpLT | kFCmpGT | kFCmpLE | kFCmpGE);
return kind & BinaryOpMask;
return kind & FPBinaryOpMask;
}
bool isUnary() const {
static constexpr uint64_t UnaryOpMask =
@ -832,7 +898,7 @@ public:
return kind & MemoryOpMask;
}
bool isTerminator() const {
static constexpr uint64_t TerminatorOpMask = kCondBr | kBr | kReturn;
static constexpr uint64_t TerminatorOpMask = kCondBr | kBr | kReturn | kUnreachable;
return kind & TerminatorOpMask;
}
bool isCmp() const {
@ -852,6 +918,7 @@ public:
}
bool isUnconditional() const { return kind == kBr; }
bool isConditional() const { return kind == kCondBr; }
bool isCondBr() const { return kind == kCondBr; }
bool isPhi() const { return kind == kPhi; }
bool isAlloca() const { return kind == kAlloca; }
bool isLoad() const { return kind == kLoad; }
@ -860,10 +927,15 @@ public:
bool isMemset() const { return kind == kMemset; }
bool isCall() const { return kind == kCall; }
bool isReturn() const { return kind == kReturn; }
bool isUnreachable() const { return kind == kUnreachable; }
bool isDefine() const {
static constexpr uint64_t DefineOpMask = kAlloca | kStore | kPhi;
return (kind & DefineOpMask) != 0U;
}
virtual ~Instruction() = default;
virtual void print(std::ostream& os) const = 0;
}; // class Instruction
class Function;
@ -885,38 +957,62 @@ class PhiInst : public Instruction {
const std::string &name = "")
: Instruction(Kind::kPhi, type, parent, name), vsize(rhs.size()) {
assert(rhs.size() == Blocks.size() && "PhiInst: rhs and Blocks must have the same size");
for(size_t i = 0; i < rhs.size(); ++i) {
for(size_t i = 0; i < vsize; ++i) {
addOperand(rhs[i]);
addOperand(Blocks[i]);
blk2val[Blocks[i]] = rhs[i];
}
}
public:
Value* getValue(unsigned k) const {return getOperand(2 * k);} ///< 获取位置为k的值
BasicBlock* getBlock(unsigned k) const {return dynamic_cast<BasicBlock*>(getOperand(2 * k + 1));}
auto& getincomings() const {return blk2val;} ///< 获取所有的基本块和对应的值
Value* getvalfromBlk(BasicBlock* blk);
BasicBlock* getBlkfromVal(Value* val);
unsigned getNumIncomingValues() const { return vsize; } ///< 获取传入值的数量
Value *getIncomingValue(unsigned Idx) const { return getOperand(Idx * 2); } ///< 获取指定位置的传入值
BasicBlock *getIncomingBlock(unsigned Idx) const {return dynamic_cast<BasicBlock *>(getOperand(Idx * 2 + 1)); } ///< 获取指定位置的传入基本块
Value* getValfromBlk(BasicBlock* block);
BasicBlock* getBlkfromVal(Value* value);
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 must not be null");
assert(value && block && "PhiInst: value and block cannot be null");
addOperand(value);
addOperand(block);
blk2val[block] = value;
vsize++;
} ///< 添加传入值和对应的基本块
void delValue(Value* val);
void delBlk(BasicBlock* blk);
void replaceBlk(BasicBlock* newBlk, unsigned k);
void replaceold2new(BasicBlock* oldBlk, BasicBlock* newBlk);
void refreshB2VMap();
void removeIncoming(unsigned Idx) {
assert(Idx < vsize && "PhiInst: Index out of bounds");
auto blk = getIncomingBlock(Idx);
removeOperand(Idx * 2 + 1); // Remove block
removeOperand(Idx * 2); // Remove value
blk2val.erase(blk);
vsize--;
} ///< 移除指定位置的传入值和对应的基本块
// 移除指定的传入值或基本块
void removeIncomingValue(Value *value);
void removeIncomingBlock(BasicBlock *block);
// 设置指定位置的传入值或基本块
void setIncomingValue(unsigned Idx, Value *value);
void setIncomingBlock(unsigned Idx, BasicBlock *block);
// 替换指定位置的传入值或基本块(原理是删除再添加)保留旧块或者旧值
void replaceIncomingValue(Value *oldValue, Value *newValue);
void replaceIncomingBlock(BasicBlock *oldBlock, BasicBlock *newBlock);
// 替换指定位置的传入值或基本块(原理是删除再添加)
void replaceIncomingValue(Value *oldValue, Value *newValue, BasicBlock *newBlock);
void replaceIncomingBlock(BasicBlock *oldBlock, BasicBlock *newBlock, Value *newValue);
void refreshMap() {
blk2val.clear();
for (unsigned i = 0; i < vsize; ++i) {
blk2val[getIncomingBlock(i)] = getIncomingValue(i);
}
} ///< 刷新块到值的映射关系
auto getValues() { return make_range(std::next(operand_begin()), operand_end()); }
void print(std::ostream& os) const override;
};
@ -925,16 +1021,14 @@ class CallInst : public Instruction {
friend class IRBuilder;
protected:
CallInst(Function *callee, const std::vector<Value *> &args = {},
BasicBlock *parent = nullptr, const std::string &name = "");
CallInst(Function *callee, const std::vector<Value *> &args, BasicBlock *parent = nullptr, const std::string &name = "");
public:
Function* getCallee() const;
Function *getCallee() const;
auto getArguments() const {
return make_range(std::next(operand_begin()), operand_end());
}
void print(std::ostream& os) const override;
}; // class CallInst
//! Unary instruction, includes '!', '-' and type conversion.
@ -952,7 +1046,7 @@ protected:
public:
Value* getOperand() const { return User::getOperand(0); }
void print(std::ostream& os) const override;
}; // class UnaryInst
//! Binary instruction, e.g., arithmatic, relation, logic, etc.
@ -1031,6 +1125,7 @@ public:
// 后端处理数组访存操作时需要创建计算地址的指令,需要在外部构造 BinaryInst 对象
return new BinaryInst(kind, type, lhs, rhs, parent, name);
}
void print(std::ostream& os) const override;
}; // class BinaryInst
//! The return statement
@ -1051,6 +1146,7 @@ class ReturnInst : public Instruction {
Value* getReturnValue() const {
return hasReturnValue() ? getOperand(0) : nullptr;
}
void print(std::ostream& os) const override;
};
//! Unconditional branch
@ -1059,12 +1155,10 @@ class UncondBrInst : public Instruction {
friend class Function;
protected:
UncondBrInst(BasicBlock *block, std::vector<Value *> args,
UncondBrInst(BasicBlock *block,
BasicBlock *parent = nullptr)
: Instruction(kBr, Type::getVoidType(), parent, "") {
// assert(block->getNumArguments() == args.size());
addOperand(block);
addOperands(args);
}
public:
@ -1072,7 +1166,17 @@ public:
auto getArguments() const {
return make_range(std::next(operand_begin()), operand_end());
}
std::vector<BasicBlock *> getSuccessors() const {
std::vector<BasicBlock *> succs;
// 假设无条件分支的目标块是它的第一个操作数
if (getNumOperands() > 0) {
if (auto target_bb = dynamic_cast<BasicBlock *>(getOperand(0))) {
succs.push_back(target_bb);
}
}
return succs;
}
void print(std::ostream& os) const override;
}; // class UncondBrInst
//! Conditional branch
@ -1083,17 +1187,12 @@ class CondBrInst : public Instruction {
friend class Function;
protected:
CondBrInst(Value *condition, BasicBlock *thenBlock, BasicBlock *elseBlock,
const std::vector<Value *> &thenArgs,
const std::vector<Value *> &elseArgs, BasicBlock *parent = nullptr)
CondBrInst(Value *condition, BasicBlock *thenBlock, BasicBlock *elseBlock,
BasicBlock *parent = nullptr)
: Instruction(kCondBr, Type::getVoidType(), parent, "") {
// assert(thenBlock->getNumArguments() == thenArgs.size() and
// elseBlock->getNumArguments() == elseArgs.size());
addOperand(condition);
addOperand(thenBlock);
addOperand(elseBlock);
addOperands(thenArgs);
addOperands(elseArgs);
}
public:
Value* getCondition() const { return getOperand(0); }
@ -1103,29 +1202,39 @@ public:
BasicBlock* getElseBlock() const {
return dynamic_cast<BasicBlock *>(getOperand(2));
}
// auto getThenArguments() const {
// auto begin = std::next(operand_begin(), 3);
// // auto end = std::next(begin, getThenBlock()->getNumArguments());
// return make_range(begin, end);
// }
// auto getElseArguments() const {
// auto begin =
// std::next(operand_begin(), 3 + getThenBlock()->getNumArguments());
// auto end = operand_end();
// return make_range(begin, end);
// }
std::vector<BasicBlock *> getSuccessors() const {
std::vector<BasicBlock *> succs;
// 假设条件分支的真实块是第二个操作数,假块是第三个操作数
// 操作数通常是:[0] 条件值, [1] TrueTargetBlock, [2] FalseTargetBlock
if (getNumOperands() > 2) {
if (auto true_bb = getThenBlock()) {
succs.push_back(true_bb);
}
if (auto false_bb = getElseBlock()) {
succs.push_back(false_bb);
}
}
return succs;
}
void print(std::ostream& os) const override;
}; // class CondBrInst
class UnreachableInst : public Instruction {
public:
// 构造函数:设置指令类型为 kUnreachable
explicit UnreachableInst(const std::string& name, BasicBlock *parent = nullptr)
: Instruction(kUnreachable, Type::getVoidType(), parent, "") {}
void print(std::ostream& os) const { os << "unreachable"; }
};
//! Allocate memory for stack variables, used for non-global variable declartion
class AllocaInst : public Instruction {
friend class IRBuilder;
friend class Function;
protected:
AllocaInst(Type *type, const std::vector<Value *> &dims = {},
AllocaInst(Type *type,
BasicBlock *parent = nullptr, const std::string &name = "")
: Instruction(kAlloca, type, parent, name) {
addOperands(dims);
}
public:
@ -1133,10 +1242,7 @@ public:
Type* getAllocatedType() const {
return getType()->as<PointerType>()->getBaseType();
} ///< 获取分配的类型
int getNumDims() const { return getNumOperands(); }
auto getDims() const { return getOperands(); }
Value* getDim(int index) { return getOperand(index); }
void print(std::ostream& os) const override;
}; // class AllocaInst
@ -1174,6 +1280,7 @@ public:
BasicBlock *parent = nullptr, const std::string &name = "") {
return new GetElementPtrInst(resultType, basePointer, indices, parent, name);
}
void print(std::ostream& os) const override;
};
//! Load a value from memory address specified by a pointer value
@ -1182,22 +1289,16 @@ class LoadInst : public Instruction {
friend class Function;
protected:
LoadInst(Value *pointer, const std::vector<Value *> &indices = {},
LoadInst(Value *pointer,
BasicBlock *parent = nullptr, const std::string &name = "")
: Instruction(kLoad, pointer->getType()->as<PointerType>()->getBaseType(),
parent, name) {
addOperand(pointer);
addOperands(indices);
}
public:
int getNumIndices() const { return getNumOperands() - 1; }
Value* getPointer() const { return getOperand(0); }
auto getIndices() const {
return make_range(std::next(operand_begin()), operand_end());
}
Value* getIndex(int index) const { return getOperand(index + 1); }
void print(std::ostream& os) const override;
}; // class LoadInst
//! Store a value to memory address specified by a pointer value
@ -1207,23 +1308,16 @@ class StoreInst : public Instruction {
protected:
StoreInst(Value *value, Value *pointer,
const std::vector<Value *> &indices = {},
BasicBlock *parent = nullptr, const std::string &name = "")
: Instruction(kStore, Type::getVoidType(), parent, name) {
addOperand(value);
addOperand(pointer);
addOperands(indices);
}
public:
int getNumIndices() const { return getNumOperands() - 2; }
Value* getValue() const { return getOperand(0); }
Value* getPointer() const { return getOperand(1); }
auto getIndices() const {
return make_range(std::next(operand_begin(), 2), operand_end());
}
Value* getIndex(int index) const { return getOperand(index + 2); }
void print(std::ostream& os) const override;
}; // class StoreInst
//! Memset instruction
@ -1253,7 +1347,7 @@ public:
Value* getBegin() const { return getOperand(1); }
Value* getSize() const { return getOperand(2); }
Value* getValue() const { return getOperand(3); }
void print(std::ostream& os) const override;
};
class GlobalValue;
@ -1271,6 +1365,11 @@ public:
public:
Function* getParent() const { return func; }
int getIndex() const { return index; }
/// 清理参数的使用关系
void cleanup();
void print(std::ostream& os) const;
};
@ -1336,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) {
@ -1348,6 +1458,11 @@ protected:
blocks.emplace_front(block);
return block;
}
/// 清理函数中的所有使用关系
void cleanup();
void print(std::ostream& os) const;
};
//! Global value declared at file scope
@ -1361,20 +1476,18 @@ protected:
protected:
GlobalValue(Module *parent, Type *type, const std::string &name,
const std::vector<Value *> &dims = {},
ValueCounter init = {})
: Value(type, name), parent(parent) {
assert(type->isPointer());
// addOperands(dims);
// 维度信息已经被记录到Type中dim只是为了方便初始化
numDims = dims.size();
numDims = 0;
if (init.size() == 0) {
unsigned num = 1;
for (unsigned i = 0; i < numDims; i++) {
// Assume dims elements are ConstantInteger and cast appropriately
auto dim_val = dynamic_cast<ConstantInteger*>(dims[i]);
assert(dim_val && "GlobalValue dims must be constant integers");
num *= dim_val->getInt();
auto arrayType = type->as<ArrayType>();
while (arrayType) {
numDims++;
num *= arrayType->getNumElements();
arrayType = arrayType->getElementType()->as<ArrayType>();
}
if (dynamic_cast<PointerType *>(type)->getBaseType() == Type::getFloatType()) {
init.push_back(ConstantFloating::get(0.0F), num); // Use new constant factory
@ -1386,9 +1499,6 @@ protected:
}
public:
// unsigned getNumDims() const { return numDims; } ///< 获取维度数量
// Value* getDim(unsigned index) const { return getOperand(index); } ///< 获取位置为index的维度
// auto getDims() const { return getOperands(); } ///< 获取维度列表
unsigned getNumIndices() const {
return numDims;
} ///< 获取维度数量
@ -1418,6 +1528,7 @@ public:
return getByIndex(index);
} ///< 通过多维索引indices获取初始值
const ValueCounter& getInitValues() const { return initValues; }
void print(std::ostream& os) const;
}; // class GlobalValue
@ -1430,13 +1541,19 @@ class ConstantVariable : public Value {
ValueCounter initValues; ///< 值
protected:
ConstantVariable(Module *parent, Type *type, const std::string &name, const ValueCounter &init,
const std::vector<Value *> &dims = {})
ConstantVariable(Module *parent, Type *type, const std::string &name, const ValueCounter &init)
: Value(type, name), parent(parent) {
assert(type->isPointer());
numDims = dims.size();
// numDims = dims.size();
numDims = 0;
if(type->as<PointerType>()->getBaseType()->isArray()) {
auto arrayType = type->as<ArrayType>();
while (arrayType) {
numDims++;
arrayType = arrayType->getElementType()->as<ArrayType>();
}
}
initValues = init;
// addOperands(dims); 同GlobalValue维度信息已经被记录到Type中dim只是为了方便初始化
}
public:
@ -1468,10 +1585,9 @@ class ConstantVariable : public Value {
return getByIndex(index);
} ///< 通过多维索引indices获取初始值
// unsigned getNumDims() const { return numDims; } ///< 获取维度数量
// Value* getDim(unsigned index) const { return getOperand(index); } ///< 获取位置为index的维度
// auto getDims() const { return getOperands(); } ///< 获取维度列表
const ValueCounter& getInitValues() const { return initValues; } ///< 获取初始值
void print(std::ostream& os) const;
void print_init(std::ostream& os) const;
};
using SymbolTableNode = struct SymbolTableNode {
@ -1494,6 +1610,8 @@ class SymbolTable {
Value* getVariable(const std::string &name) const; ///< 根据名字name以及当前作用域获取变量
Value* addVariable(const std::string &name, Value *variable); ///< 添加变量
void registerParameterName(const std::string &name); ///< 注册函数参数名字避免alloca重名
void addVariableDirectly(const std::string &name, Value *variable); ///< 直接添加变量到当前作用域,不重命名
std::vector<std::unique_ptr<GlobalValue>>& getGlobals(); ///< 获取全局变量列表
const std::vector<std::unique_ptr<ConstantVariable>>& getConsts() const; ///< 获取全局常量列表
void enterNewScope(); ///< 进入新的作用域
@ -1501,6 +1619,9 @@ class SymbolTable {
bool isInGlobalScope() const; ///< 是否位于全局作用域
void enterGlobalScope(); ///< 进入全局作用域
bool isCurNodeNull() { return curNode == nullptr; }
/// 清理符号表中的所有内容
void cleanup();
};
//! IR unit for representing a SysY compile unit
@ -1529,13 +1650,12 @@ class Module {
return result.first->second.get();
} ///< 创建外部函数
///< 变量创建伴随着符号表的更新
GlobalValue* createGlobalValue(const std::string &name, Type *type, const std::vector<Value *> &dims = {},
const ValueCounter &init = {}) {
GlobalValue* createGlobalValue(const std::string &name, Type *type, const ValueCounter &init = {}) {
bool isFinished = variableTable.isCurNodeNull();
if (isFinished) {
variableTable.enterGlobalScope();
}
auto result = variableTable.addVariable(name, new GlobalValue(this, type, name, dims, init));
auto result = variableTable.addVariable(name, new GlobalValue(this, type, name, init));
if (isFinished) {
variableTable.leaveScope();
}
@ -1544,9 +1664,8 @@ class Module {
}
return dynamic_cast<GlobalValue *>(result);
} ///< 创建全局变量
ConstantVariable* createConstVar(const std::string &name, Type *type, const ValueCounter &init,
const std::vector<Value *> &dims = {}) {
auto result = variableTable.addVariable(name, new ConstantVariable(this, type, name, init, dims));
ConstantVariable* createConstVar(const std::string &name, Type *type, const ValueCounter &init) {
auto result = variableTable.addVariable(name, new ConstantVariable(this, type, name, init));
if (result == nullptr) {
return nullptr;
}
@ -1555,6 +1674,12 @@ class Module {
void addVariable(const std::string &name, AllocaInst *variable) {
variableTable.addVariable(name, variable);
} ///< 添加变量
void addVariableDirectly(const std::string &name, AllocaInst *variable) {
variableTable.addVariableDirectly(name, variable);
} ///< 直接添加变量到当前作用域,不重命名
void registerParameterName(const std::string &name) {
variableTable.registerParameterName(name);
} ///< 注册函数参数名字避免alloca重名
Value* getVariable(const std::string &name) {
return variableTable.getVariable(name);
} ///< 根据名字name和当前作用域获取变量
@ -1567,7 +1692,7 @@ class Module {
} ///< 获取函数
Function* getExternalFunction(const std::string &name) const {
auto result = externalFunctions.find(name);
if (result == functions.end()) {
if (result == externalFunctions.end()) {
return nullptr;
}
return result->second.get();
@ -1587,6 +1712,11 @@ class Module {
void leaveScope() { variableTable.leaveScope(); } ///< 离开作用域
bool isInGlobalArea() const { return variableTable.isInGlobalScope(); } ///< 是否位于全局作用域
/// 清理模块中的所有对象,包括函数、基本块、指令等
void cleanup();
void print(std::ostream& os) const;
};
/*!

View File

@ -217,6 +217,18 @@ class IRBuilder {
BinaryInst * createOrInst(Value *lhs, Value *rhs, const std::string &name = "") {
return createBinaryInst(Instruction::kOr, 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);
} ///< 创建高位乘法指令
CallInst * createCallInst(Function *callee, const std::vector<Value *> &args, const std::string &name = "") {
std::string newName;
if (name.empty() && callee->getReturnType() != Type::getVoidType()) {
@ -239,31 +251,30 @@ class IRBuilder {
block->getInstructions().emplace(position, inst);
return inst;
} ///< 创建return指令
UncondBrInst * createUncondBrInst(BasicBlock *thenBlock, const std::vector<Value *> &args) {
auto inst = new UncondBrInst(thenBlock, args, block);
UncondBrInst * createUncondBrInst(BasicBlock *thenBlock) {
auto inst = new UncondBrInst(thenBlock, block);
assert(inst);
block->getInstructions().emplace(position, inst);
return inst;
} ///< 创建无条件指令
CondBrInst * createCondBrInst(Value *condition, BasicBlock *thenBlock, BasicBlock *elseBlock,
const std::vector<Value *> &thenArgs, const std::vector<Value *> &elseArgs) {
auto inst = new CondBrInst(condition, thenBlock, elseBlock, thenArgs, elseArgs, block);
CondBrInst * createCondBrInst(Value *condition, BasicBlock *thenBlock, BasicBlock *elseBlock) {
auto inst = new CondBrInst(condition, thenBlock, elseBlock, block);
assert(inst);
block->getInstructions().emplace(position, inst);
return inst;
} ///< 创建条件跳转指令
AllocaInst * createAllocaInst(Type *type, const std::vector<Value *> &dims = {}, const std::string &name = "") {
auto inst = new AllocaInst(type, dims, block, name);
UnreachableInst * createUnreachableInst(const std::string &name = "") {
auto inst = new UnreachableInst(name, block);
assert(inst);
block->getInstructions().emplace(position, inst);
return inst;
} ///< 创建不可达指令
AllocaInst * createAllocaInst(Type *type, const std::string &name = "") {
auto inst = new AllocaInst(type, block, name);
assert(inst);
block->getInstructions().emplace(position, inst);
return inst;
} ///< 创建分配指令
AllocaInst * createAllocaInstWithoutInsert(Type *type, const std::vector<Value *> &dims = {}, BasicBlock *parent = nullptr,
const std::string &name = "") {
auto inst = new AllocaInst(type, dims, parent, name);
assert(inst);
return inst;
} ///< 创建不插入指令列表的分配指令[仅用于phi指令]
LoadInst * createLoadInst(Value *pointer, const std::vector<Value *> &indices = {}, const std::string &name = "") {
std::string newName;
if (name.empty()) {
@ -275,7 +286,7 @@ class IRBuilder {
newName = name;
}
auto inst = new LoadInst(pointer, indices, block, newName);
auto inst = new LoadInst(pointer, block, newName);
assert(inst);
block->getInstructions().emplace(position, inst);
return inst;
@ -286,9 +297,8 @@ class IRBuilder {
block->getInstructions().emplace(position, inst);
return inst;
} ///< 创建memset指令
StoreInst * createStoreInst(Value *value, Value *pointer, const std::vector<Value *> &indices = {},
const std::string &name = "") {
auto inst = new StoreInst(value, pointer, indices, block, name);
StoreInst * createStoreInst(Value *value, Value *pointer, const std::string &name = "") {
auto inst = new StoreInst(value, pointer, block, name);
assert(inst);
block->getInstructions().emplace(position, inst);
return inst;
@ -308,24 +318,6 @@ class IRBuilder {
block->getInstructions().emplace(block->begin(), inst);
return inst;
} ///< 创建Phi指令
// GetElementPtrInst* createGetElementPtrInst(Value *basePointer,
// const std::vector<Value *> &indices = {},
// const std::string &name = "") {
// std::string newName;
// if (name.empty()) {
// std::stringstream ss;
// ss << tmpIndex;
// newName = ss.str();
// tmpIndex++;
// } else {
// newName = name;
// }
// auto inst = new GetElementPtrInst(basePointer, indices, block, newName);
// assert(inst);
// block->getInstructions().emplace(position, inst);
// return inst;
// }
/**
* @brief 根据 LLVM 设计模式创建 GEP 指令。
* 它会自动推断返回类型,无需手动指定。
@ -364,38 +356,31 @@ class IRBuilder {
Type *currentWalkType = pointerType->as<PointerType>()->getBaseType();
// 遍历所有索引来深入类型层次结构。
// `indices` 向量包含了所有 GEP 索引,包括由 `visitLValue` 等函数添加的初始 `0` 索引
// 重要:第一个索引总是用于"解引用"指针,后续索引才用于数组/结构体的索引
for (int i = 0; i < indices.size(); ++i) {
if (currentWalkType->isArray()) {
// 情况一:当前遍历类型是 `ArrayType`。
// 索引用于选择数组元素,`currentWalkType` 更新为数组的元素类型。
currentWalkType = currentWalkType->as<ArrayType>()->getElementType();
} else if (currentWalkType->isPointer()) {
// 情况二:当前遍历类型是 `PointerType`。
// 这意味着我们正在通过一个指针来访问其指向的内存。
// 索引用于选择该指针所指向的“数组”的元素。
// `currentWalkType` 更新为该指针所指向的基础类型。
// 例如:如果 `currentWalkType` 是 `i32*`,它将变为 `i32`。
// 如果 `currentWalkType` 是 `[10 x i32]*`,它将变为 `[10 x i32]`。
currentWalkType = currentWalkType->as<PointerType>()->getBaseType();
if (i == 0) {
// 第一个索引:总是用于"解引用"基指针不改变currentWalkType
// 例如:对于 `[4 x i32]* ptr, i32 0`第一个0只是说"访问ptr指向的对象"
// currentWalkType 保持为 `[4 x i32]`
continue;
} else {
// 情况三:当前遍历类型是标量类型 (例如 `i32`, `float` 等非聚合、非指针类型)。
//
// 如果 `currentWalkType` 是标量,并且当前索引 `i` **不是** `indices` 向量中的最后一个索引,
// 这意味着尝试对一个标量类型进行进一步的结构性索引,这是**无效的**。
// 例如:`int x; x[0];` 对应的 GEP 链中,`x` 的类型是 `i32`,再加 `[0]` 索引就是错误。
//
// 如果 `currentWalkType` 是标量,且这是**最后一个索引** (`i == indices.size() - 1`)
// 那么 GEP 是合法的,它只是计算一个偏移地址,最终的类型就是这个标量类型。
// 此时 `currentWalkType` 保持不变,循环结束。
if (i < indices.size() - 1) {
assert(false && "Invalid GEP indexing: attempting to index into a non-aggregate/non-pointer type with further indices.");
return nullptr; // 返回空指针表示类型推断失败
// 后续索引:用于实际的数组/结构体索引
if (currentWalkType->isArray()) {
// 数组索引:选择数组中的元素
currentWalkType = currentWalkType->as<ArrayType>()->getElementType();
} else if (currentWalkType->isPointer()) {
// 指针索引:解引用指针并继续
currentWalkType = currentWalkType->as<PointerType>()->getBaseType();
} else {
// 标量类型:不能进一步索引
if (i < indices.size() - 1) {
assert(false && "Invalid GEP indexing: attempting to index into a non-aggregate/non-pointer type with further indices.");
return nullptr;
}
}
// 如果是最后一个索引,且当前类型是标量,则类型保持不变,这是合法的。
// 循环会自然结束,返回正确的 `currentWalkType`。
}
}
// 所有索引处理完毕后,`currentWalkType` 就是 GEP 指令最终计算出的地址所指向的元素的类型。
return currentWalkType;
}

View 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

View 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

View File

@ -6,30 +6,82 @@
#include <set>
#include <vector>
#include <algorithm>
#include <functional>
namespace sysy {
// 支配树分析结果类 (保持不变)
// 支配树分析结果类
class DominatorTree : public AnalysisResultBase {
public:
DominatorTree(Function* F);
// 获取指定基本块的所有支配者
const std::set<BasicBlock*>* getDominators(BasicBlock* BB) const;
BasicBlock* getImmediateDominator(BasicBlock* BB) const;
const std::set<BasicBlock*>* getDominanceFrontier(BasicBlock* BB) const;
// 获取指定基本块的即时支配者 (Immediate Dominator)
BasicBlock* getImmediateDominator(BasicBlock* BB) const;
// 获取指定基本块的支配边界 (Dominance Frontier)
const std::set<BasicBlock*>* getDominanceFrontier(BasicBlock* BB) const;
// 获取指定基本块在支配树中的子节点
const std::set<BasicBlock*>* getDominatorTreeChildren(BasicBlock* BB) const;
// 额外的 Getter获取所有支配者、即时支配者和支配边界的完整映射可选主要用于调试或特定场景
const std::map<BasicBlock*, std::set<BasicBlock*>>& getDominatorsMap() const { return Dominators; }
const std::map<BasicBlock*, BasicBlock*>& getIDomsMap() const { return IDoms; }
const std::map<BasicBlock*, std::set<BasicBlock*>>& getDominanceFrontiersMap() const { return DominanceFrontiers; }
// 计算所有基本块的支配者集合
void computeDominators(Function* F);
void computeIDoms(Function* F);
// 计算所有基本块的即时支配者(内部使用 Lengauer-Tarjan 算法)
void computeIDoms(Function* F);
// 计算所有基本块的支配边界
void computeDominanceFrontiers(Function* F);
// 计算支配树的结构(即每个节点的直接子节点)
void computeDominatorTreeChildren(Function* F);
private:
// 与该支配树关联的函数
Function* AssociatedFunction;
std::map<BasicBlock*, std::set<BasicBlock*>> Dominators;
std::map<BasicBlock*, BasicBlock*> IDoms;
std::map<BasicBlock*, std::set<BasicBlock*>> DominanceFrontiers;
std::map<BasicBlock*, std::set<BasicBlock*>> DominatorTreeChildren;
std::map<BasicBlock*, std::set<BasicBlock*>> Dominators; // 每个基本块的支配者集合
std::map<BasicBlock*, BasicBlock*> IDoms; // 每个基本块的即时支配者
std::map<BasicBlock*, std::set<BasicBlock*>> DominanceFrontiers; // 每个基本块的支配边界
std::map<BasicBlock*, std::set<BasicBlock*>> DominatorTreeChildren; // 支配树中每个基本块的子节点
// ==========================================================
// Lengauer-Tarjan 算法内部所需的数据结构和辅助函数
// 这些成员是私有的,以封装 LT 算法的复杂性并避免命名空间污染
// ==========================================================
// DFS 遍历相关:
std::map<BasicBlock*, int> dfnum_map; // 存储每个基本块的 DFS 编号
std::vector<BasicBlock*> vertex_vec; // 通过 DFS 编号反向查找对应的基本块指针
std::map<BasicBlock*, BasicBlock*> parent_map; // 存储 DFS 树中每个基本块的父节点
int df_counter; // DFS 计数器,也代表 DFS 遍历的总节点数 (N)
// 半支配者 (Semi-dominator) 相关:
std::map<BasicBlock*, BasicBlock*> sdom_map; // 存储每个基本块的半支配者
std::map<BasicBlock*, BasicBlock*> idom_map; // 存储每个基本块的即时支配者 (IDom)
std::map<BasicBlock*, std::vector<BasicBlock*>> bucket_map; // 桶结构,用于存储具有相同半支配者的节点,以延迟 IDom 计算
// 并查集 (Union-Find) 相关(用于 evalAndCompress 函数):
std::map<BasicBlock*, BasicBlock*> ancestor_map; // 并查集中的父节点(用于路径压缩)
std::map<BasicBlock*, BasicBlock*> label_map; // 并查集中,每个集合的代表节点(或其路径上 sdom 最小的节点)
// ==========================================================
// 辅助计算函数 (私有)
// ==========================================================
// 计算基本块的逆后序遍历 (Reverse Post Order, RPO) 顺序
// RPO 用于优化支配者计算和 LT 算法的效率
std::vector<BasicBlock*> computeReversePostOrder(Function* F);
// Lengauer-Tarjan 算法特定的辅助 DFS 函数
// 用于初始化 dfnum_map, vertex_vec, parent_map
void dfs_lt_helper(BasicBlock* u);
// 结合了并查集的 Find 操作和 LT 算法的 Eval 操作
// 用于在路径压缩时更新 label找到路径上 sdom 最小的节点
BasicBlock* evalAndCompress_lt_helper(BasicBlock* i);
// 并查集的 Link 操作
// 将 v_child 挂载到 u_parent 的并查集树下
void link_lt_helper(BasicBlock* u_parent, BasicBlock* v_child);
};

View 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

View File

@ -0,0 +1,356 @@
#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 hasSimpleMemoryPattern(Loop* loop); // 简单的内存模式检查
};
} // namespace sysy

View 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

View 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

View File

@ -0,0 +1,20 @@
#pragma once
#include "IR.h"
#include "Pass.h"
#include <queue>
#include <set>
namespace sysy {
class BuildCFG : public OptimizationPass {
public:
static void *ID;
BuildCFG() : OptimizationPass("BuildCFG", Granularity::Function) {}
bool runOnFunction(Function *F, AnalysisManager &AM) override;
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override;
void *getPassID() const override { return &ID; }
};
} // namespace sysy

View File

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

View File

@ -0,0 +1,157 @@
#pragma once
#include "Pass.h"
#include "IR.h"
#include "LoopCharacteristics.h"
#include "Loop.h"
#include "Dom.h"
#include "SideEffectAnalysis.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;
// 死归纳变量存储
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);
/**
* 检查归纳变量是否只用于自身更新
* @param phiInst phi指令
* @param loop 所在循环
* @return 是否只用于自身更新
*/
bool isUsedOnlyForSelfUpdate(PhiInst* phiInst, Loop* loop);
/**
* 收集与归纳变量相关的所有指令
* @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

View 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

View File

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

View 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

View File

@ -0,0 +1,240 @@
#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 divisor 除数
* @return {魔数, 移位量}
*/
std::pair<int, int> computeMulhMagicNumbers(int divisor) 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

View File

@ -75,11 +75,7 @@ private:
// --------------------------------------------------------------------
// 对支配树进行深度优先遍历,重命名变量并替换 load/store 指令
// alloca: 当前正在处理的 AllocaInst
// currentBB: 当前正在遍历的基本块
// dt: 支配树分析结果
// valueStack: 存储当前 AllocaInst 在当前路径上可见的 SSA 值栈
void renameVariables(AllocaInst* alloca, BasicBlock* currentBB);
void renameVariables(BasicBlock* currentBB);
// --------------------------------------------------------------------
// 阶段4: 清理

View File

@ -1,196 +1,157 @@
#pragma once
#include "IR.h"
#include "Pass.h"
#include "SysYIROptUtils.h"
#include "AliasAnalysis.h"
#include "SideEffectAnalysis.h"
#include <cassert>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <unordered_set>
#include <vector>
#include <variant>
#include <functional>
namespace sysy {
// 稀疏条件常量传播类
// Sparse Conditional Constant Propagation
/*
伪代码
function SCCP_Optimization(Module):
for each Function in Module:
changed = true
while changed:
changed = false
// 阶段1: 常量传播与折叠
changed |= PropagateConstants(Function)
// 阶段2: 控制流简化
changed |= SimplifyControlFlow(Function)
end while
end for
function PropagateConstants(Function):
// 初始化
executableBlocks = {entryBlock}
valueState = map<Value, State> // 值->状态映射
instWorkList = Queue()
edgeWorkList = Queue()
// 初始化工作列表
for each inst in entryBlock:
instWorkList.push(inst)
// 迭代处理
while !instWorkList.empty() || !edgeWorkList.empty():
// 处理指令工作列表
while !instWorkList.empty():
inst = instWorkList.pop()
// 如果指令是可执行基本块中的
if executableBlocks.contains(inst.parent):
ProcessInstruction(inst)
// 处理边工作列表
while !edgeWorkList.empty():
edge = edgeWorkList.pop()
ProcessEdge(edge)
// 应用常量替换
for each inst in Function:
if valueState[inst] == CONSTANT:
ReplaceWithConstant(inst, valueState[inst].constant)
changed = true
return changed
function ProcessInstruction(Instruction inst):
switch inst.type:
//二元操作
case BINARY_OP:
lhs = GetValueState(inst.operands[0])
rhs = GetValueState(inst.operands[1])
if lhs == CONSTANT && rhs == CONSTANT:
newState = ComputeConstant(inst.op, lhs.value, rhs.value)
UpdateState(inst, newState)
else if lhs == BOTTOM || rhs == BOTTOM:
UpdateState(inst, BOTTOM)
//phi
case PHI:
mergedState =
for each incoming in inst.incomings:
// 检查每个输入的状态
if executableBlocks.contains(incoming.block):
incomingState = GetValueState(incoming.value)
mergedState = Meet(mergedState, incomingState)
UpdateState(inst, mergedState)
// 条件分支
case COND_BRANCH:
cond = GetValueState(inst.condition)
if cond == CONSTANT:
// 判断条件分支
if cond.value == true:
AddEdgeToWorkList(inst.parent, inst.trueTarget)
else:
AddEdgeToWorkList(inst.parent, inst.falseTarget)
else if cond == BOTTOM:
AddEdgeToWorkList(inst.parent, inst.trueTarget)
AddEdgeToWorkList(inst.parent, inst.falseTarget)
case UNCOND_BRANCH:
AddEdgeToWorkList(inst.parent, inst.target)
// 其他指令处理...
function ProcessEdge(Edge edge):
fromBB, toBB = edge
if !executableBlocks.contains(toBB):
executableBlocks.add(toBB)
for each inst in toBB:
if inst is PHI:
instWorkList.push(inst)
else:
instWorkList.push(inst) // 非PHI指令
// 更新PHI节点的输入
for each phi in toBB.phis:
instWorkList.push(phi)
function SimplifyControlFlow(Function):
changed = false
// 标记可达基本块
ReachableBBs = FindReachableBlocks(Function.entry)
// 删除不可达块
for each bb in Function.blocks:
if !ReachableBBs.contains(bb):
RemoveDeadBlock(bb)
changed = true
// 简化条件分支
for each bb in Function.blocks:
terminator = bb.terminator
if terminator is COND_BRANCH:
cond = GetValueState(terminator.condition)
if cond == CONSTANT:
SimplifyBranch(terminator, cond.value)
changed = true
return changed
function RemoveDeadBlock(BasicBlock bb):
// 1. 更新前驱块的分支指令
for each pred in bb.predecessors:
UpdateTerminator(pred, bb)
// 2. 更新后继块的PHI节点
for each succ in bb.successors:
RemovePhiIncoming(succ, bb)
// 3. 删除块内所有指令
for each inst in bb.instructions:
inst.remove()
// 4. 从函数中移除基本块
Function.removeBlock(bb)
function Meet(State a, State b):
if a == : return b
if b == : return a
if a == ⊥ || b == ⊥: return ⊥
if a.value == b.value: return a
return ⊥
function UpdateState(Value v, State newState):
oldState = valueState.get(v, )
if newState != oldState:
valueState[v] = newState
for each user in v.users:
if user is Instruction:
instWorkList.push(user)
*/
enum class LatticeValue {
Top, // (Unknown)
Constant, // c (Constant)
Bottom // ⊥ (Undefined / Varying)
// 定义三值格 (Three-valued Lattice) 的状态
enum class LatticeVal {
Top, // (未知 / 未初始化)
Constant, // c (常量)
Bottom // ⊥ (不确定 / 变化 / 未定义)
};
// LatticeValue: 用于表示值的状态Top表示未知Constant表示常量Bottom表示未定义或变化的值。
// 这里的LatticeValue用于跟踪每个SSA值变量、指令结果的状态
// 以便在SCCP过程中进行常量传播和控制流简化。
//TODO: 下列数据结构考虑集成到类中,避免重命名问题
static std::set<Instruction *> Worklist;
static std::unordered_set<BasicBlock*> Executable_Blocks;
static std::queue<std::pair<BasicBlock *, BasicBlock *> > Executable_Edges;
static std::map<Value*, LatticeValue> valueState;
// 新增枚举来区分常量的实际类型
enum class ValueType {
Integer,
Float,
Unknown // 用于 Top 和 Bottom 状态
};
class SCCP {
// 用于表示 SSA 值的具体状态(包含格值和常量值)
struct SSAPValue {
LatticeVal state;
std::variant<int, float> constantVal; // 使用 std::variant 存储 int 或 float
ValueType constant_type; // 记录常量是整数还是浮点数
// 默认构造函数,初始化为 Top
SSAPValue() : state(LatticeVal::Top), constantVal(0), constant_type(ValueType::Unknown) {}
// 构造函数,用于创建 Bottom 状态
SSAPValue(LatticeVal s) : state(s), constantVal(0), constant_type(ValueType::Unknown) {
assert((s == LatticeVal::Top || s == LatticeVal::Bottom) && "SSAPValue(LatticeVal) only for Top/Bottom");
}
// 构造函数,用于创建 int Constant 状态
SSAPValue(int c) : state(LatticeVal::Constant), constantVal(c), constant_type(ValueType::Integer) {}
// 构造函数,用于创建 float Constant 状态
SSAPValue(float c) : state(LatticeVal::Constant), constantVal(c), constant_type(ValueType::Float) {}
// 比较操作符,用于判断状态是否改变
bool operator==(const SSAPValue &other) const {
if (state != other.state)
return false;
if (state == LatticeVal::Constant) {
if (constant_type != other.constant_type) return false; // 类型必须匹配
return constantVal == other.constantVal; // std::variant 会比较内部值
}
return true; // Top == Top, Bottom == Bottom
}
bool operator!=(const SSAPValue &other) const { return !(*this == other); }
};
// SCCP 上下文类,持有每个函数运行时的状态
class SCCPContext {
private:
Module *pModule;
IRBuilder *builder; // IR 构建器,用于插入指令和创建常量
AliasAnalysisResult *aliasAnalysis; // 别名分析结果
SideEffectAnalysisResult *sideEffectAnalysis; // 副作用分析结果
// 工作列表
// 存储需要重新评估的指令
std::queue<Instruction *> instWorkList;
// 存储需要重新评估的控制流边 (pair: from_block, to_block)
std::queue<std::pair<BasicBlock *, BasicBlock *>> edgeWorkList;
// 格值映射SSA Value 到其当前状态
std::map<Value *, SSAPValue> valueState;
// 可执行基本块集合
std::unordered_set<BasicBlock *> executableBlocks;
// 追踪已访问的CFG边防止重复添加使用 SysYIROptUtils::PairHash
std::unordered_set<std::pair<BasicBlock*, BasicBlock*>, SysYIROptUtils::PairHash> visitedCFGEdges;
// 辅助函数:格操作 Meet
SSAPValue Meet(const SSAPValue &a, const SSAPValue &b);
// 辅助函数:获取值的当前状态,如果不存在则默认为 Top
SSAPValue GetValueState(Value *v);
// 辅助函数:更新值的状态,如果状态改变,将所有用户加入指令工作列表
void UpdateState(Value *v, SSAPValue newState);
// 辅助函数:将边加入边工作列表,并更新可执行块
void AddEdgeToWorkList(BasicBlock *fromBB, BasicBlock *toBB);
// 辅助函数:标记一个块为可执行
void MarkBlockExecutable(BasicBlock* block);
// 辅助函数:对二元操作进行常量折叠
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: 常量传播与折叠
bool PropagateConstants(Function *func);
// 阶段2: 控制流简化
bool SimplifyControlFlow(Function *func);
// 辅助函数:处理单条指令
void ProcessInstruction(Instruction *inst);
// 辅助函数:处理单条控制流边
void ProcessEdge(const std::pair<BasicBlock *, BasicBlock *> &edge);
// 控制流简化辅助函数
// 查找所有可达的基本块 (基于常量条件)
std::unordered_set<BasicBlock *> FindReachableBlocks(Function *func);
// 移除死块
void RemoveDeadBlock(BasicBlock *bb, Function *func);
// 简化分支(将条件分支替换为无条件分支)
void SimplifyBranch(CondBrInst*brInst, bool condVal); // 保持 BranchInst
// 更新前驱块的终结指令(当一个后继块被移除时)
void UpdateTerminator(BasicBlock *predBB, BasicBlock *removedSucc);
// 移除 Phi 节点的入边(当其前驱块被移除时)
void RemovePhiIncoming(BasicBlock *phiParentBB, BasicBlock *removedPred);
public:
SCCP(Module *pMoudle) : pModule(pMoudle) {}
SCCPContext(IRBuilder *builder) : builder(builder), aliasAnalysis(nullptr), sideEffectAnalysis(nullptr) {}
// 设置别名分析结果
void setAliasAnalysis(AliasAnalysisResult *aa) { aliasAnalysis = aa; }
// 设置副作用分析结果
void setSideEffectAnalysis(SideEffectAnalysisResult *sea) { sideEffectAnalysis = sea; }
void run();
bool PropagateConstants(Function *function);
bool SimplifyControlFlow(Function *function);
void ProcessInstruction(Instruction *inst);
void ProcessEdge(const std::pair<BasicBlock *, BasicBlock *> &edge);
void RemoveDeadBlock(BasicBlock *bb);
void UpdateState(Value *v, LatticeValue newState);
LatticeValue Meet(LatticeValue a, LatticeValue b);
LatticeValue GetValueState(Value *v);
// 运行 SCCP 优化
void run(Function *func, AnalysisManager &AM);
};
} // namespace sysy
// SCCP 优化遍类,继承自 OptimizationPass
class SCCP : public OptimizationPass {
private:
IRBuilder *builder; // IR 构建器,作为 Pass 的成员,传入 Context
public:
SCCP(IRBuilder *builder) : OptimizationPass("SCCP", Granularity::Function), builder(builder) {}
static void *ID;
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

View File

@ -2,6 +2,7 @@
#include "IR.h"
extern int DEBUG;
namespace sysy {
// 优化工具类,包含一些通用的优化方法
@ -10,12 +11,80 @@ namespace sysy {
class SysYIROptUtils{
public:
// 仅仅删除use关系
static void usedelete(Instruction *instr) {
for (auto &use : instr->getOperands()) {
Value* val = use->getValue();
val->removeUse(use);
struct PairHash {
template <class T1, class T2>
std::size_t operator () (const std::pair<T1, T2>& p) const {
auto h1 = std::hash<T1>{}(p.first);
auto h2 = std::hash<T2>{}(p.second);
// 简单的组合哈希值,可以更复杂以减少冲突
// 使用 boost::hash_combine 的简化版本
return h1 ^ (h2 << 1);
}
};
static void RemoveUserOperandUses(User *user) {
if (!user) {
return;
}
// 遍历 User 的 operands 列表。
// 由于 operands 是 protected 成员,我们需要一个临时方法来访问它,
// 或者在 User 类中添加一个 friend 声明。
// 假设 User 内部有一个像 getOperands() 这样的公共方法返回 operands 的引用,
// 或者将 SysYIROptUtils 声明为 User 的 friend。
// 为了示例,我将假设可以直接访问 user->operands 或通过一个getter。
// 如果无法直接访问,请在 IR.h 的 User 类中添加:
// public: const std::vector<std::shared_ptr<Use>>& getOperands() const { return operands; }
// 迭代 copies of shared_ptr to avoid issues if removeUse modifies the list
// (though remove should handle it, iterating a copy is safer or reverse iteration).
// Since we'll clear the vector at the end, iterating forward is fine.
for (const auto& use_ptr : user->getOperands()) { // 假设 getOperands() 可用
if (use_ptr) {
Value *val = use_ptr->getValue(); // 获取 Use 指向的 Value (如 AllocaInst)
if (val) {
val->removeUse(use_ptr); // 通知 Value 从其 uses 列表中移除此 Use 关系
}
}
}
}
static void usedelete(Instruction *inst) {
assert(inst && "Instruction to delete cannot be null.");
BasicBlock *parentBlock = inst->getParent();
assert(parentBlock && "Instruction must have a parent BasicBlock to be deleted.");
// 步骤1: 处理所有使用者,将他们从使用 inst 变为使用 UndefinedValue
// 这将清理 inst 作为 Value 时的 uses 列表
if (!inst->getUses().empty()) {
inst->replaceAllUsesWith(UndefinedValue::get(inst->getType()));
}
// 步骤2: 清理 inst 作为 User 时的操作数关系
// 通知 inst 所使用的所有 Value (如 AllocaInst),移除对应的 Use 关系。
// 这里的 inst 实际上是一个 User*,所以可以安全地向下转型。
RemoveUserOperandUses(static_cast<User*>(inst));
// 步骤3: 物理删除指令
// 这会导致 Instruction 对象的 unique_ptr 销毁,从而调用其析构函数链。
parentBlock->removeInst(inst);
}
static BasicBlock::iterator usedelete(BasicBlock::iterator inst_it) {
Instruction *inst_to_delete = inst_it->get();
BasicBlock *parentBlock = inst_to_delete->getParent();
assert(parentBlock && "Instruction must have a parent BasicBlock for iterator deletion.");
// 步骤1: 处理所有使用者
if (!inst_to_delete->getUses().empty()) {
inst_to_delete->replaceAllUsesWith(UndefinedValue::get(inst_to_delete->getType()));
}
// 步骤2: 清理操作数关系
RemoveUserOperandUses(static_cast<User*>(inst_to_delete));
// 步骤3: 物理删除指令并返回下一个迭代器
return parentBlock->removeInst(inst_it);
}
// 判断是否是全局变量
@ -26,7 +95,17 @@ public:
// 判断是否是数组
static bool isArr(Value *val) {
auto aval = dynamic_cast<AllocaInst *>(val);
return aval != nullptr && aval->getNumDims() != 0;
// 如果是 AllocaInst 且通过Type::isArray()判断为数组类型
return aval && aval->getType()->as<PointerType>()->getBaseType()->isArray();
}
// 判断是否是指向数组的指针
static bool isArrPointer(Value *val) {
auto aval = dynamic_cast<AllocaInst *>(val);
// 如果是 AllocaInst 且通过Type::isPointer()判断为指针;
auto baseType = aval->getType()->as<PointerType>()->getBaseType();
// 在sysy中函数的数组参数会退化成指针
// 所以当AllocaInst的basetype是PointerType时一维数组或者是指向ArrayType的PointerType多位数组返回true
return aval && (baseType->isPointer() || baseType->as<PointerType>()->getBaseType()->isArray());
}
};

View File

@ -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);
// 获取结果并缓存
@ -279,7 +299,7 @@ private:
IRBuilder *pBuilder;
public:
PassManager() = default;
PassManager() = delete;
~PassManager() = default;
PassManager(Module *module, IRBuilder *builder) : pmodule(module) ,pBuilder(builder), analysisManager(module) {}

View File

@ -86,7 +86,60 @@ private:
case LPAREN: case RPAREN: return 0; // Parentheses have lowest precedence for stack logic
default: return -1; // Unknown operator
}
}
};
struct ExpKey {
BinaryOp op; ///< 操作符
Value *left; ///< 左操作数
Value *right; ///< 右操作数
ExpKey(BinaryOp op, Value *left, Value *right) : op(op), left(left), right(right) {}
bool operator<(const ExpKey &other) const {
if (op != other.op)
return op < other.op; ///< 比较操作符
if (left != other.left)
return left < other.left; ///< 比较左操作
return right < other.right; ///< 比较右操作数
} ///< 重载小于运算符用于比较ExpKey
};
struct UnExpKey {
BinaryOp op; ///< 一元操作符
Value *operand; ///< 操作数
UnExpKey(BinaryOp op, Value *operand) : op(op), operand(operand) {}
bool operator<(const UnExpKey &other) const {
if (op != other.op)
return op < other.op; ///< 比较操作符
return operand < other.operand; ///< 比较操作数
} ///< 重载小于运算符用于比较UnExpKey
};
struct GEPKey {
Value *basePointer;
std::vector<Value *> indices;
// 为 std::map 定义比较运算符,使得 GEPKey 可以作为键
bool operator<(const GEPKey &other) const {
if (basePointer != other.basePointer) {
return basePointer < other.basePointer;
}
// 逐个比较索引,确保顺序一致
if (indices.size() != other.indices.size()) {
return indices.size() < other.indices.size();
}
for (size_t i = 0; i < indices.size(); ++i) {
if (indices[i] != other.indices[i]) {
return indices[i] < other.indices[i];
}
}
return false; // 如果 basePointer 和所有索引都相同,则认为相等
}
};
std::map<GEPKey, Value*> availableGEPs; ///< 用于存储 GEP 的缓存
std::map<ExpKey, Value*> availableBinaryExpressions;
std::map<UnExpKey, Value*> availableUnaryExpressions;
std::map<Value*, Value*> availableLoads;
public:
SysYIRGenerator() = default;
@ -167,6 +220,15 @@ public:
Value* computeExp(SysYParser::ExpContext *ctx, Type* targetType = nullptr);
Value* computeAddExp(SysYParser::AddExpContext *ctx, Type* targetType = nullptr);
void compute();
// 参数是发生 store 操作的目标地址/变量的 Value*
void invalidateExpressionsOnStore(Value* storedAddress);
// 清除因函数调用而失效的表达式缓存(保守策略)
void invalidateExpressionsOnCall();
// 在进入新的基本块时清空所有表达式缓存
void enterNewBasicBlock();
public:
// 获取GEP指令的地址
Value* getGEPAddressInst(Value* basePointer, const std::vector<Value*>& indices);

View File

@ -6,10 +6,23 @@ 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/SysYIRCFGOpt.cpp
Pass/Optimize/SCCP.cpp
Pass/Optimize/LoopNormalization.cpp
Pass/Optimize/LICM.cpp
Pass/Optimize/LoopStrengthReduction.cpp
Pass/Optimize/InductionVariableElimination.cpp
Pass/Optimize/BuildCFG.cpp
Pass/Optimize/LargeArrayToGlobal.cpp
)
# 包含中端模块所需的头文件路径

File diff suppressed because it is too large Load Diff

View 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

View 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

View File

@ -1,19 +1,30 @@
#include "Dom.h"
#include <limits> // for std::numeric_limits
#include <algorithm> // for std::set_intersection, std::reverse
#include <iostream> // for debug output
#include <limits> // for std::numeric_limits
#include <queue>
#include <functional> // for std::function
#include <map>
#include <vector>
#include <set>
namespace sysy {
// 初始化 支配树静态 ID
// ==============================================================
// DominatorTreeAnalysisPass 的静态ID
// ==============================================================
void *DominatorTreeAnalysisPass::ID = (void *)&DominatorTreeAnalysisPass::ID;
// ==============================================================
// DominatorTree 结果类的实现
// ==============================================================
// 构造函数:初始化关联函数,但不进行计算
DominatorTree::DominatorTree(Function *F) : AssociatedFunction(F) {
// 构造时可以不计算,在分析遍运行里计算并填充
// 构造时不需要计算,在分析遍运行里计算并填充
}
// Getter 方法 (保持不变)
const std::set<BasicBlock *> *DominatorTree::getDominators(BasicBlock *BB) const {
auto it = Dominators.find(BB);
if (it != Dominators.end()) {
@ -38,164 +49,437 @@ const std::set<BasicBlock *> *DominatorTree::getDominanceFrontier(BasicBlock *BB
return nullptr;
}
const std::set<BasicBlock*>* DominatorTree::getDominatorTreeChildren(BasicBlock* BB) const {
auto it = DominatorTreeChildren.find(BB);
if (it != DominatorTreeChildren.end()) {
return &(it->second);
}
return nullptr;
const std::set<BasicBlock *> *DominatorTree::getDominatorTreeChildren(BasicBlock *BB) const {
auto it = DominatorTreeChildren.find(BB);
if (it != DominatorTreeChildren.end()) {
return &(it->second);
}
return nullptr;
}
void DominatorTree::computeDominators(Function *F) {
// 经典的迭代算法计算支配者集合
// TODO: 可以替换为更高效的算法,如 Lengauer-Tarjan 算法
BasicBlock *entryBlock = F->getEntryBlock();
// 辅助函数:打印 BasicBlock 集合 (保持不变)
void printBBSet(const std::string &prefix, const std::set<BasicBlock *> &s) {
if (!DEBUG)
return;
std::cout << prefix << "{";
bool first = true;
for (const auto &bb : s) {
if (!first)
std::cout << ", ";
std::cout << bb->getName();
first = false;
}
std::cout << "}" << std::endl;
}
for (const auto &bb_ptr : F->getBasicBlocks()) {
BasicBlock *bb = bb_ptr.get();
// 辅助函数:计算逆后序遍历 (RPO) - 保持不变
std::vector<BasicBlock*> DominatorTree::computeReversePostOrder(Function* F) {
std::vector<BasicBlock*> postOrder;
std::set<BasicBlock*> visited;
std::function<void(BasicBlock*)> dfs_rpo =
[&](BasicBlock* bb) {
visited.insert(bb);
for (BasicBlock* succ : bb->getSuccessors()) {
if (visited.find(succ) == visited.end()) {
dfs_rpo(succ);
}
}
postOrder.push_back(bb);
};
dfs_rpo(F->getEntryBlock());
std::reverse(postOrder.begin(), postOrder.end());
if (DEBUG) {
std::cout << "--- Computed RPO: ";
for (BasicBlock* bb : postOrder) {
std::cout << bb->getName() << " ";
}
std::cout << "---" << std::endl;
}
return postOrder;
}
// computeDominators 方法 (保持不变因为它它是独立于IDom算法的)
void DominatorTree::computeDominators(Function *F) {
if (DEBUG)
std::cout << "--- Computing Dominators ---" << std::endl;
BasicBlock *entryBlock = F->getEntryBlock();
std::vector<BasicBlock*> bbs_rpo = computeReversePostOrder(F);
for (BasicBlock *bb : bbs_rpo) {
if (bb == entryBlock) {
Dominators[bb].clear();
Dominators[bb].insert(bb);
if (DEBUG) std::cout << "Init Dominators[" << bb->getName() << "]: {" << bb->getName() << "}" << std::endl;
} else {
for (const auto &all_bb_ptr : F->getBasicBlocks()) {
Dominators[bb].insert(all_bb_ptr.get());
Dominators[bb].clear();
for (BasicBlock *all_bb : bbs_rpo) {
Dominators[bb].insert(all_bb);
}
if (DEBUG) {
std::cout << "Init Dominators[" << bb->getName() << "]: ";
printBBSet("", Dominators[bb]);
}
}
}
bool changed = true;
int iteration = 0;
while (changed) {
changed = false;
for (const auto &bb_ptr : F->getBasicBlocks()) {
BasicBlock *bb = bb_ptr.get();
if (bb == entryBlock)
continue;
iteration++;
if (DEBUG) std::cout << "Iteration " << iteration << std::endl;
for (BasicBlock *bb : bbs_rpo) {
if (bb == entryBlock) continue;
std::set<BasicBlock *> newDom;
bool firstPred = true;
bool firstPredProcessed = false;
for (BasicBlock *pred : bb->getPredecessors()) {
if (Dominators.count(pred)) {
if (firstPred) {
newDom = Dominators[pred];
firstPred = false;
} else {
std::set<BasicBlock *> intersection;
std::set_intersection(newDom.begin(), newDom.end(), Dominators[pred].begin(), Dominators[pred].end(),
std::inserter(intersection, intersection.begin()));
newDom = intersection;
}
if(DEBUG){
std::cout << " Processing predecessor: " << pred->getName() << std::endl;
}
if (!firstPredProcessed) {
newDom = Dominators[pred];
firstPredProcessed = true;
} else {
std::set<BasicBlock *> intersection;
std::set_intersection(newDom.begin(), newDom.end(), Dominators[pred].begin(), Dominators[pred].end(),
std::inserter(intersection, intersection.begin()));
newDom = intersection;
}
}
newDom.insert(bb);
if (newDom != Dominators[bb]) {
if (DEBUG) {
std::cout << " Dominators[" << bb->getName() << "] changed from ";
printBBSet("", Dominators[bb]);
std::cout << " to ";
printBBSet("", newDom);
}
Dominators[bb] = newDom;
changed = true;
}
}
}
if (DEBUG)
std::cout << "--- Dominators Computation Finished ---" << std::endl;
}
void DominatorTree::computeIDoms(Function *F) {
// 采用与之前类似的简化实现。TODO:Lengauer-Tarjan算法
BasicBlock *entryBlock = F->getEntryBlock();
IDoms[entryBlock] = nullptr;
// ==============================================================
// Lengauer-Tarjan 算法辅助数据结构和函数 (私有成员)
// ==============================================================
for (const auto &bb_ptr : F->getBasicBlocks()) {
BasicBlock *bb = bb_ptr.get();
if (bb == entryBlock)
continue;
BasicBlock *currentIDom = nullptr;
const std::set<BasicBlock *> *domsOfBB = getDominators(bb);
if (!domsOfBB)
continue;
for (BasicBlock *D : *domsOfBB) {
if (D == bb)
continue;
bool isCandidateIDom = true;
for (BasicBlock *candidate : *domsOfBB) {
if (candidate == bb || candidate == D)
continue;
const std::set<BasicBlock *> *domsOfCandidate = getDominators(candidate);
if (domsOfCandidate && domsOfCandidate->count(D) == 0 && domsOfBB->count(candidate)) {
isCandidateIDom = false;
break;
}
}
if (isCandidateIDom) {
currentIDom = D;
break;
}
// DFS 遍历,填充 dfnum_map, vertex_vec, parent_map
// 对应用户代码的 dfs 函数
void DominatorTree::dfs_lt_helper(BasicBlock* u) {
dfnum_map[u] = df_counter;
if (df_counter >= vertex_vec.size()) { // 动态调整大小
vertex_vec.resize(df_counter + 1);
}
vertex_vec[df_counter] = u;
if (DEBUG) std::cout << " DFS: Visiting " << u->getName() << ", dfnum = " << df_counter << std::endl;
df_counter++;
for (BasicBlock* v : u->getSuccessors()) {
if (dfnum_map.find(v) == dfnum_map.end()) { // 如果 v 未访问过
parent_map[v] = u;
if (DEBUG) std::cout << " DFS: Setting parent[" << v->getName() << "] = " << u->getName() << std::endl;
dfs_lt_helper(v);
}
}
IDoms[bb] = currentIDom;
}
}
// 并查集:找到集合的代表,并进行路径压缩
// 同时更新 label确保 label[i] 总是指向其祖先链中 sdom_map 最小的节点
// 对应用户代码的 find 函数,也包含了 eval 的逻辑
BasicBlock* DominatorTree::evalAndCompress_lt_helper(BasicBlock* i) {
if (DEBUG) std::cout << " Eval: Processing " << i->getName() << std::endl;
// 如果 i 是根 (ancestor_map[i] == nullptr)
if (ancestor_map.find(i) == ancestor_map.end() || ancestor_map[i] == nullptr) {
if (DEBUG) std::cout << " Eval: " << i->getName() << " is root, returning itself." << std::endl;
return i; // 根节点自身就是路径上sdom最小的因为它没有祖先
}
// 如果 i 的祖先不是根,则递归查找并进行路径压缩
BasicBlock* root_ancestor = evalAndCompress_lt_helper(ancestor_map[i]);
// 路径压缩时,根据 sdom_map 比较并更新 label_map
// 确保 label_map[i] 存储的是 i 到 root_ancestor 路径上 sdom_map 最小的节点
// 注意:这里的 ancestor_map[i] 已经被递归调用压缩过一次了所以是root_ancestor的旧路径
// 应该比较的是 label_map[ancestor_map[i]] 和 label_map[i]
if (sdom_map.count(label_map[ancestor_map[i]]) && // 确保 label_map[ancestor_map[i]] 存在 sdom
sdom_map.count(label_map[i]) && // 确保 label_map[i] 存在 sdom
dfnum_map[sdom_map[label_map[ancestor_map[i]]]] < dfnum_map[sdom_map[label_map[i]]]) {
if (DEBUG) std::cout << " Eval: Updating label for " << i->getName() << " from "
<< label_map[i]->getName() << " to " << label_map[ancestor_map[i]]->getName() << std::endl;
label_map[i] = label_map[ancestor_map[i]];
}
ancestor_map[i] = root_ancestor; // 执行路径压缩:将 i 直接指向其所属集合的根
if (DEBUG) std::cout << " Eval: Path compression for " << i->getName() << ", new ancestor = "
<< (root_ancestor ? root_ancestor->getName() : "nullptr") << std::endl;
return label_map[i]; // <-- **将这里改为返回 label_map[i]**
}
// Link 函数:将 v 加入 u 的 DFS 树子树中 (实际上是并查集操作)
// 对应用户代码的 fa[u] = fth[u];
void DominatorTree::link_lt_helper(BasicBlock* u_parent, BasicBlock* v_child) {
ancestor_map[v_child] = u_parent; // 设置并查集父节点
label_map[v_child] = v_child; // 初始化 label 为自身
if (DEBUG) std::cout << " Link: " << v_child->getName() << " linked to " << u_parent->getName() << std::endl;
}
// ==============================================================
// Lengauer-Tarjan 算法实现 computeIDoms
// ==============================================================
void DominatorTree::computeIDoms(Function *F) {
if (DEBUG) std::cout << "--- Computing Immediate Dominators (IDoms) using Lengauer-Tarjan ---" << std::endl;
BasicBlock *entryBlock = F->getEntryBlock();
// 1. 初始化所有 LT 相关的数据结构
dfnum_map.clear();
vertex_vec.clear();
parent_map.clear();
sdom_map.clear();
idom_map.clear();
bucket_map.clear();
ancestor_map.clear();
label_map.clear();
df_counter = 0; // DFS 计数器从 0 开始
// 预分配 vertex_vec 的大小避免频繁resize
vertex_vec.resize(F->getBasicBlocks().size() + 1);
// 在 DFS 遍历之前,先为所有基本块初始化 sdom 和 label
// 这是 Lengauer-Tarjan 算法的要求,确保所有节点在 Phase 2 开始前都在 map 中
for (auto &bb_ptr : F->getBasicBlocks()) {
BasicBlock* bb = bb_ptr.get();
sdom_map[bb] = bb; // sdom(bb) 初始化为 bb 自身
label_map[bb] = bb; // label(bb) 初始化为 bb 自身 (用于 Union-Find 的路径压缩)
}
// 确保入口块也被正确初始化(如果它不在 F->getBasicBlocks() 的正常迭代中)
sdom_map[entryBlock] = entryBlock;
label_map[entryBlock] = entryBlock;
// Phase 1: DFS 遍历并预处理
// 对应用户代码的 dfs(st)
dfs_lt_helper(entryBlock);
idom_map[entryBlock] = nullptr; // 入口块没有即时支配者
if (DEBUG) std::cout << " IDom[" << entryBlock->getName() << "] = nullptr" << std::endl;
if (DEBUG) std::cout << " Sdom[" << entryBlock->getName() << "] = " << entryBlock->getName() << std::endl;
// 初始化并查集的祖先和 label
for (auto const& [bb_key, dfn_val] : dfnum_map) {
ancestor_map[bb_key] = nullptr; // 初始为独立集合的根
label_map[bb_key] = bb_key; // 初始 label 为自身
}
if (DEBUG) {
std::cout << " --- DFS Phase Complete ---" << std::endl;
std::cout << " dfnum_map:" << std::endl;
for (auto const& [bb, dfn] : dfnum_map) {
std::cout << " " << bb->getName() << " -> " << dfn << std::endl;
}
std::cout << " vertex_vec (by dfnum):" << std::endl;
for (size_t k = 0; k < df_counter; ++k) {
if (vertex_vec[k]) std::cout << " [" << k << "] -> " << vertex_vec[k]->getName() << std::endl;
}
std::cout << " parent_map:" << std::endl;
for (auto const& [child, parent] : parent_map) {
std::cout << " " << child->getName() << " -> " << (parent ? parent->getName() : "nullptr") << std::endl;
}
std::cout << " ------------------------" << std::endl;
}
// Phase 2: 计算半支配者 (sdom)
// 对应用户代码的 for (int i = dfc; i >= 2; --i) 循环的上半部分
// 按照 DFS 编号递减的顺序遍历所有节点 (除了 entryBlock它的 DFS 编号是 0)
if (DEBUG) std::cout << "--- Phase 2: Computing Semi-Dominators (sdom) ---" << std::endl;
for (int i = df_counter - 1; i >= 1; --i) { // 从 DFS 编号最大的节点开始,到 1
BasicBlock* w = vertex_vec[i]; // 当前处理的节点
if (DEBUG) std::cout << " Processing node w: " << w->getName() << " (dfnum=" << i << ")" << std::endl;
// 对于 w 的每个前驱 v
for (BasicBlock* v : w->getPredecessors()) {
if (DEBUG) std::cout << " Considering predecessor v: " << v->getName() << std::endl;
// 如果前驱 v 未被 DFS 访问过 (即不在 dfnum_map 中),则跳过
if (dfnum_map.find(v) == dfnum_map.end()) {
if (DEBUG) std::cout << " Predecessor " << v->getName() << " not in DFS tree, skipping." << std::endl;
continue;
}
// 调用 evalAndCompress 来找到 v 在其 DFS 树祖先链上具有最小 sdom 的节点
BasicBlock* u_with_min_sdom_on_path = evalAndCompress_lt_helper(v);
if (DEBUG) std::cout << " Eval(" << v->getName() << ") returned "
<< u_with_min_sdom_on_path->getName() << std::endl;
if (DEBUG && sdom_map.count(u_with_min_sdom_on_path) && sdom_map.count(w)) {
std::cout << " Comparing sdom: dfnum[" << sdom_map[u_with_min_sdom_on_path]->getName() << "] (" << dfnum_map[sdom_map[u_with_min_sdom_on_path]]
<< ") vs dfnum[" << sdom_map[w]->getName() << "] (" << dfnum_map[sdom_map[w]] << ")" << std::endl;
}
// 比较 sdom(u) 和 sdom(w)
if (sdom_map.count(u_with_min_sdom_on_path) && sdom_map.count(w) &&
dfnum_map[sdom_map[u_with_min_sdom_on_path]] < dfnum_map[sdom_map[w]]) {
if (DEBUG) std::cout << " Updating sdom[" << w->getName() << "] from "
<< sdom_map[w]->getName() << " to "
<< sdom_map[u_with_min_sdom_on_path]->getName() << std::endl;
sdom_map[w] = sdom_map[u_with_min_sdom_on_path]; // 更新 sdom(w)
if (DEBUG) std::cout << " Sdom update applied. New sdom[" << w->getName() << "] = " << sdom_map[w]->getName() << std::endl;
}
}
// 将 w 加入 sdom(w) 对应的桶中
bucket_map[sdom_map[w]].push_back(w);
if (DEBUG) std::cout << " Adding " << w->getName() << " to bucket of sdom(" << w->getName() << "): "
<< sdom_map[w]->getName() << std::endl;
// 将 w 的父节点加入并查集 (link 操作)
if (parent_map.count(w) && parent_map[w] != nullptr) {
link_lt_helper(parent_map[w], w);
}
// Phase 3-part 1: 处理 parent[w] 的桶中所有节点,确定部分 idom
if (parent_map.count(w) && parent_map[w] != nullptr) {
BasicBlock* p = parent_map[w]; // p 是 w 的父节点
if (DEBUG) std::cout << " Processing bucket for parent " << p->getName() << std::endl;
// 注意这里需要复制桶的内容因为原始桶在循环中会被clear
std::vector<BasicBlock*> nodes_in_p_bucket_copy = bucket_map[p];
for (BasicBlock* y : nodes_in_p_bucket_copy) {
if (DEBUG) std::cout << " Processing node y from bucket: " << y->getName() << std::endl;
// 找到 y 在其 DFS 树祖先链上具有最小 sdom 的节点
BasicBlock* u = evalAndCompress_lt_helper(y);
if (DEBUG) std::cout << " Eval(" << y->getName() << ") returned " << u->getName() << std::endl;
// 确定 idom(y)
// if sdom(eval(y)) == sdom(parent(w)), then idom(y) = parent(w)
// else idom(y) = eval(y)
if (sdom_map.count(u) && sdom_map.count(p) &&
dfnum_map[sdom_map[u]] < dfnum_map[sdom_map[p]]) {
idom_map[y] = u; // 确定的 idom
if (DEBUG) std::cout << " IDom[" << y->getName() << "] set to " << u->getName() << std::endl;
} else {
idom_map[y] = p; // p 是 y 的 idom
if (DEBUG) std::cout << " IDom[" << y->getName() << "] set to " << p->getName() << std::endl;
}
}
bucket_map[p].clear(); // 清空桶,防止重复处理
if (DEBUG) std::cout << " Cleared bucket for parent " << p->getName() << std::endl;
}
}
// Phase 3-part 2: 最终确定 idom (处理那些 idom != sdom 的节点)
if (DEBUG) std::cout << "--- Phase 3: Finalizing Immediate Dominators (idom) ---" << std::endl;
for (int i = 1; i < df_counter; ++i) { // 从 DFS 编号最小的节点 (除了 entryBlock) 开始
BasicBlock* w = vertex_vec[i];
if (DEBUG) std::cout << " Finalizing node w: " << w->getName() << std::endl;
if (idom_map.count(w) && sdom_map.count(w) && idom_map[w] != sdom_map[w]) {
// idom[w] 的 idom 是其真正的 idom
if (DEBUG) std::cout << " idom[" << w->getName() << "] (" << idom_map[w]->getName()
<< ") != sdom[" << w->getName() << "] (" << sdom_map[w]->getName() << ")" << std::endl;
if (idom_map.count(idom_map[w])) {
idom_map[w] = idom_map[idom_map[w]];
if (DEBUG) std::cout << " Updating idom[" << w->getName() << "] to idom(idom(w)): "
<< idom_map[w]->getName() << std::endl;
} else {
if (DEBUG) std::cout << " Warning: idom(idom(" << w->getName() << ")) not found, leaving idom[" << w->getName() << "] as is." << std::endl;
}
}
if (DEBUG) {
std::cout << " Final IDom[" << w->getName() << "] = " << (idom_map[w] ? idom_map[w]->getName() : "nullptr") << std::endl;
}
}
// 将计算结果从 idom_map 存储到 DominatorTree 的成员变量 IDoms 中
IDoms = idom_map;
if (DEBUG) std::cout << "--- Immediate Dominators Computation Finished ---" << std::endl;
}
// ==============================================================
// computeDominanceFrontiers 和 computeDominatorTreeChildren (保持不变)
// ==============================================================
void DominatorTree::computeDominanceFrontiers(Function *F) {
// 经典的支配边界计算算法
if (DEBUG)
std::cout << "--- Computing Dominance Frontiers ---" << std::endl;
for (const auto &bb_ptr_X : F->getBasicBlocks()) {
BasicBlock *X = bb_ptr_X.get();
DominanceFrontiers[X].clear();
for (BasicBlock *Y : X->getSuccessors()) {
const std::set<BasicBlock *> *domsOfY = getDominators(Y);
if (domsOfY && domsOfY->find(X) == domsOfY->end()) {
DominanceFrontiers[X].insert(Y);
}
}
const std::set<BasicBlock *> *domsOfX = getDominators(X);
if (!domsOfX)
continue;
for (const auto &bb_ptr_Z : F->getBasicBlocks()) {
BasicBlock *Z = bb_ptr_Z.get();
if (Z == X)
continue;
const std::set<BasicBlock *> *domsOfZ = getDominators(Z);
if (domsOfZ && domsOfZ->count(X) && Z != X) {
for (BasicBlock *Y : Z->getSuccessors()) {
const std::set<BasicBlock *> *domsOfY = getDominators(Y);
if (domsOfY && domsOfY->find(X) == domsOfY->end()) {
DominanceFrontiers[X].insert(Y);
}
if (!domsOfZ || domsOfZ->find(X) == domsOfZ->end()) { // Z 不被 X 支配
continue;
}
for (BasicBlock *Y : Z->getSuccessors()) {
const std::set<BasicBlock *> *domsOfY = getDominators(Y);
// 如果 Y == X或者 Y 不被 X 严格支配 (即 Y 不被 X 支配)
if (Y == X || (domsOfY && domsOfY->find(X) == domsOfY->end())) {
DominanceFrontiers[X].insert(Y);
}
}
}
if (DEBUG) {
std::cout << " DF(" << X->getName() << "): ";
printBBSet("", DominanceFrontiers[X]);
}
}
if (DEBUG)
std::cout << "--- Dominance Frontiers Computation Finished ---" << std::endl;
}
void DominatorTree::computeDominatorTreeChildren(Function *F) {
if (DEBUG)
std::cout << "--- Computing Dominator Tree Children ---" << std::endl;
// 首先清空,确保重新计算时是空的
for (auto &bb_ptr : F->getBasicBlocks()) {
DominatorTreeChildren[bb_ptr.get()].clear();
}
for (auto &bb_ptr : F->getBasicBlocks()) {
BasicBlock *B = bb_ptr.get();
auto it = getImmediateDominator(B);
if (it != nullptr) {
BasicBlock *A = it;
if (A) {
DominatorTreeChildren[A].insert(B);
BasicBlock *A = getImmediateDominator(B); // A 是 B 的即时支配者
if (A) { // 如果 B 有即时支配者 A (即 B 不是入口块)
DominatorTreeChildren[A].insert(B);
if (DEBUG) {
std::cout << " " << B->getName() << " is child of " << A->getName() << std::endl;
}
}
}
if (DEBUG)
std::cout << "--- Dominator Tree Children Computation Finished ---" << std::endl;
}
// ==============================================================
// DominatorTreeAnalysisPass 的实现
// DominatorTreeAnalysisPass 的实现 (保持不变)
// ==============================================================
bool DominatorTreeAnalysisPass::runOnFunction(Function* F, AnalysisManager &AM) {
bool DominatorTreeAnalysisPass::runOnFunction(Function *F, AnalysisManager &AM) {
// 每次运行时清空旧数据,确保重新计算
CurrentDominatorTree = std::make_unique<DominatorTree>(F);
CurrentDominatorTree->computeDominators(F);
CurrentDominatorTree->computeIDoms(F);
CurrentDominatorTree->computeIDoms(F); // 修正后的LT算法
CurrentDominatorTree->computeDominanceFrontiers(F);
CurrentDominatorTree->computeDominatorTreeChildren(F);
return false;
}
std::unique_ptr<AnalysisResultBase> DominatorTreeAnalysisPass::getResult() {
// 返回计算好的 DominatorTree 实例,所有权转移给 AnalysisManager
return std::move(CurrentDominatorTree);
}

View 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

View File

@ -0,0 +1,813 @@
#include "LoopCharacteristics.h"
#include "Dom.h"
#include "Loop.h"
#include "Liveness.h"
#include "AliasAnalysis.h"
#include "SideEffectAnalysis.h"
#include <iostream>
#include <cmath>
// 使用全局调试开关
extern int DEBUG;
namespace sysy {
// 定义 Pass 的唯一 ID
void *LoopCharacteristicsPass::ID = (void *)&LoopCharacteristicsPass::ID;
void LoopCharacteristicsResult::print() const {
if (!DEBUG) return;
std::cout << "\n--- Loop Characteristics Analysis Results for Function: "
<< AssociatedFunction->getName() << " ---" << std::endl;
if (CharacteristicsMap.empty()) {
std::cout << " No loop characteristics found." << std::endl;
return;
}
// 打印统计信息
auto stats = getOptimizationStats();
std::cout << "\n=== Basic Loop Characteristics Statistics ===" << std::endl;
std::cout << "Total Loops: " << stats.totalLoops << std::endl;
std::cout << "Counting Loops: " << stats.countingLoops << std::endl;
std::cout << "Unrolling Candidates: " << stats.unrollingCandidates << std::endl;
std::cout << "Pure Loops: " << stats.pureLoops << std::endl;
std::cout << "Local Memory Only Loops: " << stats.localMemoryOnlyLoops << std::endl;
std::cout << "No Alias Conflict Loops: " << stats.noAliasConflictLoops << std::endl;
std::cout << "Avg Instructions per Loop: " << stats.avgInstructionCount << std::endl;
std::cout << "Avg Compute/Memory Ratio: " << stats.avgComputeMemoryRatio << std::endl;
// 按热度排序并打印循环特征
auto loopsByHotness = getLoopsByHotness();
std::cout << "\n=== Loop Characteristics (by hotness) ===" << std::endl;
for (auto* loop : loopsByHotness) {
auto* chars = getCharacteristics(loop);
if (!chars) continue;
std::cout << "\n--- Loop: " << loop->getName() << " (Hotness: "
<< loop->getLoopHotness() << ") ---" << std::endl;
std::cout << " Level: " << loop->getLoopLevel() << std::endl;
std::cout << " Blocks: " << loop->getLoopSize() << std::endl;
std::cout << " Instructions: " << chars->instructionCount << std::endl;
std::cout << " Memory Operations: " << chars->memoryOperationCount << std::endl;
std::cout << " Compute/Memory Ratio: " << chars->computeToMemoryRatio << std::endl;
// 循环形式
std::cout << " Form: ";
if (chars->isCountingLoop) std::cout << "Counting ";
if (chars->isSimpleForLoop) std::cout << "SimpleFor ";
if (chars->isInnermost) std::cout << "Innermost ";
if (chars->hasComplexControlFlow) std::cout << "Complex ";
if (chars->isPure) std::cout << "Pure ";
if (chars->accessesOnlyLocalMemory) std::cout << "LocalMemOnly ";
if (chars->hasNoMemoryAliasConflicts) std::cout << "NoAliasConflicts ";
std::cout << std::endl;
// 边界信息
if (chars->staticTripCount.has_value()) {
std::cout << " Static Trip Count: " << *chars->staticTripCount << std::endl;
}
if (chars->hasKnownBounds) {
std::cout << " Has Known Bounds: Yes" << std::endl;
}
// 优化机会
std::cout << " Optimization Opportunities: ";
if (chars->benefitsFromUnrolling)
std::cout << "Unroll(factor=" << chars->suggestedUnrollFactor << ") ";
std::cout << std::endl;
// 归纳变量
if (!chars->InductionVars.empty()) {
std::cout << " Induction Vars: " << chars->InductionVars.size() << std::endl;
}
// 循环不变量
if (!chars->loopInvariants.empty()) {
std::cout << " Loop Invariants: " << chars->loopInvariants.size() << std::endl;
}
if (!chars->invariantInsts.empty()) {
std::cout << " Hoistable Instructions: " << chars->invariantInsts.size() << std::endl;
}
}
std::cout << "-----------------------------------------------" << std::endl;
}
bool LoopCharacteristicsPass::runOnFunction(Function *F, AnalysisManager &AM) {
if (F->getBasicBlocks().empty()) {
CurrentResult = std::make_unique<LoopCharacteristicsResult>(F);
return false; // 空函数
}
if (DEBUG)
std::cout << "Running LoopCharacteristicsPass on function: " << F->getName() << std::endl;
// 获取并缓存所有需要的分析结果
loopAnalysis = AM.getAnalysisResult<LoopAnalysisResult, LoopAnalysisPass>(F);
if (!loopAnalysis) {
std::cerr << "Error: LoopAnalysisResult not available for function " << F->getName() << std::endl;
CurrentResult = std::make_unique<LoopCharacteristicsResult>(F);
return false;
}
// 如果没有循环,直接返回
if (!loopAnalysis->hasLoops()) {
CurrentResult = std::make_unique<LoopCharacteristicsResult>(F);
return false;
}
// 获取别名分析和副作用分析结果并缓存
aliasAnalysis = AM.getAnalysisResult<AliasAnalysisResult, SysYAliasAnalysisPass>(F);
sideEffectAnalysis = AM.getAnalysisResult<SideEffectAnalysisResult, SysYSideEffectAnalysisPass>();
if (DEBUG) {
if (aliasAnalysis) std::cout << "LoopCharacteristics: Using alias analysis results" << std::endl;
if (sideEffectAnalysis) std::cout << "LoopCharacteristics: Using side effect analysis results" << std::endl;
}
CurrentResult = std::make_unique<LoopCharacteristicsResult>(F);
// 分析每个循环的特征 - 现在不需要传递分析结果参数
for (const auto& loop_ptr : loopAnalysis->getAllLoops()) {
Loop* loop = loop_ptr.get();
auto characteristics = std::make_unique<LoopCharacteristics>(loop);
// 执行各种特征分析,使用缓存的分析结果
analyzeLoop(loop, characteristics.get());
// 添加到结果中
CurrentResult->addLoopCharacteristics(std::move(characteristics));
}
if (DEBUG) {
std::cout << "LoopCharacteristicsPass completed for function: " << F->getName() << std::endl;
auto stats = CurrentResult->getOptimizationStats();
std::cout << "Analyzed " << stats.totalLoops << " loops, found "
<< stats.countingLoops << " counting loops, "
<< stats.unrollingCandidates << " unroll candidates" << std::endl;
}
return false; // 特征分析不修改IR
}
void LoopCharacteristicsPass::analyzeLoop(Loop* loop, LoopCharacteristics* characteristics) {
if (DEBUG)
std::cout << " Analyzing basic characteristics of loop: " << loop->getName() << std::endl;
// 按顺序执行基础分析 - 现在使用缓存的分析结果
computePerformanceMetrics(loop, characteristics);
analyzeLoopForm(loop, characteristics);
analyzePurityAndSideEffects(loop, characteristics);
identifyBasicInductionVariables(loop, characteristics);
identifyBasicLoopInvariants(loop, characteristics);
analyzeBasicLoopBounds(loop, characteristics);
analyzeBasicMemoryAccessPatterns(loop, characteristics);
evaluateBasicOptimizationOpportunities(loop, characteristics);
}
void LoopCharacteristicsPass::computePerformanceMetrics(Loop* loop, LoopCharacteristics* characteristics) {
size_t totalInsts = 0;
size_t memoryOps = 0;
size_t arithmeticOps = 0;
// 遍历循环中的所有指令
for (BasicBlock* bb : loop->getBlocks()) {
for (auto& inst : bb->getInstructions()) {
totalInsts++;
// 分类指令类型
if (dynamic_cast<LoadInst*>(inst.get()) || dynamic_cast<StoreInst*>(inst.get())) {
memoryOps++;
} else if (dynamic_cast<BinaryInst*>(inst.get())) {
// 检查是否为算术运算
auto* binInst = dynamic_cast<BinaryInst*>(inst.get());
// 简化:假设所有二元运算都是算术运算
arithmeticOps++;
}
}
}
characteristics->instructionCount = totalInsts;
characteristics->memoryOperationCount = memoryOps;
characteristics->arithmeticOperationCount = arithmeticOps;
// 计算计算与内存操作比率
if (memoryOps > 0) {
characteristics->computeToMemoryRatio = static_cast<double>(arithmeticOps) / memoryOps;
} else {
characteristics->computeToMemoryRatio = arithmeticOps; // 纯计算循环
}
}
void LoopCharacteristicsPass::analyzeLoopForm(Loop* loop, LoopCharacteristics* characteristics) {
// 基本形式判断
characteristics->isInnermost = loop->isInnermost();
// 检查是否为简单循环 (只有一个回边)
bool isSimple = loop->isSimpleLoop();
characteristics->isSimpleForLoop = isSimple;
// 检查复杂控制流 (多个出口表示可能有break/continue)
auto exitingBlocks = loop->getExitingBlocks();
characteristics->hasComplexControlFlow = exitingBlocks.size() > 1;
// 初步判断是否为计数循环 (需要更复杂的分析)
// 简化版本:如果是简单循环且是最内层,很可能是计数循环
characteristics->isCountingLoop = isSimple && loop->isInnermost() && exitingBlocks.size() == 1;
}
void LoopCharacteristicsPass::analyzePurityAndSideEffects(Loop* loop, LoopCharacteristics* characteristics) {
if (!sideEffectAnalysis) {
// 没有副作用分析结果,保守处理
characteristics->isPure = false;
return;
}
// 检查循环是否有副作用
characteristics->isPure = !loop->mayHaveSideEffects(sideEffectAnalysis);
if (DEBUG && characteristics->isPure) {
std::cout << " Loop " << loop->getName() << " is identified as PURE (no side effects)" << std::endl;
}
}
void LoopCharacteristicsPass::analyzeBasicMemoryAccessPatterns(Loop* loop, LoopCharacteristics* characteristics) {
if (!aliasAnalysis) {
// 没有别名分析结果,保守处理
characteristics->accessesOnlyLocalMemory = false;
characteristics->hasNoMemoryAliasConflicts = false;
return;
}
// 检查是否只访问局部内存
characteristics->accessesOnlyLocalMemory = !loop->accessesGlobalMemory(aliasAnalysis);
// 检查是否有内存别名冲突
characteristics->hasNoMemoryAliasConflicts = !loop->hasMemoryAliasConflicts(aliasAnalysis);
if (DEBUG) {
if (characteristics->accessesOnlyLocalMemory) {
std::cout << " Loop " << loop->getName() << " accesses ONLY LOCAL MEMORY" << std::endl;
}
if (characteristics->hasNoMemoryAliasConflicts) {
std::cout << " Loop " << loop->getName() << " has NO MEMORY ALIAS CONFLICTS" << std::endl;
}
}
// 分析基础的内存访问模式
for (BasicBlock* bb : loop->getBlocks()) {
for (auto& inst : bb->getInstructions()) {
if (auto* loadInst = dynamic_cast<LoadInst*>(inst.get())) {
Value* ptr = loadInst->getPointer();
auto& pattern = characteristics->memoryPatterns[ptr];
pattern.loadInsts.push_back(loadInst);
pattern.isArrayParameter = aliasAnalysis->isFunctionParameter(ptr);
pattern.isGlobalArray = aliasAnalysis->isGlobalArray(ptr);
pattern.hasConstantIndices = aliasAnalysis->hasConstantAccess(ptr);
} else if (auto* storeInst = dynamic_cast<StoreInst*>(inst.get())) {
Value* ptr = storeInst->getPointer();
auto& pattern = characteristics->memoryPatterns[ptr];
pattern.storeInsts.push_back(storeInst);
pattern.isArrayParameter = aliasAnalysis->isFunctionParameter(ptr);
pattern.isGlobalArray = aliasAnalysis->isGlobalArray(ptr);
pattern.hasConstantIndices = aliasAnalysis->hasConstantAccess(ptr);
}
}
}
}
bool LoopCharacteristicsPass::isBasicInductionVariable(Value* val, Loop* loop) {
// 简化的基础归纳变量检测
auto* phiInst = dynamic_cast<PhiInst*>(val);
if (!phiInst) return false;
// 检查phi指令是否在循环头
if (phiInst->getParent() != loop->getHeader()) return false;
// 检查是否有来自循环内的更新
for (auto& [incomingBB, incomingVal] : phiInst->getIncomingValues()) {
if (loop->contains(incomingBB)) {
return true; // 简化:有来自循环内的值就认为是基础归纳变量
}
}
return false;
}
void LoopCharacteristicsPass::identifyBasicInductionVariables(
Loop* loop, LoopCharacteristics* characteristics) {
BasicBlock* header = loop->getHeader();
std::vector<std::unique_ptr<InductionVarInfo>> ivs;
if (DEBUG) {
std::cout << " === Identifying Induction Variables for Loop: " << loop->getName() << " ===" << std::endl;
std::cout << " Loop header: " << header->getName() << std::endl;
std::cout << " Loop blocks: ";
for (auto* bb : loop->getBlocks()) {
std::cout << bb->getName() << " ";
}
std::cout << std::endl;
}
// 1. 识别所有BIV
for (auto& inst : header->getInstructions()) {
auto* phi = dynamic_cast<PhiInst*>(inst.get());
if (!phi) continue;
if (isBasicInductionVariable(phi, loop)) {
ivs.push_back(InductionVarInfo::createBasicBIV(phi, Instruction::Kind::kPhi, phi));
if (DEBUG) {
std::cout << " [BIV] Found basic induction variable: " << phi->getName() << std::endl;
std::cout << " Incoming values: ";
for (auto& [incomingBB, incomingVal] : phi->getIncomingValues()) {
std::cout << "{" << incomingBB->getName() << ": " << incomingVal->getName() << "} ";
}
std::cout << std::endl;
}
}
}
if (DEBUG) {
std::cout << " Found " << ivs.size() << " basic induction variables" << std::endl;
}
// 2. 递归识别所有派生DIV
std::set<Value*> visited;
size_t initialSize = ivs.size();
// 保存初始的BIV列表避免在遍历过程中修改向量导致迭代器失效
std::vector<InductionVarInfo*> bivList;
for (size_t i = 0; i < initialSize; ++i) {
if (ivs[i] && ivs[i]->ivkind == IVKind::kBasic) {
bivList.push_back(ivs[i].get());
}
}
for (auto* biv : bivList) {
if (DEBUG) {
if (biv && biv->div) {
std::cout << " Searching for derived IVs from BIV: " << biv->div->getName() << std::endl;
} else {
std::cout << " ERROR: Invalid BIV pointer or div field is null" << std::endl;
continue;
}
}
findDerivedInductionVars(biv->div, biv->base, loop, ivs, visited);
}
if (DEBUG) {
size_t derivedCount = ivs.size() - initialSize;
std::cout << " Found " << derivedCount << " derived induction variables" << std::endl;
// 打印所有归纳变量的详细信息
std::cout << " === Final Induction Variables Summary ===" << std::endl;
for (size_t i = 0; i < ivs.size(); ++i) {
const auto& iv = ivs[i];
std::cout << " [" << i << "] " << iv->div->getName()
<< " (kind: " << (iv->ivkind == IVKind::kBasic ? "Basic" :
iv->ivkind == IVKind::kLinear ? "Linear" : "Complex") << ")" << std::endl;
std::cout << " Operation: " << static_cast<int>(iv->Instkind) << std::endl;
if (iv->base) {
std::cout << " Base: " << iv->base->getName() << std::endl;
}
if (iv->Multibase.first || iv->Multibase.second) {
std::cout << " Multi-base: ";
if (iv->Multibase.first) std::cout << iv->Multibase.first->getName() << " ";
if (iv->Multibase.second) std::cout << iv->Multibase.second->getName() << " ";
std::cout << std::endl;
}
std::cout << " Factor: " << iv->factor << ", Offset: " << iv->offset << std::endl;
std::cout << " Valid: " << (iv->valid ? "Yes" : "No") << std::endl;
}
std::cout << " =============================================" << std::endl;
}
characteristics->InductionVars = std::move(ivs);
}
struct LinearExpr {
// 表达为: a * base1 + b * base2 + offset
Value* base1 = nullptr;
Value* base2 = nullptr;
int factor1 = 0;
int factor2 = 0;
int offset = 0;
bool valid = false;
bool isSimple = false; // 仅一个BIV时true
};
static LinearExpr analyzeLinearExpr(Value* val, Loop* loop, std::vector<std::unique_ptr<InductionVarInfo>>& ivs) {
// 递归归约val为线性表达式
// 只支持单/双BIV线性组合
// 见下方详细实现
// ----------
if (DEBUG >= 2) { // 更详细的调试级别
if (auto* inst = dynamic_cast<Instruction*>(val)) {
std::cout << " Analyzing linear expression for: " << val->getName()
<< " (kind: " << static_cast<int>(inst->getKind()) << ")" << std::endl;
} else {
std::cout << " Analyzing linear expression for value: " << val->getName() << std::endl;
}
}
// 基本变量:常数
if (auto* cint = dynamic_cast<ConstantInteger*>(val)) {
if (DEBUG >= 2) {
std::cout << " -> Constant: " << cint->getInt() << std::endl;
}
return {nullptr, nullptr, 0, 0, cint->getInt(), true, false};
}
// 基本变量BIV或派生IV
for (auto& iv : ivs) {
if (iv->div == val) {
if (iv->ivkind == IVKind::kBasic ||
iv->ivkind == IVKind::kLinear) {
if (DEBUG >= 2) {
std::cout << " -> Found " << (iv->ivkind == IVKind::kBasic ? "Basic" : "Linear")
<< " IV with base: " << (iv->base ? iv->base->getName() : "null")
<< ", factor: " << iv->factor << ", offset: " << iv->offset << std::endl;
}
return {iv->base, nullptr, iv->factor, 0, iv->offset, true, true};
}
// 复杂归纳变量
if (iv->ivkind == IVKind::kCmplx) {
if (DEBUG >= 2) {
std::cout << " -> Found Complex IV with multi-base" << std::endl;
}
return {iv->Multibase.first, iv->Multibase.second, 1, 1, 0, true, false};
}
}
}
// 一元负号
if (auto* inst = dynamic_cast<Instruction*>(val)) {
auto kind = inst->getKind();
if (kind == Instruction::Kind::kNeg) {
if (DEBUG >= 2) {
std::cout << " -> Analyzing negation" << std::endl;
}
auto expr = analyzeLinearExpr(inst->getOperand(0), loop, ivs);
if (!expr.valid) return expr;
expr.factor1 = -expr.factor1;
expr.factor2 = -expr.factor2;
expr.offset = -expr.offset;
expr.isSimple = (expr.base2 == nullptr);
if (DEBUG >= 2) {
std::cout << " -> Negation result: valid=" << expr.valid << ", simple=" << expr.isSimple << std::endl;
}
return expr;
}
// 二元加减乘
if (kind == Instruction::Kind::kAdd || kind == Instruction::Kind::kSub) {
if (DEBUG >= 2) {
std::cout << " -> Analyzing " << (kind == Instruction::Kind::kAdd ? "addition" : "subtraction") << std::endl;
}
auto expr0 = analyzeLinearExpr(inst->getOperand(0), loop, ivs);
auto expr1 = analyzeLinearExpr(inst->getOperand(1), loop, ivs);
if (!expr0.valid || !expr1.valid) {
if (DEBUG >= 2) {
std::cout << " -> Failed: operand not linear (expr0.valid=" << expr0.valid << ", expr1.valid=" << expr1.valid << ")" << std::endl;
}
return {nullptr, nullptr, 0, 0, 0, false, false};
}
// 合并若BIV相同或有一个是常数
// 单BIV+常数
if (expr0.base1 && !expr1.base1 && !expr1.base2) {
int sign = (kind == Instruction::Kind::kAdd ? 1 : -1);
if (DEBUG >= 2) {
std::cout << " -> Single BIV + constant pattern" << std::endl;
}
return {expr0.base1, nullptr, expr0.factor1, 0, expr0.offset + sign * expr1.offset, true, expr0.isSimple};
}
if (!expr0.base1 && !expr0.base2 && expr1.base1) {
int sign = (kind == Instruction::Kind::kAdd ? 1 : -1);
int f = sign * expr1.factor1;
int off = expr0.offset + sign * expr1.offset;
if (DEBUG >= 2) {
std::cout << " -> Constant + single BIV pattern" << std::endl;
}
return {expr1.base1, nullptr, f, 0, off, true, expr1.isSimple};
}
// 双BIV线性组合
if (expr0.base1 && expr1.base1 && expr0.base1 != expr1.base1 && !expr0.base2 && !expr1.base2) {
int sign = (kind == Instruction::Kind::kAdd ? 1 : -1);
Value* base1 = expr0.base1;
Value* base2 = expr1.base1;
int f1 = expr0.factor1;
int f2 = sign * expr1.factor1;
int off = expr0.offset + sign * expr1.offset;
if (DEBUG >= 2) {
std::cout << " -> Double BIV linear combination" << std::endl;
}
return {base1, base2, f1, f2, off, true, false};
}
// 同BIV合并
if (expr0.base1 && expr1.base1 && expr0.base1 == expr1.base1 && !expr0.base2 && !expr1.base2) {
int sign = (kind == Instruction::Kind::kAdd ? 1 : -1);
int f = expr0.factor1 + sign * expr1.factor1;
int off = expr0.offset + sign * expr1.offset;
if (DEBUG >= 2) {
std::cout << " -> Same BIV combination" << std::endl;
}
return {expr0.base1, nullptr, f, 0, off, true, true};
}
}
// 乘法BIV*const 或 const*BIV
if (kind == Instruction::Kind::kMul) {
if (DEBUG >= 2) {
std::cout << " -> Analyzing multiplication" << std::endl;
}
auto expr0 = analyzeLinearExpr(inst->getOperand(0), loop, ivs);
auto expr1 = analyzeLinearExpr(inst->getOperand(1), loop, ivs);
// 只允许一侧为常数
if (expr0.base1 && !expr1.base1 && !expr1.base2 && expr1.offset) {
if (DEBUG >= 2) {
std::cout << " -> BIV * constant pattern" << std::endl;
}
return {expr0.base1, nullptr, expr0.factor1 * expr1.offset, 0, expr0.offset * expr1.offset, true, true};
}
if (!expr0.base1 && !expr0.base2 && expr0.offset && expr1.base1) {
if (DEBUG >= 2) {
std::cout << " -> Constant * BIV pattern" << std::endl;
}
return {expr1.base1, nullptr, expr1.factor1 * expr0.offset, 0, expr1.offset * expr0.offset, true, true};
}
// 双BIV乘法不支持
if (DEBUG >= 2) {
std::cout << " -> Multiplication pattern not supported" << std::endl;
}
}
// 除法BIV/const仅当const是2的幂时
if (kind == Instruction::Kind::kDiv) {
if (DEBUG >= 2) {
std::cout << " -> Analyzing division" << std::endl;
}
auto expr0 = analyzeLinearExpr(inst->getOperand(0), loop, ivs);
auto expr1 = analyzeLinearExpr(inst->getOperand(1), loop, ivs);
// 只支持 BIV / 2^n 形式
if (expr0.base1 && !expr1.base1 && !expr1.base2 && expr1.offset > 0) {
// 检查是否为2的幂
int divisor = expr1.offset;
if ((divisor & (divisor - 1)) == 0) { // 2的幂检查
if (DEBUG >= 2) {
std::cout << " -> BIV / power_of_2 pattern (divisor=" << divisor << ")" << std::endl;
}
// 对于除法,我们记录为特殊的归纳变量模式
// factor表示除数用于后续强度削弱
return {expr0.base1, nullptr, -divisor, 0, expr0.offset / divisor, true, true};
}
}
if (DEBUG >= 2) {
std::cout << " -> Division pattern not supported (not power of 2)" << std::endl;
}
}
// 取模BIV % const仅当const是2的幂时
if (kind == Instruction::Kind::kRem) {
if (DEBUG >= 2) {
std::cout << " -> Analyzing remainder" << std::endl;
}
auto expr0 = analyzeLinearExpr(inst->getOperand(0), loop, ivs);
auto expr1 = analyzeLinearExpr(inst->getOperand(1), loop, ivs);
// 只支持 BIV % 2^n 形式
if (expr0.base1 && !expr1.base1 && !expr1.base2 && expr1.offset > 0) {
// 检查是否为2的幂
int modulus = expr1.offset;
if ((modulus & (modulus - 1)) == 0) { // 2的幂检查
if (DEBUG >= 2) {
std::cout << " -> BIV % power_of_2 pattern (modulus=" << modulus << ")" << std::endl;
}
// 对于取模,我们记录为特殊的归纳变量模式
// 使用负的模数来区分取模和除法
return {expr0.base1, nullptr, -10000 - modulus, 0, 0, true, true}; // 特殊标记
}
}
if (DEBUG >= 2) {
std::cout << " -> Remainder pattern not supported (not power of 2)" << std::endl;
}
}
}
// 其它情况
if (DEBUG >= 2) {
std::cout << " -> Other case: not linear" << std::endl;
}
return {nullptr, nullptr, 0, 0, 0, false, false};
}
void LoopCharacteristicsPass::identifyBasicLoopInvariants(Loop* loop, LoopCharacteristics* characteristics) {
// 经典推进法:反复遍历,直到收敛 TODO优化
bool changed;
std::unordered_set<Value*> invariants = characteristics->loopInvariants; // 可能为空
do {
changed = false;
for (BasicBlock* bb : loop->getBlocks()) {
for (auto& inst : bb->getInstructions()) {
Instruction* I = inst.get();
// 跳过phi和terminator
if (dynamic_cast<PhiInst*>(I)) continue;
if (I->isTerminator()) continue;
if (invariants.count(I)) continue;
if (isClassicLoopInvariant(I, loop, invariants)) {
invariants.insert(I);
characteristics->invariantInsts.insert(I);
if (DEBUG)
std::cout << " Found loop invariant: " << I->getName() << std::endl;
changed = true;
}
}
}
} while (changed);
characteristics->loopInvariants = std::move(invariants);
}
void LoopCharacteristicsPass::analyzeBasicLoopBounds(Loop* loop, LoopCharacteristics* characteristics) {
// 简化的基础边界分析
// 检查是否有静态可确定的循环次数(简化版本)
if (characteristics->isCountingLoop && !characteristics->InductionVars.empty()) {
// 简化:如果是计数循环且有基本归纳变量,尝试确定循环次数
if (characteristics->instructionCount < 10) {
characteristics->staticTripCount = 100; // 简化估计
characteristics->hasKnownBounds = true;
if (DEBUG) {
std::cout << " Estimated static trip count: " << *characteristics->staticTripCount << std::endl;
}
}
}
}
void LoopCharacteristicsPass::evaluateBasicOptimizationOpportunities(Loop* loop, LoopCharacteristics* characteristics) {
// 评估基础循环展开机会
characteristics->benefitsFromUnrolling =
characteristics->isInnermost &&
characteristics->instructionCount > 3 &&
characteristics->instructionCount < 50 &&
!characteristics->hasComplexControlFlow;
if (characteristics->benefitsFromUnrolling) {
// 基于循环体大小估算展开因子
if (characteristics->instructionCount <= 5) characteristics->suggestedUnrollFactor = 8;
else if (characteristics->instructionCount <= 10) characteristics->suggestedUnrollFactor = 4;
else if (characteristics->instructionCount <= 20) characteristics->suggestedUnrollFactor = 2;
else characteristics->suggestedUnrollFactor = 1;
}
if (DEBUG) {
if (characteristics->benefitsFromUnrolling) {
std::cout << " Loop " << loop->getName() << " benefits from UNROLLING (factor="
<< characteristics->suggestedUnrollFactor << ")" << std::endl;
}
}
}
// ========== 辅助方法实现 ==========
// 递归识别DIV支持线性与复杂归纳变量
void LoopCharacteristicsPass::findDerivedInductionVars(
Value* root,
Value* base, // 只传单一BIV base
Loop* loop,
std::vector<std::unique_ptr<InductionVarInfo>>& ivs,
std::set<Value*>& visited)
{
if (visited.count(root)) return;
visited.insert(root);
if (DEBUG) {
std::cout << " Analyzing uses of: " << root->getName() << std::endl;
}
for (auto use : root->getUses()) {
auto user = use->getUser();
Instruction* inst = dynamic_cast<Instruction*>(user);
if (!inst) continue;
if (!loop->contains(inst->getParent())) {
if (DEBUG) {
std::cout << " Skipping user outside loop: " << inst->getName() << std::endl;
}
continue;
}
if (DEBUG) {
std::cout << " Checking instruction: " << inst->getName()
<< " (kind: " << static_cast<int>(inst->getKind()) << ")" << std::endl;
}
// 线性归约分析
auto expr = analyzeLinearExpr(inst, loop, ivs);
if (!expr.valid) {
if (DEBUG) {
std::cout << " Linear expression analysis failed for: " << inst->getName() << std::endl;
}
// 复杂非线性归纳变量作为kCmplx记录假如你想追踪
// 这里假设expr.base1、base2都有效才记录double
if (expr.base1 && expr.base2) {
if (DEBUG) {
std::cout << " [DIV-COMPLEX] Creating complex derived IV: " << inst->getName()
<< " with bases: " << expr.base1->getName() << ", " << expr.base2->getName() << std::endl;
}
ivs.push_back(InductionVarInfo::createDoubleDIV(inst, inst->getKind(), expr.base1, expr.base2, 0, expr.offset));
}
continue;
}
// 单BIV线性
if (expr.base1 && !expr.base2) {
// 检查这个指令是否已经是一个已知的IV特别是BIV避免重复创建
bool alreadyExists = false;
for (const auto& existingIV : ivs) {
if (existingIV->div == inst) {
alreadyExists = true;
if (DEBUG) {
std::cout << " [DIV-SKIP] Instruction " << inst->getName()
<< " already exists as IV, skipping creation" << std::endl;
}
break;
}
}
if (!alreadyExists) {
if (DEBUG) {
std::cout << " [DIV-LINEAR] Creating single-base derived IV: " << inst->getName()
<< " with base: " << expr.base1->getName()
<< ", factor: " << expr.factor1
<< ", offset: " << expr.offset << std::endl;
}
ivs.push_back(InductionVarInfo::createSingleDIV(inst, inst->getKind(), expr.base1, expr.factor1, expr.offset));
findDerivedInductionVars(inst, expr.base1, loop, ivs, visited);
}
}
// 双BIV线性
else if (expr.base1 && expr.base2) {
if (DEBUG) {
std::cout << " [DIV-COMPLEX] Creating double-base derived IV: " << inst->getName()
<< " with bases: " << expr.base1->getName() << ", " << expr.base2->getName()
<< ", offset: " << expr.offset << std::endl;
}
ivs.push_back(InductionVarInfo::createDoubleDIV(inst, inst->getKind(), expr.base1, expr.base2, 0, expr.offset));
// 双BIV情形一般不再递归下游
}
}
if (DEBUG) {
std::cout << " Finished analyzing uses of: " << root->getName() << std::endl;
}
}
// 递归/推进式判定
bool LoopCharacteristicsPass::isClassicLoopInvariant(Value* val, Loop* loop, const std::unordered_set<Value*>& invariants) {
// 1. 常量
if (auto* constval = dynamic_cast<ConstantValue*>(val)) return true;
// 2. 参数函数参数通常不在任何BasicBlock内直接判定为不变量
if (auto* arg = dynamic_cast<Argument*>(val)) return true;
// 3. 指令且定义在循环外
if (auto* inst = dynamic_cast<Instruction*>(val)) {
if (!loop->contains(inst->getParent()))
return true;
// 4. 跳转 phi指令 副作用 不外提
if (inst->isTerminator() || inst->isPhi() || sideEffectAnalysis->hasSideEffect(inst))
return false;
// 5. 所有操作数都是不变量
for (size_t i = 0; i < inst->getNumOperands(); ++i) {
Value* op = inst->getOperand(i);
if (!isClassicLoopInvariant(op, loop, invariants) && !invariants.count(op))
return false;
}
return true;
}
// 其它情况
return false;
}
bool LoopCharacteristicsPass::hasSimpleMemoryPattern(Loop* loop) {
// 检查是否有简单的内存访问模式
return true; // 暂时简化处理
}
} // namespace sysy

View 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

View File

@ -0,0 +1,402 @@
#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;
}
// 返回默认的无副作用信息
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

View File

@ -0,0 +1,79 @@
#include "BuildCFG.h"
#include "Dom.h"
#include "Liveness.h"
#include <iostream>
#include <queue>
#include <set>
namespace sysy {
void *BuildCFG::ID = (void *)&BuildCFG::ID; // 定义唯一的 Pass ID
// 声明Pass的分析使用
void BuildCFG::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
// BuildCFG不依赖其他分析
// analysisDependencies.insert(&DominatorTreeAnalysisPass::ID); // 错误的例子
// BuildCFG会使所有依赖于CFG的分析结果失效所以它必须声明这些失效
analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID);
analysisInvalidations.insert(&LivenessAnalysisPass::ID);
}
bool BuildCFG::runOnFunction(Function *F, AnalysisManager &AM) {
if (DEBUG) {
std::cout << "Running BuildCFG pass on function: " << F->getName() << std::endl;
}
bool changed = false;
// 1. 清空所有基本块的前驱和后继列表
for (auto &bb : F->getBasicBlocks()) {
bb->clearPredecessors();
bb->clearSuccessors();
}
// 2. 遍历每个基本块重建CFG
for (auto &bb : F->getBasicBlocks()) {
// 获取基本块的最后一条指令
auto &inst = *bb->terminator();
Instruction *termInst = inst.get();
// 确保基本块有终结指令
if (!termInst) {
continue;
}
// 根据终结指令类型,建立前驱后继关系
if (termInst->isBranch()) {
// 无条件跳转
if (termInst->isUnconditional()) {
auto brInst = dynamic_cast<UncondBrInst *>(termInst);
BasicBlock *succ = dynamic_cast<BasicBlock *>(brInst->getBlock());
assert(succ && "Branch instruction's target must be a BasicBlock");
bb->addSuccessor(succ);
succ->addPredecessor(bb.get());
changed = true;
// 条件跳转
} else if (termInst->isConditional()) {
auto brInst = dynamic_cast<CondBrInst *>(termInst);
BasicBlock *trueSucc = dynamic_cast<BasicBlock *>(brInst->getThenBlock());
BasicBlock *falseSucc = dynamic_cast<BasicBlock *>(brInst->getElseBlock());
assert(trueSucc && falseSucc && "Branch instruction's targets must be BasicBlocks");
bb->addSuccessor(trueSucc);
trueSucc->addPredecessor(bb.get());
bb->addSuccessor(falseSucc);
falseSucc->addPredecessor(bb.get());
changed = true;
}
} else if (auto retInst = dynamic_cast<ReturnInst *>(termInst)) {
// RetInst没有后继无需处理
// ...
}
}
return changed;
}
} // namespace sysy

View File

@ -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,10 +67,8 @@ void DCEContext::run(Function *func, AnalysisManager *AM, bool &changed) {
// 如果指令不在活跃集合中,则删除它。
// 分支和返回指令由 isAlive 处理,并会被保留。
if (alive_insts.count(currentInst) == 0) {
// 删除指令,保留用户风格的 SysYIROptUtils::usedelete 和 erase
instIter = SysYIROptUtils::usedelete(instIter); // 删除后返回下一个迭代器
changed = true; // 标记 IR 已被修改
SysYIROptUtils::usedelete(currentInst);
instIter = basicBlock->getInstructions().erase(instIter); // 删除后返回下一个迭代器
} else {
++instIter; // 指令活跃,移动到下一个
}
@ -62,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 集合中
@ -104,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 优化
@ -122,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会删除指令这会影响许多分析结果。
// 至少,它会影响活跃性分析、支配树、控制流图(如果删除导致基本块为空并被合并)。

View File

@ -0,0 +1,433 @@
#include "InductionVariableElimination.h"
#include "LoopCharacteristics.h"
#include "Loop.h"
#include "Dom.h"
#include "SideEffectAnalysis.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);
// 会使失效的分析归纳变量消除会修改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;
}
}
// 执行三个阶段的优化
// 阶段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 指令
}
// 检查是否只用于自身更新
if (!isUsedOnlyForSelfUpdate(phiInst, loop)) {
return nullptr; // 有其他用途
}
// 创建死归纳变量信息
auto deadIV = std::make_unique<DeadInductionVariable>(phiInst, loop);
deadIV->relatedInsts = collectRelatedInstructions(phiInst, loop);
return deadIV;
}
bool InductionVariableEliminationContext::isUsedOnlyForSelfUpdate(PhiInst* phiInst, Loop* loop) {
// 检查 phi 指令的所有使用
for (auto use : phiInst->getUses()) {
auto user = use->getUser();
auto* userInst = dynamic_cast<Instruction*>(user);
if (!userInst) {
return false; // 被非指令使用
}
// 检查使用是否在循环内
if (!loop->contains(userInst->getParent())) {
return false; // 在循环外被使用
}
// 检查是否为自身的更新指令
bool isSelfUpdate = false;
// 检查是否为加法/减法指令(常见的归纳变量更新模式)
if (userInst->getKind() == Instruction::Kind::kAdd ||
userInst->getKind() == Instruction::Kind::kSub) {
auto* binInst = dynamic_cast<BinaryInst*>(userInst);
if (binInst && (binInst->getOperand(0) == phiInst || binInst->getOperand(1) == phiInst)) {
// 检查这个指令的结果是否流回到 phi
for (auto& [incomingBB, incomingVal] : phiInst->getIncomingValues()) {
if (loop->contains(incomingBB) && incomingVal == binInst) {
isSelfUpdate = true;
break;
}
}
}
}
if (!isSelfUpdate) {
return false; // 有非自更新的使用
}
}
return true; // 只用于自身更新
}
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

View File

@ -0,0 +1,112 @@
#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());
// 2. 计算每个指令被依赖的次数(入度)
std::unordered_map<Instruction *, int> indegree;
for (auto *inst : workSet) {
indegree[inst] = 0;
}
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]++;
}
}
}
}
// 3. Kahn拓扑排序
std::vector<Instruction *> sorted;
std::queue<Instruction *> q;
for (auto &[inst, deg] : indegree) {
if (deg == 0)
q.push(inst);
}
while (!q.empty()) {
auto *inst = q.front();
q.pop();
sorted.push_back(inst);
for (size_t i = 0; i < inst->getNumOperands(); ++i) {
if (auto *dep = dynamic_cast<Instruction *>(inst->getOperand(i))) {
if (workSet.count(dep)) {
indegree[dep]--;
if (indegree[dep] == 0)
q.push(dep);
}
}
}
}
// 检查是否全部排序,若未全部排序,说明有环(理论上不会)
if (sorted.size() != workSet.size()) {
if (DEBUG)
std::cerr << "LICM: Topological sort failed, possible dependency cycle." << std::endl;
return false;
}
// 4. 按拓扑序外提
for (auto *inst : sorted) {
if (!inst)
continue;
BasicBlock *parent = inst->getParent();
if (parent && loop->contains(parent)) {
auto sourcePos = parent->findInstIterator(inst);
auto targetPos = preheader->terminator();
parent->moveInst(sourcePos, targetPos, preheader);
changed = true;
}
}
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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -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> // 用于断言
@ -60,7 +62,7 @@ void Mem2RegContext::run(Function *func, AnalysisManager *AM) {
}
// 从入口基本块开始,对支配树进行 DFS 遍历,进行变量重命名
renameVariables(nullptr, func->getEntryBlock()); // 第一个参数 alloca 在这里不使用,因为是递归入口点
renameVariables(func->getEntryBlock()); // 第一个参数 alloca 在这里不使用,因为是递归入口点
// --------------------------------------------------------------------
// 阶段4: 清理
@ -209,16 +211,21 @@ void Mem2RegContext::insertPhis(AllocaInst *alloca, const std::unordered_set<Bas
}
// 对支配树进行深度优先遍历,重命名变量并替换 load/store 指令
void Mem2RegContext::renameVariables(AllocaInst *currentAlloca, BasicBlock *currentBB) {
// 维护一个局部栈,用于存储当前基本块中为 Phi 和 Store 创建的 SSA 值,以便在退出时弹出
std::stack<Value *> localStackPushed;
// 移除了 AllocaInst *currentAlloca 参数,因为这个函数是为整个基本块处理所有可提升的 Alloca
void Mem2RegContext::renameVariables(BasicBlock *currentBB) {
// 1. 在函数开始时,记录每个 promotableAlloca 的当前栈深度。
// 这将用于在函数返回时精确地回溯栈状态。
std::map<AllocaInst *, size_t> originalStackSizes;
for (auto alloca : promotableAllocas) {
originalStackSizes[alloca] = allocaToValueStackMap[alloca].size();
}
// --------------------------------------------------------------------
// 处理当前基本块的指令
// --------------------------------------------------------------------
for (auto instIter = currentBB->getInstructions().begin(); instIter != currentBB->getInstructions().end();) {
Instruction *inst = instIter->get();
bool instDeleted = false;
bool instDeleted = false;
// 处理 Phi 指令 (如果是当前 alloca 的 Phi)
if (auto phiInst = dynamic_cast<PhiInst *>(inst)) {
@ -227,52 +234,69 @@ void Mem2RegContext::renameVariables(AllocaInst *currentAlloca, BasicBlock *curr
if (allocaToPhiMap[alloca].count(currentBB) && allocaToPhiMap[alloca][currentBB] == phiInst) {
// 为 Phi 指令的输出创建一个新的 SSA 值,并压入值栈
allocaToValueStackMap[alloca].push(phiInst);
localStackPushed.push(phiInst); // 记录以便弹出
break; // 找到对应的 alloca处理下一个指令
if (DEBUG) {
std::cout << "Mem2Reg: Pushed Phi " << (phiInst->getName().empty() ? "anonymous" : phiInst->getName()) << " for alloca " << alloca->getName()
<< ". Stack size: " << allocaToValueStackMap[alloca].size() << std::endl;
}
break; // 找到对应的 alloca处理下一个指令
}
}
}
// 处理 LoadInst
else if (auto loadInst = dynamic_cast<LoadInst *>(inst)) {
// 检查这个 LoadInst 是否是为某个可提升的 alloca
for (auto alloca : promotableAllocas) {
if (loadInst->getPointer() == alloca) {
// loadInst->getPointer() 返回 AllocaInst*
// 将 LoadInst 的所有用途替换为当前 alloca 值栈顶部的 SSA 值
// 检查 LoadInst 的指针是否直接是 alloca或者是指向 alloca 的 GEP
Value *ptrOperand = loadInst->getPointer();
if (ptrOperand == alloca || (dynamic_cast<GetElementPtrInst *>(ptrOperand) &&
dynamic_cast<GetElementPtrInst *>(ptrOperand)->getBasePointer() == alloca)) {
assert(!allocaToValueStackMap[alloca].empty() && "Value stack empty for alloca during load replacement!");
if (DEBUG) {
std::cout << "Mem2Reg: Replacing load "
<< (ptrOperand->getName().empty() ? "anonymous" : ptrOperand->getName()) << " with SSA value "
<< (allocaToValueStackMap[alloca].top()->getName().empty()
? "anonymous"
: allocaToValueStackMap[alloca].top()->getName())
<< " for alloca " << alloca->getName() << std::endl;
std::cout << "Mem2Reg: allocaToValueStackMap[" << alloca->getName()
<< "] size: " << allocaToValueStackMap[alloca].size() << std::endl;
}
loadInst->replaceAllUsesWith(allocaToValueStackMap[alloca].top());
// instIter = currentBB->force_delete_inst(loadInst); // 删除 LoadInst
SysYIROptUtils::usedelete(loadInst); // 仅删除 use 关系
instIter = currentBB->getInstructions().erase(instIter); // 删除 LoadInst
instIter = SysYIROptUtils::usedelete(instIter);
instDeleted = true;
// std::cerr << "Mem2Reg: Replaced load " << loadInst->name() << " with SSA value." << std::endl;
break;
}
}
}
// 处理 StoreInst
else if (auto storeInst = dynamic_cast<StoreInst *>(inst)) {
// 检查这个 StoreInst 是否是为某个可提升的 alloca
for (auto alloca : promotableAllocas) {
if (storeInst->getPointer() == alloca) {
// 假设 storeInst->getPointer() 返回 AllocaInst*
// 将 StoreInst 存储的值作为新的 SSA 值,压入值栈
// 检查 StoreInst 的指针是否直接是 alloca或者是指向 alloca 的 GEP
Value *ptrOperand = storeInst->getPointer();
if (ptrOperand == alloca || (dynamic_cast<GetElementPtrInst *>(ptrOperand) &&
dynamic_cast<GetElementPtrInst *>(ptrOperand)->getBasePointer() == alloca)) {
if (DEBUG) {
std::cout << "Mem2Reg: Replacing store to "
<< (ptrOperand->getName().empty() ? "anonymous" : ptrOperand->getName()) << " with SSA value "
<< (storeInst->getValue()->getName().empty() ? "anonymous" : storeInst->getValue()->getName())
<< " for alloca " << alloca->getName() << std::endl;
std::cout << "Mem2Reg: allocaToValueStackMap[" << alloca->getName()
<< "] size before push: " << allocaToValueStackMap[alloca].size() << std::endl;
}
allocaToValueStackMap[alloca].push(storeInst->getValue());
localStackPushed.push(storeInst->getValue()); // 记录以便弹出
SysYIROptUtils::usedelete(storeInst);
instIter = currentBB->getInstructions().erase(instIter); // 删除 StoreInst
instIter = SysYIROptUtils::usedelete(instIter);
instDeleted = true;
// std::cerr << "Mem2Reg: Replaced store to " << storeInst->ptr()->name() << " with SSA value." << std::endl;
if (DEBUG) {
std::cout << "Mem2Reg: allocaToValueStackMap[" << alloca->getName()
<< "] size after push: " << allocaToValueStackMap[alloca].size() << std::endl;
}
break;
}
}
}
if (!instDeleted) {
++instIter; // 如果指令没有被删除,移动到下一个
}
}
// --------------------------------------------------------------------
// 处理后继基本块的 Phi 指令参数
// --------------------------------------------------------------------
@ -287,38 +311,57 @@ void Mem2RegContext::renameVariables(AllocaInst *currentAlloca, BasicBlock *curr
// 参数值是当前 alloca 值栈顶部的 SSA 值
assert(!allocaToValueStackMap[alloca].empty() && "Value stack empty for alloca when setting phi operand!");
phiInst->addIncoming(allocaToValueStackMap[alloca].top(), currentBB);
if (DEBUG) {
std::cout << "Mem2Reg: Added incoming arg to Phi "
<< (phiInst->getName().empty() ? "anonymous" : phiInst->getName()) << " from "
<< currentBB->getName() << " with value "
<< (allocaToValueStackMap[alloca].top()->getName().empty()
? "anonymous"
: allocaToValueStackMap[alloca].top()->getName())
<< std::endl;
}
}
}
}
// --------------------------------------------------------------------
// 递归访问支配树的子节点
// --------------------------------------------------------------------
const std::set<BasicBlock *> *dominatedBlocks = dt->getDominatorTreeChildren(currentBB);
if(dominatedBlocks){
if (dominatedBlocks) { // 检查是否存在子节点
if(DEBUG){
std::cout << "Mem2Reg: Processing dominated blocks for " << currentBB->getName() << std::endl;
for (auto dominatedBB : *dominatedBlocks) {
std::cout << "Mem2Reg: Dominated block: " << (dominatedBB ? dominatedBB->getName() : "null") << std::endl;
}
}
for (auto dominatedBB : *dominatedBlocks) {
if (dominatedBB) {
std::cout << "Mem2Reg: Recursively renaming variables in dominated block: " << dominatedBB->getName() << std::endl;
renameVariables(currentAlloca, dominatedBB);
if (dominatedBB) { // 确保子块有效
if (DEBUG) {
std::cout << "Mem2Reg: Recursively renaming variables in dominated block: " << dominatedBB->getName()
<< std::endl;
}
renameVariables(dominatedBB); // 递归调用,不再传递 currentAlloca
}
}
}
// --------------------------------------------------------------------
// 退出基本块时,弹出在此块中压入值栈的 SSA 值
// 退出基本块时,弹出在此块中压入值栈的 SSA 值,恢复栈到进入该块时的状态
// --------------------------------------------------------------------
while (!localStackPushed.empty()) {
Value *val = localStackPushed.top();
localStackPushed.pop();
// 找到是哪个 alloca 对应的栈
for (auto alloca : promotableAllocas) {
if (!allocaToValueStackMap[alloca].empty() && allocaToValueStackMap[alloca].top() == val) {
allocaToValueStackMap[alloca].pop();
break;
for (auto alloca : promotableAllocas) {
while (allocaToValueStackMap[alloca].size() > originalStackSizes[alloca]) {
if (DEBUG) {
std::cout << "Mem2Reg: Popping value "
<< (allocaToValueStackMap[alloca].top()->getName().empty()
? "anonymous"
: allocaToValueStackMap[alloca].top()->getName())
<< " for alloca " << alloca->getName() << ". Stack size: " << allocaToValueStackMap[alloca].size()
<< " -> " << (allocaToValueStackMap[alloca].size() - 1) << std::endl;
}
allocaToValueStackMap[alloca].pop();
}
}
}
// 删除所有原始的 AllocaInst、LoadInst 和 StoreInst
@ -327,7 +370,6 @@ void Mem2RegContext::cleanup() {
if (alloca && alloca->getParent()) {
// 删除 alloca 指令本身
SysYIROptUtils::usedelete(alloca);
alloca->getParent()->removeInst(alloca); // 从基本块中删除 alloca
// std::cerr << "Mem2Reg: Deleted alloca " << alloca->name() << std::endl;
}
@ -380,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 结构的分析都可能失效。
}

View File

@ -74,7 +74,7 @@ void Reg2MemContext::allocateMemoryForSSAValues(Function *func) {
// 默认情况下,将所有参数是提升到内存
if (isPromotableToMemory(arg)) {
// 参数的类型就是 AllocaInst 需要分配的类型
AllocaInst *alloca = builder->createAllocaInst(Type::getPointerType(arg->getType()), {}, arg->getName() + ".reg2mem");
AllocaInst *alloca = builder->createAllocaInst(Type::getPointerType(arg->getType()), arg->getName() + ".reg2mem");
// 将参数值 store 到 alloca 中 (这是 Mem2Reg 逆转的关键一步)
valueToAllocaMap[arg] = alloca;
@ -103,7 +103,7 @@ void Reg2MemContext::allocateMemoryForSSAValues(Function *func) {
// AllocaInst 应该在入口块,而不是当前指令所在块
// 这里我们只是创建,并稍后调整其位置
// 通常的做法是在循环结束后统一将 alloca 放到 entryBlock 的顶部
AllocaInst *alloca = builder->createAllocaInst(Type::getPointerType(inst.get()->getType()), {}, inst.get()->getName() + ".reg2mem");
AllocaInst *alloca = builder->createAllocaInst(Type::getPointerType(inst.get()->getType()), inst.get()->getName() + ".reg2mem");
valueToAllocaMap[inst.get()] = alloca;
}
}
@ -148,8 +148,8 @@ void Reg2MemContext::rewritePhis(Function *func) {
// 1. 为 Phi 指令的每个入边,在前驱块的末尾插入 Store 指令
// PhiInst 假设有 getIncomingValues() 和 getIncomingBlocks()
for (unsigned i = 0; i < phiInst->getNumIncomingValues(); ++i) { // 假设 PhiInst 是通过操作数来管理入边的
Value *incomingValue = phiInst->getValue(i); // 获取入值
BasicBlock *incomingBlock = phiInst->getBlock(i); // 获取对应的入块
Value *incomingValue = phiInst->getIncomingValue(i); // 获取入值
BasicBlock *incomingBlock = phiInst->getIncomingBlock(i); // 获取对应的入块
// 在入块的跳转指令之前插入 StoreInst
// 需要找到 incomingBlock 的终结指令 (Terminator Instruction)
@ -181,8 +181,7 @@ void Reg2MemContext::rewritePhis(Function *func) {
// 实际删除 Phi 指令
for (auto phi : phisToErase) {
if (phi && phi->getParent()) {
SysYIROptUtils::usedelete(phi); // 清理 use-def 链
phi->getParent()->removeInst(phi); // 从基本块中删除
SysYIROptUtils::usedelete(phi);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,12 @@
#include "SysYIRCFGOpt.h"
#include "SysYIROptUtils.h"
#include <cassert>
#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <string>
#include <iostream>
#include <queue> // 引入队列SysYDelNoPreBLock需要
#include <string>
namespace sysy {
@ -18,7 +18,6 @@ void *SysYBlockMergePass::ID = (void *)&SysYBlockMergePass::ID;
void *SysYAddReturnPass::ID = (void *)&SysYAddReturnPass::ID;
void *SysYCondBr2BrPass::ID = (void *)&SysYCondBr2BrPass::ID;
// ======================================================================
// SysYCFGOptUtils: 辅助工具类包含实际的CFG优化逻辑
// ======================================================================
@ -26,40 +25,42 @@ void *SysYCondBr2BrPass::ID = (void *)&SysYCondBr2BrPass::ID;
// 删除br后的无用指令
bool SysYCFGOptUtils::SysYDelInstAfterBr(Function *func) {
bool changed = false;
auto basicBlocks = func->getBasicBlocks();
for (auto &basicBlock : basicBlocks) {
bool Branch = false;
auto &instructions = basicBlock->getInstructions();
auto Branchiter = instructions.end();
for (auto iter = instructions.begin(); iter != instructions.end(); ++iter) {
if ((*iter)->isTerminator()){
if ((*iter)->isTerminator()) {
Branch = true;
Branchiter = iter;
break;
}
}
if (Branchiter != instructions.end()) ++Branchiter;
if (Branchiter != instructions.end())
++Branchiter;
while (Branchiter != instructions.end()) {
changed = true;
Branchiter = instructions.erase(Branchiter);
Branchiter = SysYIROptUtils::usedelete(Branchiter); // 删除指令
}
if (Branch) { // 更新前驱后继关系
auto thelastinstinst = basicBlock->getInstructions().end();
--thelastinstinst;
if (Branch) { // 更新前驱后继关系
auto thelastinstinst = basicBlock->terminator();
auto &Successors = basicBlock->getSuccessors();
for (auto iterSucc = Successors.begin(); iterSucc != Successors.end();) {
(*iterSucc)->removePredecessor(basicBlock.get());
basicBlock->removeSuccessor(*iterSucc);
}
if (thelastinstinst->get()->isUnconditional()) {
BasicBlock* branchBlock = dynamic_cast<BasicBlock *>(thelastinstinst->get()->getOperand(0));
auto brinst = dynamic_cast<UncondBrInst *>(thelastinstinst->get());
BasicBlock *branchBlock = dynamic_cast<BasicBlock *>(brinst->getBlock());
basicBlock->addSuccessor(branchBlock);
branchBlock->addPredecessor(basicBlock.get());
} else if (thelastinstinst->get()->isConditional()) {
BasicBlock* thenBlock = dynamic_cast<BasicBlock *>(thelastinstinst->get()->getOperand(1));
BasicBlock* elseBlock = dynamic_cast<BasicBlock *>(thelastinstinst->get()->getOperand(2));
auto brinst = dynamic_cast<CondBrInst *>(thelastinstinst->get());
BasicBlock *thenBlock = dynamic_cast<BasicBlock *>(brinst->getThenBlock());
BasicBlock *elseBlock = dynamic_cast<BasicBlock *>(brinst->getElseBlock());
basicBlock->addSuccessor(thenBlock);
basicBlock->addSuccessor(elseBlock);
thenBlock->addPredecessor(basicBlock.get());
@ -75,38 +76,48 @@ bool SysYCFGOptUtils::SysYDelInstAfterBr(Function *func) {
bool SysYCFGOptUtils::SysYBlockMerge(Function *func) {
bool changed = false;
for (auto blockiter = func->getBasicBlocks().begin();
blockiter != func->getBasicBlocks().end();) {
for (auto blockiter = func->getBasicBlocks().begin(); blockiter != func->getBasicBlocks().end();) {
// 检查当前块是是不是entry块
if( blockiter->get() == func->getEntryBlock() ) {
blockiter++;
continue; // 跳过入口块
}
if (blockiter->get()->getNumSuccessors() == 1) {
// 如果当前块只有一个后继块
// 且后继块只有一个前驱块
// 则将当前块和后继块合并
if (((blockiter->get())->getSuccessors()[0])->getNumPredecessors() == 1) {
// std::cout << "merge block: " << blockiter->get()->getName() << std::endl;
BasicBlock* block = blockiter->get();
BasicBlock* nextBlock = blockiter->get()->getSuccessors()[0];
BasicBlock *block = blockiter->get();
BasicBlock *nextBlock = blockiter->get()->getSuccessors()[0];
// auto nextarguments = nextBlock->getArguments();
// 删除br指令
// 删除block的br指令
if (block->getNumInstructions() != 0) {
auto thelastinstinst = block->end();
(--thelastinstinst);
auto thelastinstinst = block->terminator();
if (thelastinstinst->get()->isUnconditional()) {
SysYIROptUtils::usedelete(thelastinstinst->get());
thelastinstinst = block->getInstructions().erase(thelastinstinst);
thelastinstinst = SysYIROptUtils::usedelete(thelastinstinst);
} else if (thelastinstinst->get()->isConditional()) {
// 如果是条件分支,判断条件是否相同,主要优化相同布尔表达式
if (thelastinstinst->get()->getOperand(1)->getName() == thelastinstinst->get()->getOperand(1)->getName()) {
SysYIROptUtils::usedelete(thelastinstinst->get());
thelastinstinst = block->getInstructions().erase(thelastinstinst);
// 按道理不会走到这个分支
// 如果是条件分支查看then else是否相同
auto brinst = dynamic_cast<CondBrInst *>(thelastinstinst->get());
if (brinst->getThenBlock() == brinst->getElseBlock()) {
thelastinstinst = SysYIROptUtils::usedelete(thelastinstinst);
}
else{
assert(false && "SysYBlockMerge: unexpected conditional branch with different then and else blocks");
}
}
}
// 将后继块的指令移动到当前块
// 并将后继块的父指针改为当前块
for (auto institer = nextBlock->begin(); institer != nextBlock->end();) {
institer->get()->setParent(block);
block->getInstructions().emplace_back(institer->release());
institer = nextBlock->getInstructions().erase(institer);
// institer->get()->setParent(block);
// block->getInstructions().emplace_back(institer->release());
// 用usedelete删除会导致use关系被删除我只希望移动指令到当前块
// institer = SysYIROptUtils::usedelete(institer);
// institer = nextBlock->getInstructions().erase(institer);
institer = nextBlock->moveInst(institer, block->getInstructions().end(), block);
}
// 更新前驱后继关系,类似树节点操作
block->removeSuccessor(nextBlock);
@ -137,323 +148,433 @@ bool SysYCFGOptUtils::SysYBlockMerge(Function *func) {
// 删除无前驱块兼容SSA后的处理
bool SysYCFGOptUtils::SysYDelNoPreBLock(Function *func) {
bool changed = false;
bool changed = false; // 标记是否有基本块被删除
std::set<BasicBlock *> reachableBlocks; // 用于存储所有可达的基本块
std::queue<BasicBlock *> blockQueue; // BFS 遍历队列
for (auto &block : func->getBasicBlocks()) {
block->setreachableFalse();
BasicBlock *entryBlock = func->getEntryBlock();
if (entryBlock) { // 确保函数有入口块
reachableBlocks.insert(entryBlock); // 将入口块标记为可达
blockQueue.push(entryBlock); // 入口块入队
}
// 对函数基本块做一个拓扑排序,排查不可达基本块
auto entryBlock = func->getEntryBlock();
entryBlock->setreachableTrue();
std::queue<BasicBlock *> blockqueue;
blockqueue.push(entryBlock);
while (!blockqueue.empty()) {
auto block = blockqueue.front();
blockqueue.pop();
for (auto &succ : block->getSuccessors()) {
if (!succ->getreachable()) {
succ->setreachableTrue();
blockqueue.push(succ);
// 如果没有入口块(比如一个空函数),则没有块是可达的,所有块都将被删除。
while (!blockQueue.empty()) { // BFS 遍历:只要队列不空
BasicBlock *currentBlock = blockQueue.front();
blockQueue.pop(); // 取出当前块
for (auto &succ : currentBlock->getSuccessors()) { // 遍历当前块的所有后继
// 如果后继块不在 reachableBlocks 中(即尚未被访问过)
if (reachableBlocks.find(succ) == reachableBlocks.end()) {
reachableBlocks.insert(succ); // 标记为可达
blockQueue.push(succ); // 入队,以便继续遍历
}
}
}
// 删除不可达基本块指令
for (auto blockIter = func->getBasicBlocks().begin(); blockIter != func->getBasicBlocks().end(); blockIter++) {
if (!blockIter->get()->getreachable()) {
for (auto instIter = blockIter->get()->getInstructions().begin();
instIter != blockIter->get()->getInstructions().end();) {
SysYIROptUtils::usedelete(instIter->get());
instIter = blockIter->get()->getInstructions().erase(instIter);
std::vector<BasicBlock *> blocksToDelete; // 用于存储所有不可达基本块
for (auto &blockPtr : func->getBasicBlocks()) {
BasicBlock *block = blockPtr.get();
// 如果当前块不在 reachableBlocks 集合中,说明它是不可达的
if (reachableBlocks.find(block) == reachableBlocks.end()) {
blocksToDelete.push_back(block); // 将其加入待删除列表
changed = true; // 只要找到一个不可达块,就说明函数发生了改变
}
}
for (BasicBlock *unreachableBlock : blocksToDelete) {
// 遍历不可达块中的所有指令,并删除它们
for (auto instIter = unreachableBlock->getInstructions().begin();
instIter != unreachableBlock->getInstructions().end();) {
instIter = SysYIROptUtils::usedelete(instIter);
}
}
for (BasicBlock *unreachableBlock : blocksToDelete) {
for (BasicBlock *succBlock : unreachableBlock->getSuccessors()) {
// 只有当后继块自身是可达的(没有被删除)时才需要处理
if (reachableBlocks.count(succBlock)) {
for (auto &phiInstPtr : succBlock->getInstructions()) {
// Phi 指令总是在基本块的开头。一旦遇到非 Phi 指令即可停止。
if (phiInstPtr->getKind() != Instruction::kPhi) {
break;
}
// 将这个 Phi 节点中来自不可达前驱unreachableBlock的输入参数删除
dynamic_cast<PhiInst *>(phiInstPtr.get())->removeIncomingBlock(unreachableBlock);
}
}
}
}
for (auto blockIter = func->getBasicBlocks().begin(); blockIter != func->getBasicBlocks().end();) {
if (!blockIter->get()->getreachable()) {
for (auto succblock : blockIter->get()->getSuccessors()) {
for (auto &phiinst : succblock->getInstructions()) {
if (phiinst->getKind() != Instruction::kPhi) {
break;
}
// 使用 delBlk 方法正确地删除对应于被删除基本块的传入值
dynamic_cast<PhiInst *>(phiinst.get())->delBlk(blockIter->get());
}
}
// 删除不可达基本块,注意迭代器不可达问题
BasicBlock *currentBlock = blockIter->get();
// 如果当前块不在可达块集合中,则将其从函数中移除
if (reachableBlocks.find(currentBlock) == reachableBlocks.end()) {
// func->removeBasicBlock 应该返回下一个有效的迭代器
func->removeBasicBlock((blockIter++)->get());
changed = true;
} else {
blockIter++;
blockIter++; // 如果可达,则移动到下一个块
}
}
return changed;
}
// 删除空块
bool SysYCFGOptUtils::SysYDelEmptyBlock(Function *func, IRBuilder* pBuilder) {
bool SysYCFGOptUtils::SysYDelEmptyBlock(Function *func, IRBuilder *pBuilder) {
bool changed = false;
// 收集不可达基本块
// 这里的不可达基本块是指没有实际指令的基本块
// 当一个基本块没有实际指令例如只有phi指令和一个uncondbr指令时也会被视作不可达
auto basicBlocks = func->getBasicBlocks();
std::map<sysy::BasicBlock *, BasicBlock *> EmptyBlocks;
// 空块儿和后继的基本块的映射
for (auto &basicBlock : basicBlocks) {
if (basicBlock->getNumInstructions() == 0) {
if (basicBlock->getNumSuccessors() == 1) {
EmptyBlocks[basicBlock.get()] = basicBlock->getSuccessors().front();
}
}
else{
// 如果只有phi指令和一个uncondbr。(phi)*(uncondbr)?
// 判断除了最后一个指令之外是不是只有phi指令
bool onlyPhi = true;
for (auto &inst : basicBlock->getInstructions()) {
if (!inst->isPhi() && !inst->isUnconditional()) {
onlyPhi = false;
break;
}
}
if(onlyPhi && basicBlock->getNumSuccessors() == 1) // 确保有后继且只有一个
EmptyBlocks[basicBlock.get()] = basicBlock->getSuccessors().front();
}
// 步骤 1: 识别并映射所有符合“空块”定义的基本块及其目标后继
// 使用 std::map 来存储 <空块, 空块跳转目标>
// 这样可以处理空块链A -> B -> C如果 B 是空块A 应该跳到 C
std::map<BasicBlock *, BasicBlock *> emptyBlockRedirectMap;
// 为了避免在遍历 func->getBasicBlocks() 时修改它导致迭代器失效,
// 我们先收集所有的基本块。
std::vector<BasicBlock *> allBlocks;
for (auto &blockPtr : func->getBasicBlocks()) {
allBlocks.push_back(blockPtr.get());
}
// 更新基本块信息,增加必要指令
for (auto &basicBlock : basicBlocks) {
// 把空块转换成只有跳转指令的不可达块 (这段逻辑在优化遍中可能需要调整,这里是原样保留)
// 通常DelEmptyBlock 应该在BlockMerge之后运行如果存在完全空块它会尝试填充一个Br指令
// 但是,它主要目的是重定向跳转。
if (distance(basicBlock->begin(), basicBlock->end()) == 0) {
if (basicBlock->getNumSuccessors() == 0) {
continue;
}
if (basicBlock->getNumSuccessors() > 1) {
// 如果一个空块有多个后继说明CFG结构有问题或者需要特殊处理这里简单assert
assert(false && "Empty block with multiple successors found during SysYDelEmptyBlock");
}
// 这里的逻辑有点问题,如果一个块是空的,且只有一个后继,应该直接跳转到后继。
// 如果这个块最终被删除了,那么其前驱也需要重定向。
// 这个循环的目的是重定向现有的跳转指令,而不是创建新的。
// 所以下面的逻辑才是核心。
// pBuilder->setPosition(basicBlock.get(), basicBlock->end());
// pBuilder->createUncondBrInst(basicBlock->getSuccessors()[0], {});
for (BasicBlock *block : allBlocks) {
// 入口块通常不应该被认为是空块并删除,除非它没有实际指令且只有一个后继,
// 但为了安全起见,通常会跳过入口块的删除
// 如果入口块是空的,它应该被合并到它的后继,但处理起来更复杂,这里先不处理入口块为空的情况
if (block == func->getEntryBlock()) {
continue;
}
auto thelastinst = basicBlock->getInstructions().end();
--thelastinst;
// 根据br指令传递的后继块信息跳过空块链
if (thelastinst->get()->isUnconditional()) {
BasicBlock* OldBrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
BasicBlock *thelastBlockOld = nullptr;
// 如果空块链表为多个块
while (EmptyBlocks.count(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0)))) {
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
thelastinst->get()->replaceOperand(0, EmptyBlocks[thelastBlockOld]);
}
// 如果有重定向发生
if (thelastBlockOld != nullptr) {
basicBlock->removeSuccessor(OldBrBlock);
OldBrBlock->removePredecessor(basicBlock.get());
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0)));
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->addPredecessor(basicBlock.get());
changed = true; // 标记IR被修改
}
if (thelastBlockOld != nullptr) {
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getInstructions()) {
if (InstInNew->isPhi()) {
// 使用 delBlk 方法删除 oldBlock 对应的传入值
dynamic_cast<PhiInst *>(InstInNew.get())->delBlk(thelastBlockOld);
} else {
// 检查基本块是否是空的除了Phi指令外只包含一个终止指令 (Terminator)
// 且该终止指令必须是无条件跳转。
// 空块必须只有一个后继才能被简化
if (block->getNumSuccessors() == 1) {
bool hasNonPhiNonTerminator = false;
// 遍历除了最后一个指令之外的指令
for (auto instIter = block->getInstructions().begin(); instIter != block->getInstructions().end();) {
// 如果是终止指令(例如 br, ret且不是最后一个指令则该块有问题
if ((*instIter)->isTerminator() && instIter != block->terminator()) {
hasNonPhiNonTerminator = true;
break;
}
}
}
} else if (thelastinst->get()->getKind() == Instruction::kCondBr) {
auto OldThenBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
auto OldElseBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2));
bool thenChanged = false;
bool elseChanged = false;
BasicBlock *thelastBlockOld = nullptr;
while (EmptyBlocks.count(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)))) {
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
thelastinst->get()->replaceOperand(
1, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))]);
thenChanged = true;
}
if (thenChanged) {
basicBlock->removeSuccessor(OldThenBlock);
OldThenBlock->removePredecessor(basicBlock.get());
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)));
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->addPredecessor(basicBlock.get());
changed = true; // 标记IR被修改
}
// 处理 then 和 else 分支合并的情况
if (dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)) ==
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) {
auto thebrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
SysYIROptUtils::usedelete(thelastinst->get());
thelastinst = basicBlock->getInstructions().erase(thelastinst);
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
pBuilder->createUncondBrInst(thebrBlock, {});
changed = true; // 标记IR被修改
continue;
}
if (thelastBlockOld != nullptr) {
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->getInstructions()) {
if (InstInNew->isPhi()) {
// 使用 delBlk 方法删除 oldBlock 对应的传入值
dynamic_cast<PhiInst *>(InstInNew.get())->delBlk(thelastBlockOld);
} else {
break;
// 如果不是 Phi 指令且不是终止指令
if (!(*instIter)->isPhi() && !(*instIter)->isTerminator()) {
hasNonPhiNonTerminator = true;
break;
}
++instIter;
if (!hasNonPhiNonTerminator &&
instIter == block->getInstructions().end()) { // 如果块中只有 Phi 指令和一个 Terminator
// 确保最后一个指令是无条件跳转
auto lastInst = block->terminator()->get();
if (lastInst && lastInst->isUnconditional()) {
emptyBlockRedirectMap[block] = block->getSuccessors().front();
}
}
}
thelastBlockOld = nullptr;
while (EmptyBlocks.count(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2)))) {
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2));
thelastinst->get()->replaceOperand(
2, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))]);
elseChanged = true;
}
if (elseChanged) {
basicBlock->removeSuccessor(OldElseBlock);
OldElseBlock->removePredecessor(basicBlock.get());
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2)));
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->addPredecessor(basicBlock.get());
changed = true; // 标记IR被修改
}
// 处理 then 和 else 分支合并的情况
if (dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)) ==
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) {
auto thebrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
SysYIROptUtils::usedelete(thelastinst->get());
thelastinst = basicBlock->getInstructions().erase(thelastinst);
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
pBuilder->createUncondBrInst(thebrBlock, {});
changed = true; // 标记IR被修改
continue;
}
// 如果有重定向发生
// 需要更新后继块的前驱关系
if (thelastBlockOld != nullptr) {
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->getInstructions()) {
if (InstInNew->isPhi()) {
// 使用 delBlk 方法删除 oldBlock 对应的传入值
dynamic_cast<PhiInst *>(InstInNew.get())->delBlk(thelastBlockOld);
} else {
break;
}
}
}
} else {
// 如果不是终止指令,但有后继 (例如,末尾没有显式终止指令的块)
// 这段逻辑可能需要更严谨的CFG检查来确保正确性
if (basicBlock->getNumSuccessors() == 1) {
// 这里的逻辑似乎是想为没有terminator的块添加一个但通常这应该在CFG构建阶段完成。
// 如果这里仍然执行,确保它符合预期。
// pBuilder->setPosition(basicBlock.get(), basicBlock->end());
// pBuilder->createUncondBrInst(basicBlock->getSuccessors()[0], {});
// auto thelastinst = basicBlock->getInstructions().end();
// (--thelastinst);
// auto OldBrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
// sysy::BasicBlock *thelastBlockOld = nullptr;
// while (EmptyBlocks.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))) !=
// EmptyBlocks.end()) {
// thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
// thelastinst->get()->replaceOperand(
// 0, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))]);
// }
// basicBlock->removeSuccessor(OldBrBlock);
// OldBrBlock->removePredecessor(basicBlock.get());
// basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0)));
// dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->addPredecessor(basicBlock.get());
// changed = true; // 标记IR被修改
// if (thelastBlockOld != nullptr) {
// int indexphi = 0;
// for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getPredecessors()) {
// if (pred == thelastBlockOld) {
// break;
// }
// indexphi++;
// }
// for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getInstructions()) {
// if (InstInNew->isPhi()) {
// dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
// } else {
// break;
// }
// }
// }
}
}
}
}
// 真正的删除空块
for (auto iter = func->getBasicBlocks().begin(); iter != func->getBasicBlocks().end();) {
if (EmptyBlocks.count(iter->get())) {
// EntryBlock跳过
if (iter->get() == func->getEntryBlock()) {
++iter;
continue;
// 步骤 2: 遍历 emptyBlockRedirectMap处理空块
// 确保每个空块都直接重定向到其最终的非空后继块
for (auto const &[emptyBlock, directSucc] : emptyBlockRedirectMap) {
BasicBlock *targetBlock = directSucc;
// 沿着空块链一直找到最终的非空块目标
while (emptyBlockRedirectMap.count(targetBlock)) {
targetBlock = emptyBlockRedirectMap[targetBlock];
}
emptyBlockRedirectMap[emptyBlock] = targetBlock; // 更新映射到最终目标
}
// 步骤 3: 遍历所有基本块,重定向其终止指令,绕过空块
// 注意:这里需要再次遍历所有块,包括可能成为新目标的块
for (BasicBlock *currentBlock : allBlocks) {
// 如果 currentBlock 本身就是个空块,它会通过其前驱的重定向被处理,这里跳过
if (emptyBlockRedirectMap.count(currentBlock)) {
continue;
}
// 获取当前块的最后一个指令(终止指令)
if (currentBlock->getInstructions().empty()) {
// 理论上,除了入口块和可能被合并的空块外,所有块都应该有终止指令
// 如果这里碰到空块,可能是逻辑错误或者需要特殊处理
continue;
}
std::function<Value *(Value *, BasicBlock *)> getUltimateSourceValue = [&](Value *val, BasicBlock *currentDefBlock) -> Value * {
if(!dynamic_cast<Instruction *>(val)) {
// 如果 val 不是指令,直接返回它
return val;
}
Instruction *inst = dynamic_cast<Instruction *>(val);
// 如果定义指令不在任何空块中,它就是最终来源
if (!emptyBlockRedirectMap.count(currentDefBlock)) {
return val;
}
for (auto instIter = iter->get()->getInstructions().begin();
instIter != iter->get()->getInstructions().end();) {
SysYIROptUtils::usedelete(instIter->get()); // 仅删除 use 关系
// 显式地从基本块中删除指令并更新迭代器
instIter = iter->get()->getInstructions().erase(instIter);
// 如果是 Phi 指令,且它在空块中,则继续追溯其在空块链中前驱的传入值
if (inst->getKind() == Instruction::kPhi) {
PhiInst *phi = dynamic_cast<PhiInst *>(inst);
// 查找哪个前驱是空块链中的上一个块
for (size_t i = 0; i < phi->getNumOperands(); i += 2) {
BasicBlock *incomingBlock = dynamic_cast<BasicBlock *>(phi->getOperand(i + 1));
// 检查 incomingBlock 是否是当前空块的前驱,且也在空块映射中(或就是 P
// 找到在空块链中导致 currentDefBlock 的那个前驱块
if (emptyBlockRedirectMap.count(incomingBlock) || incomingBlock == currentBlock) {
// 递归追溯该传入值
return getUltimateSourceValue(phi->getValfromBlk(incomingBlock), incomingBlock);
}
}
}
// 删除不可达基本块的phi指令的操作数
for (auto &succ : iter->get()->getSuccessors()) {
for (auto &instinsucc : succ->getInstructions()) {
if (instinsucc->isPhi()) {
// iter->get() 就是当前被删除的空基本块它作为前驱连接到这里的Phi指令
dynamic_cast<PhiInst *>(instinsucc.get())->delBlk(iter->get());
// 如果是其他指令或者无法追溯到Phi链则认为它在空块中产生无法安全传播返回null或原值
// 在严格的空块定义下除了Phi和Terminator不应有其他指令产生值。
return val; // Fallback: If not a Phi, or unable to trace, return itself (may be dangling)
};
auto lastInst = currentBlock->getInstructions().back().get();
if (lastInst->isUnconditional()) { // 无条件跳转
UncondBrInst *brInst = dynamic_cast<UncondBrInst *>(lastInst);
BasicBlock *oldTarget = dynamic_cast<BasicBlock *>(brInst->getBlock()); // 原始跳转目标
if (emptyBlockRedirectMap.count(oldTarget)) { // 如果目标是空块
BasicBlock *newTarget = emptyBlockRedirectMap[oldTarget]; // 获取最终目标
// 更新 CFG 关系
currentBlock->removeSuccessor(oldTarget);
oldTarget->removePredecessor(currentBlock);
brInst->replaceOperand(0, newTarget); // 更新跳转指令的操作数
currentBlock->addSuccessor(newTarget);
newTarget->addPredecessor(currentBlock);
changed = true; // 标记发生改变
for (auto &phiInstPtr : newTarget->getInstructions()) {
if (phiInstPtr->getKind() == Instruction::kPhi) {
PhiInst *phiInst = dynamic_cast<PhiInst *>(phiInstPtr.get());
BasicBlock *actualEmptyPredecessorOfS = nullptr;
for (size_t i = 0; i < phiInst->getNumOperands(); i += 2) {
BasicBlock *incomingBlock = dynamic_cast<BasicBlock *>(phiInst->getOperand(i + 1));
if (incomingBlock && emptyBlockRedirectMap.count(incomingBlock) &&
emptyBlockRedirectMap[incomingBlock] == newTarget) {
actualEmptyPredecessorOfS = incomingBlock;
break;
}
}
if (actualEmptyPredecessorOfS) {
// 获取 Phi 节点原本从 actualEmptyPredecessorOfS 接收的值
Value *valueFromEmptyPredecessor = phiInst->getValfromBlk(actualEmptyPredecessorOfS);
// 追溯这个值,找到它在非空块中的最终来源
// currentBlock 是 P
// oldTarget 是 E1 (链的起点)
// actualEmptyPredecessorOfS 是 En (链的终点S 的前驱)
Value *ultimateSourceValue = getUltimateSourceValue(valueFromEmptyPredecessor, actualEmptyPredecessorOfS);
// 替换 Phi 节点的传入块和传入值
if (ultimateSourceValue) { // 确保成功追溯到有效来源
// phiInst->replaceIncoming(actualEmptyPredecessorOfS, currentBlock, ultimateSourceValue);
phiInst->replaceIncomingBlock(actualEmptyPredecessorOfS, currentBlock, ultimateSourceValue);
} else {
assert(false && "[DelEmptyBlock] Unable to trace a valid source for Phi instruction");
// 无法追溯到有效来源,这可能是个错误或特殊情况
// 此时可能需要移除该 Phi 项,或者插入一个 undef 值
phiInst->getValfromBlk(actualEmptyPredecessorOfS);
}
}
} else {
// Phi 指令通常在基本块的开头,如果不是 Phi 指令就停止检查
break;
}
}
}
func->removeBasicBlock((iter++)->get());
changed = true;
} else {
++iter;
} else if (lastInst->getKind() == Instruction::kCondBr) { // 条件跳转
CondBrInst *condBrInst = dynamic_cast<CondBrInst *>(lastInst);
BasicBlock *oldThenTarget = dynamic_cast<BasicBlock *>(condBrInst->getThenBlock());
BasicBlock *oldElseTarget = dynamic_cast<BasicBlock *>(condBrInst->getElseBlock());
bool thenPathChanged = false;
bool elsePathChanged = false;
// 处理 Then 分支
if (emptyBlockRedirectMap.count(oldThenTarget)) {
BasicBlock *newThenTarget = emptyBlockRedirectMap[oldThenTarget];
condBrInst->replaceOperand(1, newThenTarget); // 更新跳转指令操作数
currentBlock->removeSuccessor(oldThenTarget);
oldThenTarget->removePredecessor(currentBlock);
currentBlock->addSuccessor(newThenTarget);
newThenTarget->addPredecessor(currentBlock);
thenPathChanged = true;
changed = true;
// 处理新 Then 目标块中的 Phi 指令
// for (auto &phiInstPtr : newThenTarget->getInstructions()) {
// if (phiInstPtr->getKind() == Instruction::kPhi) {
// dynamic_cast<PhiInst *>(phiInstPtr.get())->delBlk(oldThenTarget);
// } else {
// break;
// }
// }
for (auto &phiInstPtr : newThenTarget->getInstructions()) {
if (phiInstPtr->getKind() == Instruction::kPhi) {
PhiInst *phiInst = dynamic_cast<PhiInst *>(phiInstPtr.get());
BasicBlock *actualEmptyPredecessorOfS = nullptr;
for (size_t i = 0; i < phiInst->getNumOperands(); i += 2) {
BasicBlock *incomingBlock = dynamic_cast<BasicBlock *>(phiInst->getOperand(i + 1));
if (incomingBlock && emptyBlockRedirectMap.count(incomingBlock) &&
emptyBlockRedirectMap[incomingBlock] == newThenTarget) {
actualEmptyPredecessorOfS = incomingBlock;
break;
}
}
if (actualEmptyPredecessorOfS) {
// 获取 Phi 节点原本从 actualEmptyPredecessorOfS 接收的值
Value *valueFromEmptyPredecessor = phiInst->getValfromBlk(actualEmptyPredecessorOfS);
// 追溯这个值,找到它在非空块中的最终来源
// currentBlock 是 P
// oldTarget 是 E1 (链的起点)
// actualEmptyPredecessorOfS 是 En (链的终点S 的前驱)
Value *ultimateSourceValue = getUltimateSourceValue(valueFromEmptyPredecessor, actualEmptyPredecessorOfS);
// 替换 Phi 节点的传入块和传入值
if (ultimateSourceValue) { // 确保成功追溯到有效来源
// phiInst->replaceIncoming(actualEmptyPredecessorOfS, currentBlock, ultimateSourceValue);
phiInst->replaceIncomingBlock(actualEmptyPredecessorOfS, currentBlock, ultimateSourceValue);
} else {
assert(false && "[DelEmptyBlock] Unable to trace a valid source for Phi instruction");
// 无法追溯到有效来源,这可能是个错误或特殊情况
// 此时可能需要移除该 Phi 项,或者插入一个 undef 值
phiInst->removeIncomingBlock(actualEmptyPredecessorOfS);
}
}
} else {
break;
}
}
}
// 处理 Else 分支
if (emptyBlockRedirectMap.count(oldElseTarget)) {
BasicBlock *newElseTarget = emptyBlockRedirectMap[oldElseTarget];
condBrInst->replaceOperand(2, newElseTarget); // 更新跳转指令操作数
currentBlock->removeSuccessor(oldElseTarget);
oldElseTarget->removePredecessor(currentBlock);
currentBlock->addSuccessor(newElseTarget);
newElseTarget->addPredecessor(currentBlock);
elsePathChanged = true;
changed = true;
// 处理新 Else 目标块中的 Phi 指令
// for (auto &phiInstPtr : newElseTarget->getInstructions()) {
// if (phiInstPtr->getKind() == Instruction::kPhi) {
// dynamic_cast<PhiInst *>(phiInstPtr.get())->delBlk(oldElseTarget);
// } else {
// break;
// }
// }
for (auto &phiInstPtr : newElseTarget->getInstructions()) {
if (phiInstPtr->getKind() == Instruction::kPhi) {
PhiInst *phiInst = dynamic_cast<PhiInst *>(phiInstPtr.get());
BasicBlock *actualEmptyPredecessorOfS = nullptr;
for (size_t i = 0; i < phiInst->getNumOperands(); i += 2) {
BasicBlock *incomingBlock = dynamic_cast<BasicBlock *>(phiInst->getOperand(i + 1));
if (incomingBlock && emptyBlockRedirectMap.count(incomingBlock) &&
emptyBlockRedirectMap[incomingBlock] == newElseTarget) {
actualEmptyPredecessorOfS = incomingBlock;
break;
}
}
if (actualEmptyPredecessorOfS) {
// 获取 Phi 节点原本从 actualEmptyPredecessorOfS 接收的值
Value *valueFromEmptyPredecessor = phiInst->getValfromBlk(actualEmptyPredecessorOfS);
// 追溯这个值,找到它在非空块中的最终来源
// currentBlock 是 P
// oldTarget 是 E1 (链的起点)
// actualEmptyPredecessorOfS 是 En (链的终点S 的前驱)
Value *ultimateSourceValue = getUltimateSourceValue(valueFromEmptyPredecessor, actualEmptyPredecessorOfS);
// 替换 Phi 节点的传入块和传入值
if (ultimateSourceValue) { // 确保成功追溯到有效来源
// phiInst->replaceIncoming(actualEmptyPredecessorOfS, currentBlock, ultimateSourceValue);
phiInst->replaceIncomingBlock(actualEmptyPredecessorOfS, currentBlock, ultimateSourceValue);
} else {
assert(false && "[DelEmptyBlock] Unable to trace a valid source for Phi instruction");
// 无法追溯到有效来源,这可能是个错误或特殊情况
// 此时可能需要移除该 Phi 项,或者插入一个 undef 值
phiInst->removeIncomingBlock(actualEmptyPredecessorOfS);
}
}
} else {
break;
}
}
}
// 额外处理:如果条件跳转的两个分支现在指向同一个块,则可以简化为无条件跳转
if (condBrInst->getThenBlock() == condBrInst->getElseBlock()) {
BasicBlock *commonTarget = dynamic_cast<BasicBlock *>(condBrInst->getThenBlock());
SysYIROptUtils::usedelete(lastInst); // 删除旧的条件跳转指令
pBuilder->setPosition(currentBlock, currentBlock->end());
pBuilder->createUncondBrInst(commonTarget); // 插入新的无条件跳转指令
// 更安全地更新 CFG 关系
std::set<BasicBlock *> currentSuccessors;
currentSuccessors.insert(oldThenTarget);
currentSuccessors.insert(oldElseTarget);
// 移除旧的后继关系
for (BasicBlock *succ : currentSuccessors) {
currentBlock->removeSuccessor(succ);
succ->removePredecessor(currentBlock);
}
// 添加新的后继关系
currentBlock->addSuccessor(commonTarget);
commonTarget->addPredecessor(currentBlock);
changed = true;
}
}
}
// 步骤 4: 真正地删除空基本块
// 注意:只能在所有跳转和 Phi 指令都更新完毕后才能删除这些块
for (auto blockIter = func->getBasicBlocks().begin(); blockIter != func->getBasicBlocks().end();) {
BasicBlock *currentBlock = blockIter->get();
if (emptyBlockRedirectMap.count(currentBlock)) { // 如果在空块映射中
// 入口块不应该被删除,即使它符合空块定义,因为函数需要一个入口
if (currentBlock == func->getEntryBlock()) {
++blockIter;
continue;
}
// 在删除块之前,确保其内部指令被正确删除(虽然这类块指令很少)
for (auto instIter = currentBlock->getInstructions().begin();
instIter != currentBlock->getInstructions().end();) {
instIter = SysYIROptUtils::usedelete(instIter);
}
// 移除块
func->removeBasicBlock((blockIter++)->get());
changed = true;
} else {
++blockIter;
}
}
return changed;
}
// 如果函数没有返回指令,则添加一个默认返回指令(主要解决void函数没有返回指令的问题)
bool SysYCFGOptUtils::SysYAddReturn(Function *func, IRBuilder* pBuilder) {
bool SysYCFGOptUtils::SysYAddReturn(Function *func, IRBuilder *pBuilder) {
bool changed = false;
auto basicBlocks = func->getBasicBlocks();
for (auto &block : basicBlocks) {
@ -467,7 +588,8 @@ bool SysYCFGOptUtils::SysYAddReturn(Function *func, IRBuilder* pBuilder) {
auto thelastinst = block->getInstructions().end();
--thelastinst;
if (thelastinst->get()->getKind() != Instruction::kReturn) {
// std::cout << "Warning: Function " << func->getName() << " has no return instruction, adding default return." << std::endl;
// std::cout << "Warning: Function " << func->getName() << " has no return instruction, adding default
// return." << std::endl;
pBuilder->setPosition(block.get(), block->end());
// TODO: 如果int float函数缺少返回值是否需要报错
@ -483,7 +605,7 @@ bool SysYCFGOptUtils::SysYAddReturn(Function *func, IRBuilder* pBuilder) {
}
}
}
return changed;
}
@ -491,18 +613,18 @@ bool SysYCFGOptUtils::SysYAddReturn(Function *func, IRBuilder* pBuilder) {
// 主要针对已知条件值的分支转换为无条件分支
// 例如 if (cond) { ... } else { ... } 中的 cond 已经
// 确定为 true 或 false 的情况
bool SysYCFGOptUtils::SysYCondBr2Br(Function *func, IRBuilder* pBuilder) {
bool SysYCFGOptUtils::SysYCondBr2Br(Function *func, IRBuilder *pBuilder) {
bool changed = false;
for (auto &basicblock : func->getBasicBlocks()) {
if (basicblock->getNumInstructions() == 0)
continue;
auto thelast = basicblock->getInstructions().end();
--thelast;
if (thelast->get()->isConditional()){
ConstantValue *constOperand = dynamic_cast<ConstantValue *>(thelast->get()->getOperand(0));
auto thelast = basicblock->terminator();
if (thelast->get()->isConditional()) {
auto condBrInst = dynamic_cast<CondBrInst *>(thelast->get());
ConstantValue *constOperand = dynamic_cast<ConstantValue *>(condBrInst->getCondition());
std::string opname;
int constint = 0;
float constfloat = 0.0F;
@ -521,32 +643,31 @@ bool SysYCFGOptUtils::SysYCondBr2Br(Function *func, IRBuilder* pBuilder) {
if (constfloat_Use || constint_Use) {
changed = true;
auto thenBlock = dynamic_cast<BasicBlock *>(thelast->get()->getOperand(1));
auto elseBlock = dynamic_cast<BasicBlock *>(thelast->get()->getOperand(2));
SysYIROptUtils::usedelete(thelast->get());
thelast = basicblock->getInstructions().erase(thelast);
auto thenBlock = dynamic_cast<BasicBlock *>(condBrInst->getThenBlock());
auto elseBlock = dynamic_cast<BasicBlock *>(condBrInst->getElseBlock());
thelast = SysYIROptUtils::usedelete(thelast);
if ((constfloat_Use && constfloat == 1.0F) || (constint_Use && constint == 1)) {
// cond为true或非0
pBuilder->setPosition(basicblock.get(), basicblock->end());
pBuilder->createUncondBrInst(thenBlock, {});
pBuilder->createUncondBrInst(thenBlock);
// 更新CFG关系
basicblock->removeSuccessor(elseBlock);
elseBlock->removePredecessor(basicblock.get());
// 删除elseBlock的phi指令中对应的basicblock.get()的传入值
for (auto &phiinst : elseBlock->getInstructions()) {
if (phiinst->getKind() != Instruction::kPhi) {
break;
}
// 使用 delBlk 方法删除 basicblock.get() 对应的传入值
dynamic_cast<PhiInst *>(phiinst.get())->delBlk(basicblock.get());
dynamic_cast<PhiInst *>(phiinst.get())->removeIncomingBlock(basicblock.get());
}
} else { // cond为false或0
pBuilder->setPosition(basicblock.get(), basicblock->end());
pBuilder->createUncondBrInst(elseBlock, {});
pBuilder->createUncondBrInst(elseBlock);
// 更新CFG关系
basicblock->removeSuccessor(thenBlock);
@ -558,9 +679,8 @@ bool SysYCFGOptUtils::SysYCondBr2Br(Function *func, IRBuilder* pBuilder) {
break;
}
// 使用 delBlk 方法删除 basicblock.get() 对应的传入值
dynamic_cast<PhiInst *>(phiinst.get())->delBlk(basicblock.get());
dynamic_cast<PhiInst *>(phiinst.get())->removeIncomingBlock(basicblock.get());
}
}
}
}
@ -573,28 +693,28 @@ bool SysYCFGOptUtils::SysYCondBr2Br(Function *func, IRBuilder* pBuilder) {
// 独立的CFG优化遍的实现
// ======================================================================
bool SysYDelInstAfterBrPass::runOnFunction(Function *F, AnalysisManager& AM) {
bool SysYDelInstAfterBrPass::runOnFunction(Function *F, AnalysisManager &AM) {
return SysYCFGOptUtils::SysYDelInstAfterBr(F);
}
bool SysYDelEmptyBlockPass::runOnFunction(Function *F, AnalysisManager& AM) {
bool SysYDelEmptyBlockPass::runOnFunction(Function *F, AnalysisManager &AM) {
return SysYCFGOptUtils::SysYDelEmptyBlock(F, pBuilder);
}
bool SysYDelNoPreBLockPass::runOnFunction(Function *F, AnalysisManager& AM) {
bool SysYDelNoPreBLockPass::runOnFunction(Function *F, AnalysisManager &AM) {
return SysYCFGOptUtils::SysYDelNoPreBLock(F);
}
bool SysYBlockMergePass::runOnFunction(Function *F, AnalysisManager& AM) {
return SysYCFGOptUtils::SysYBlockMerge(F);
bool SysYBlockMergePass::runOnFunction(Function *F, AnalysisManager &AM) {
return SysYCFGOptUtils::SysYBlockMerge(F);
}
bool SysYAddReturnPass::runOnFunction(Function *F, AnalysisManager& AM) {
bool SysYAddReturnPass::runOnFunction(Function *F, AnalysisManager &AM) {
return SysYCFGOptUtils::SysYAddReturn(F, pBuilder);
}
bool SysYCondBr2BrPass::runOnFunction(Function *F, AnalysisManager& AM) {
bool SysYCondBr2BrPass::runOnFunction(Function *F, AnalysisManager &AM) {
return SysYCFGOptUtils::SysYCondBr2Br(F, pBuilder);
}
} // namespace sysy
} // namespace sysy

View File

@ -1,10 +1,22 @@
#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 "SCCP.h"
#include "BuildCFG.h"
#include "LargeArrayToGlobal.h"
#include "LoopNormalization.h"
#include "LICM.h"
#include "LoopStrengthReduction.h"
#include "InductionVariableElimination.h"
#include "Pass.h"
#include <iostream>
#include <queue>
@ -34,10 +46,20 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
3. 添加优化passid
*/
// 注册分析遍
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<SysYDelInstAfterBrPass>();
registerOptimizationPass<SysYDelNoPreBLockPass>();
registerOptimizationPass<SysYBlockMergePass>();
@ -48,13 +70,29 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
registerOptimizationPass<DCE>();
registerOptimizationPass<Mem2Reg>(builderIR);
registerOptimizationPass<LoopNormalizationPass>(builderIR);
registerOptimizationPass<LICM>(builderIR);
registerOptimizationPass<LoopStrengthReduction>(builderIR);
registerOptimizationPass<InductionVariableElimination>();
registerOptimizationPass<Reg2Mem>(builderIR);
registerOptimizationPass<SCCP>(builderIR);
if (optLevel >= 1) {
//经过设计安排优化遍的执行顺序以及执行逻辑
if (DEBUG) std::cout << "Applying -O1 optimizations.\n";
if (DEBUG) std::cout << "--- Running custom optimization sequence ---\n";
if(DEBUG) {
std::cout << "=== IR Before CFGOpt Optimizations ===\n";
printPasses();
}
this->clearPasses();
this->addPass(&BuildCFG::ID);
this->addPass(&LargeArrayToGlobalPass::ID);
this->run();
this->clearPasses();
this->addPass(&SysYDelInstAfterBrPass::ID);
this->addPass(&SysYDelNoPreBLockPass::ID);
@ -64,6 +102,10 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
this->addPass(&SysYAddReturnPass::ID);
this->run();
this->clearPasses();
this->addPass(&BuildCFG::ID);
this->run();
if(DEBUG) {
std::cout << "=== IR After CFGOpt Optimizations ===\n";
printPasses();
@ -88,14 +130,37 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
}
this->clearPasses();
this->addPass(&Reg2Mem::ID);
this->addPass(&SCCP::ID);
this->run();
if(DEBUG) {
std::cout << "=== IR After SCCP Optimizations ===\n";
printPasses();
}
this->clearPasses();
this->addPass(&LoopNormalizationPass::ID);
this->addPass(&LICM::ID);
this->addPass(&LoopStrengthReduction::ID);
this->addPass(&InductionVariableElimination::ID);
this->run();
if(DEBUG) {
std::cout << "=== IR After Loop Normalization, LICM, and Strength Reduction Optimizations ===\n";
printPasses();
}
// this->clearPasses();
// this->addPass(&Reg2Mem::ID);
// this->run();
if(DEBUG) {
std::cout << "=== IR After Reg2Mem Optimizations ===\n";
printPasses();
}
this->clearPasses();
this->addPass(&BuildCFG::ID);
this->run();
if (DEBUG) std::cout << "--- Custom optimization sequence finished ---\n";
}
@ -110,6 +175,7 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
SysYPrinter printer(moduleIR);
printer.printIR();
}
}
void PassManager::clearPasses() {

File diff suppressed because it is too large Load Diff

View File

@ -240,6 +240,10 @@ void SysYPrinter::printInst(Instruction *pInst) {
case Kind::kMul:
case Kind::kDiv:
case Kind::kRem:
case Kind::kSrl:
case Kind::kSll:
case Kind::kSra:
case Kind::kMulh:
case Kind::kFAdd:
case Kind::kFSub:
case Kind::kFMul:
@ -272,6 +276,10 @@ 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::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;
case Kind::kFMul: std::cout << "fmul"; break;
@ -295,7 +303,12 @@ void SysYPrinter::printInst(Instruction *pInst) {
// Types and operands
std::cout << " ";
printType(binInst->getType());
// For comparison operations, print operand types instead of result type
if (pInst->getKind() >= Kind::kICmpEQ && pInst->getKind() <= Kind::kFCmpGE) {
printType(binInst->getLhs()->getType());
} else {
printType(binInst->getType());
}
std::cout << " ";
printValue(binInst->getLhs());
std::cout << ", ";
@ -408,7 +421,12 @@ void SysYPrinter::printInst(Instruction *pInst) {
}
std::cout << std::endl;
} break;
case Kind::kUnreachable: {
std::cout << "Unreachable" << std::endl;
} break;
case Kind::kAlloca: {
auto allocaInst = dynamic_cast<AllocaInst *>(pInst);
std::cout << "%" << allocaInst->getName() << " = alloca ";
@ -419,17 +437,6 @@ void SysYPrinter::printInst(Instruction *pInst) {
auto allocatedType = allocaInst->getAllocatedType();
printType(allocatedType);
// 仍然打印维度信息,如果存在的话
if (allocaInst->getNumDims() > 0) {
std::cout << ", ";
for (size_t i = 0; i < allocaInst->getNumDims(); i++) {
if (i > 0) std::cout << ", ";
printType(Type::getIntType()); // 维度大小通常是 i32 类型
std::cout << " ";
printValue(allocaInst->getDim(i));
}
}
std::cout << ", align 4" << std::endl;
} break;
@ -442,17 +449,6 @@ void SysYPrinter::printInst(Instruction *pInst) {
std::cout << " ";
printValue(loadInst->getPointer()); // 要加载的地址
// 仍然打印索引信息,如果存在的话
if (loadInst->getNumIndices() > 0) {
std::cout << ", indices "; // 或者其他分隔符,取决于你期望的格式
for (size_t i = 0; i < loadInst->getNumIndices(); i++) {
if (i > 0) std::cout << ", ";
printType(loadInst->getIndex(i)->getType());
std::cout << " ";
printValue(loadInst->getIndex(i));
}
}
std::cout << ", align 4" << std::endl;
} break;
@ -467,16 +463,6 @@ void SysYPrinter::printInst(Instruction *pInst) {
std::cout << " ";
printValue(storeInst->getPointer()); // 目标地址
// 仍然打印索引信息,如果存在的话
if (storeInst->getNumIndices() > 0) {
std::cout << ", indices "; // 或者其他分隔符
for (size_t i = 0; i < storeInst->getNumIndices(); i++) {
if (i > 0) std::cout << ", ";
printType(storeInst->getIndex(i)->getType());
std::cout << " ";
printValue(storeInst->getIndex(i));
}
}
std::cout << ", align 4" << std::endl;
} break;
@ -535,9 +521,9 @@ void SysYPrinter::printInst(Instruction *pInst) {
if (!firstPair) std::cout << ", ";
firstPair = false;
std::cout << "[ ";
printValue(phiInst->getValue(i));
printValue(phiInst->getIncomingValue(i));
std::cout << ", %";
printBlock(phiInst->getBlock(i));
printBlock(phiInst->getIncomingBlock(i));
std::cout << " ]";
}
std::cout << std::endl;

View File

@ -21,6 +21,8 @@ using namespace sysy;
int DEBUG = 0;
int DEEPDEBUG = 0;
int DEEPERDEBUG = 0;
int DEBUGLENGTH = 50;
static string argStopAfter;
static string argInputFile;
@ -33,7 +35,7 @@ void usage(int code) {
"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";
@ -108,6 +110,7 @@ int main(int argc, char **argv) {
// 如果指定停止在 AST 阶段,则打印并退出
if (argStopAfter == "ast") {
cout << moduleAST->toStringTree(true) << '\n';
sysy::cleanupIRPools(); // 清理内存池
return EXIT_SUCCESS;
}
@ -130,7 +133,7 @@ int main(int argc, char **argv) {
if (DEBUG) {
cout << "=== Init IR ===\n";
SysYPrinter(moduleIR).printIR(); // 临时打印器用于调试
moduleIR->print(cout); // 使用新实现的print方法直接打印IR
}
// 创建 Pass 管理器并运行优化管道
@ -142,10 +145,26 @@ int main(int argc, char **argv) {
// a) 如果指定停止在 IR 阶段,则打印最终 IR 并退出
if (argStopAfter == "ir" || argStopAfter == "ird") {
// 打印最终 IR
cout << "=== Final IR ===\n";
SysYPrinter printer(moduleIR); // 在这里创建打印器,因为可能之前调试时用过临时打印器
printer.printIR();
if (DEBUG) cerr << "=== Final IR ===\n";
if (!argOutputFilename.empty()) {
// 输出到指定文件
ofstream fout(argOutputFilename);
if (not fout.is_open()) {
cerr << "Failed to open output file: " << argOutputFilename << endl;
moduleIR->cleanup(); // 清理模块
sysy::cleanupIRPools(); // 清理内存池
return EXIT_FAILURE;
}
moduleIR->print(fout);
fout.close();
} else {
// 输出到标准输出
moduleIR->print(cout);
}
moduleIR->cleanup(); // 清理模块
sysy::cleanupIRPools(); // 清理内存池
return EXIT_SUCCESS;
}
// b) 如果未停止在 IR 阶段,则继续生成汇编 (后端)
@ -164,6 +183,8 @@ int main(int argc, char **argv) {
ofstream fout(argOutputFilename);
if (not fout.is_open()) {
cerr << "Failed to open output file: " << argOutputFilename << endl;
moduleIR->cleanup(); // 清理模块
sysy::cleanupIRPools(); // 清理内存池
return EXIT_FAILURE;
}
fout << asmCode << endl;
@ -171,6 +192,8 @@ int main(int argc, char **argv) {
} else {
cout << asmCode << endl;
}
moduleIR->cleanup(); // 清理模块
sysy::cleanupIRPools(); // 清理内存池
return EXIT_SUCCESS;
}
@ -179,5 +202,7 @@ int main(int argc, char **argv) {
cout << "Compilation completed. No output specified (neither -s nor -S). Exiting.\n";
// return EXIT_SUCCESS; // 或者这里调用一个链接器生成可执行文件
moduleIR->cleanup(); // 清理模块
sysy::cleanupIRPools(); // 清理内存池
return EXIT_SUCCESS;
}

200
testdata/performance/01_mm1.in vendored Normal file
View File

@ -0,0 +1,200 @@
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 Normal file
View File

@ -0,0 +1,2 @@
1151854256
0

89
testdata/performance/01_mm1.sy vendored Normal file
View File

@ -0,0 +1,89 @@
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 Normal file
View File

@ -0,0 +1,301 @@
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

2
testdata/performance/01_mm2.out vendored Normal file
View File

@ -0,0 +1,2 @@
830422199
0

89
testdata/performance/01_mm2.sy vendored Normal file
View File

@ -0,0 +1,89 @@
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;
}

261
testdata/performance/01_mm3.in vendored Normal file
View File

@ -0,0 +1,261 @@
130
202 498 237 413 -830 -723 -503 603 783 -73 -718 158 315 608 -587 -271 597 320 762 670 515 -860 565 -328 990 -531 -906 562 -923 502 822 55 553 576 -221 -775 -471 116 580 -476 -242 518 -751 190 613 -130 -653 -624 365 -439 -265 403 -296 527 666 6 829 675 -843 -894 885 24 874 228 -739 279 621 -806 -231 -635 396 62 -893 780 988 907 420 -976 -968 -588 52 559 -183 597 878 -459 -570 747 640 -993 -237 97 674 160 -41 437 -610 -426 -245 -958 548 321 687 -893 -607 -689 -933 137 -525 615 -503 732 568 -218 -768 842 -997 425 454 832 -150 66 553 -47 -732 728 -695 -167 -235 966
-105 183 -253 624 747 30 974 235 672 -433 904 437 995 -604 -495 -267 157 874 630 -219 827 -688 912 552 329 428 -369 -837 544 -776 -842 -978 700 783 649 -831 123 455 -495 224 -726 -615 88 -190 -628 -920 231 -701 -84 -760 -381 -786 -622 888 -196 -861 -601 -978 -751 -195 -1000 103 -46 -177 -746 -183 643 836 -452 839 -20 -271 158 511 -219 553 -439 855 -557 287 -694 -18 199 -797 -696 -484 124 708 126 376 485 -754 237 -335 344 -442 -343 221 497 297 289 -505 254 -230 -868 -399 661 -807 -847 -183 361 967 382 -518 505 -685 681 -125 -45 791 -238 -948 -489 765 331 -539 -903 984 552 -963
-792 -670 219 354 597 29 397 -794 396 -993 -925 -684 -762 267 -544 58 476 -104 -705 855 -288 -25 71 751 13 -39 -609 180 -442 105 -25 121 -834 395 804 -962 55 236 -964 419 -860 260 628 553 308 -297 -943 -409 -15 -372 412 728 -577 170 569 685 451 851 -420 433 -782 -957 500 -245 177 788 -961 539 -579 717 -203 -452 -280 617 628 323 -784 -812 -856 -791 474 -617 -176 118 351 -25 1000 145 570 -630 820 141 201 -443 801 939 -599 -864 -40 -743 586 729 287 -923 -417 -211 -645 806 870 -551 -486 -30 -912 912 -577 46 -477 -831 585 -843 279 -269 368 919 -864 -28 -702 501 937 -656
-96 887 -323 -943 567 -726 55 894 -944 -116 -649 631 -596 985 627 8 213 -306 -408 -146 -494 918 827 780 996 310 288 981 -486 -462 -68 -522 -624 -89 -681 -666 128 -881 557 629 252 785 807 603 -58 -837 504 621 417 -10 124 437 7 549 686 433 -665 -354 484 -419 185 -363 580 866 33 812 954 -273 504 -723 -630 -464 -894 -28 765 217 -404 545 78 -274 -800 -379 -690 -637 969 -269 28 -829 -73 -609 -131 -645 982 -150 947 269 853 -766 963 -511 726 360 34 -17 944 310 510 -455 -435 57 -435 765 -596 370 -778 647 -675 376 -283 -149 787 774 110 -519 -5 -102 -387 263 840 -101
286 -845 691 673 -975 -920 120 -773 150 -712 -544 37 917 413 472 -770 -319 990 -686 682 -63 41 -101 -379 103 -737 889 977 919 214 565 743 388 254 -130 313 511 -87 117 657 674 -784 -888 122 770 -706 -890 -820 386 -468 -280 -21 -823 850 675 -403 -205 972 -747 -795 -915 241 753 -696 906 663 -492 -544 382 -706 446 744 894 -226 570 -629 -681 -309 324 -813 718 -287 -451 236 32 423 -604 -501 -502 -584 492 158 -978 853 -617 -173 533 331 -855 -9 628 -627 -204 945 -123 -758 -734 812 427 -777 503 309 -878 -176 516 -981 -727 675 -318 -918 698 -562 -774 -246 -574 -960 -905 243 -526 811
-500 363 148 -19 -268 -522 845 304 200 -781 415 -834 995 -29 -167 466 270 -174 687 721 -854 894 34 -742 499 -119 371 -649 26 315 339 -295 583 782 -356 899 -358 731 96 958 -544 -854 245 -208 881 -230 -907 750 367 385 -200 345 -456 -59 -282 -196 -478 -813 149 216 -680 -464 580 -650 -869 -398 710 222 284 93 -192 -153 -771 -103 608 -94 -604 -793 -673 302 -835 -141 -930 561 341 -955 -663 -284 947 766 149 -537 -395 293 -411 479 738 240 347 -884 -723 588 184 623 -925 -173 221 -471 182 756 673 869 443 572 -361 -287 -752 -727 -604 -629 -25 233 -351 607 915 439 241 -765 -20 -724
-12 674 -170 -16 465 -943 -674 459 -87 346 823 649 650 788 159 897 -213 -606 -70 -324 355 1 914 -720 209 981 404 778 -291 107 91 939 744 864 752 150 -886 567 792 990 73 288 585 -257 540 -449 411 484 360 -746 -935 56 912 -100 92 806 256 -122 277 209 17 301 -142 -97 449 975 164 0 736 -59 -730 862 208 -593 -922 -478 906 79 -314 840 -492 831 -166 130 570 447 -356 1 -746 -955 489 -199 -36 -13 174 -179 -63 -826 -682 299 990 895 855 632 -969 546 -142 786 420 -402 -458 -734 958 989 9 544 125 -368 668 486 93 580 -549 -543 -318 -95 730 673 300 -390
-140 -995 381 657 644 -675 569 -796 815 -243 463 725 365 -350 -689 -1000 979 434 -853 -376 -674 262 771 -7 116 163 759 -215 -621 -300 83 -233 -235 -631 811 463 -858 687 -546 297 815 579 15 96 -769 885 327 409 -284 -610 493 -234 -171 90 22 1000 -94 250 -212 -206 -427 -732 -519 -458 862 648 -354 294 308 -534 -448 659 954 -317 520 420 -456 602 666 -66 497 -128 699 -796 -949 108 434 128 -688 -600 -855 -67 -111 570 838 -335 345 -13 -534 -579 442 423 -343 -496 -527 464 372 -359 -486 -761 -175 944 240 226 196 652 611 595 -504 -395 -828 571 -74 254 -409 -732 360 137 903 -34
-355 -646 -33 -694 -757 696 30 -626 350 -425 -62 219 -942 -107 246 516 264 -883 -903 -165 -400 -926 -99 773 889 165 -156 5 197 -337 113 -257 -745 -44 149 -520 377 552 78 125 -330 225 -419 -753 -676 413 189 -180 510 -898 978 -809 515 431 -59 -109 -445 725 688 654 -133 340 -859 -805 -404 76 489 611 -301 -558 -7 -544 82 791 648 355 -680 -407 -532 47 -438 -510 29 -118 -436 -532 -545 121 751 821 205 143 950 -529 -448 575 -668 -506 -163 898 382 181 -40 836 -287 707 -721 957 -818 -57 855 251 -235 -659 110 -111 30 467 -979 -423 -962 501 -237 621 -199 63 695 -545 798 -751
460 -135 169 790 -591 -767 122 955 83 -784 411 41 370 462 -286 17 -532 903 302 -368 875 -850 -69 314 845 763 -986 831 -588 112 750 -977 607 -843 15 464 365 841 132 716 -580 163 335 -852 -649 153 -858 702 444 949 429 347 154 -903 -550 -576 615 988 -429 -165 614 -321 -589 -518 684 -283 -839 282 323 741 -621 -582 797 -749 -978 -463 948 -768 410 -944 320 -790 -155 -715 -978 635 890 969 799 678 923 -637 954 603 -710 -296 -820 306 443 -871 -251 32 -23 -373 -172 -300 -851 -537 -36 497 -37 195 35 -988 -730 765 955 -264 -85 -110 947 -321 365 -42 374 -680 -250 -42 -810 -904
-300 381 32 208 598 -475 -953 -948 330 -925 -362 563 460 279 -102 679 -831 905 -563 178 572 990 -821 -366 799 -201 -578 -190 699 613 -303 -213 983 -246 875 133 303 752 758 925 577 383 935 -820 687 -115 818 -968 769 814 -683 -551 -715 762 -691 371 29 636 696 203 -785 -743 -892 576 366 -28 -544 -452 740 -702 305 -458 -440 -917 -895 -852 -426 108 966 -336 96 817 582 -612 -776 -92 -496 666 -826 249 89 -380 -231 -949 482 -801 518 578 395 320 -192 102 -122 467 940 270 -383 489 -328 -924 -331 300 -56 -483 -6 151 943 441 600 468 -215 -150 212 -902 -356 107 -15 567 656 -764
43 -713 -137 943 -878 820 556 93 738 -72 882 -331 -387 205 956 -765 917 -41 -876 138 223 -188 951 -132 796 439 -373 -574 232 417 687 958 558 741 209 -620 -854 -837 -12 850 207 308 -265 -938 -299 -652 641 -232 54 -538 789 188 -585 -245 790 -534 -192 377 205 -275 -339 865 -490 -31 482 -198 707 340 724 197 -535 -367 -774 724 795 750 -250 -77 -367 30 -677 405 843 -120 -709 217 331 -24 -484 674 893 -476 164 -650 -845 -690 -194 -878 -593 372 894 -996 -131 795 906 -408 -857 -571 319 -605 -351 -157 763 -217 -292 258 388 729 748 788 511 -986 236 701 -904 629 508 -15 465 -462
132 623 207 -272 -705 -719 535 -125 -704 558 517 327 -459 795 221 -595 -85 989 784 463 -589 -584 577 599 -772 7 -759 675 -836 -913 -414 -27 -188 -776 680 -750 988 -456 -280 655 -531 99 291 804 686 -434 889 -353 626 -4 -310 147 -861 393 751 -142 -119 110 623 -10 428 1000 196 918 -425 -342 905 -120 759 52 49 106 -518 174 -929 -305 246 876 -238 -205 -193 430 -386 -800 -324 400 -676 -759 253 628 -893 324 -733 -153 -870 917 169 245 -411 -910 -878 222 -724 885 448 671 234 -123 273 -743 -566 651 591 764 -296 62 -86 829 462 828 -191 -642 -698 -281 -409 301 993 -278 422 479
597 -837 -769 288 -870 -88 -91 426 -312 -285 602 -183 120 -922 -332 654 320 -288 -665 -864 -183 35 604 391 -114 808 -507 -484 -692 786 -824 822 7 -60 423 -432 409 202 -705 -140 640 -440 215 -506 -684 -558 -129 -619 651 625 841 368 693 390 -825 -302 -65 754 -816 -473 779 -763 13 219 40 520 -150 798 -498 -969 -883 -42 690 -357 809 -41 -846 374 -375 952 802 298 930 507 363 794 -562 419 -852 -888 1 919 421 -197 334 9 -155 -844 -611 892 -759 975 -737 108 -927 16 848 311 -637 186 -836 771 551 -337 -572 852 -243 431 361 41 124 -537 -944 -764 -481 120 34 -27 -186 -110
-461 -804 -623 736 -790 -470 168 -934 -692 -397 -361 -309 -615 654 -105 111 556 52 -193 486 -27 2 -746 -547 525 -801 835 452 -423 -729 -21 -476 109 501 -700 -659 583 906 979 205 773 285 530 220 -383 68 -223 -68 554 -296 498 -861 630 730 401 470 857 121 -821 -646 575 273 278 969 965 475 -26 682 923 217 -100 -766 -410 -672 441 -544 -719 -323 531 131 154 -92 -317 186 -933 -419 463 -584 514 259 -856 176 106 -778 -996 -444 -274 -494 537 589 -120 539 257 -139 -737 -743 465 -57 225 366 87 -360 -729 -190 -42 -322 923 -4 552 -612 628 703 233 581 -173 1 -690 372 -983 65
-655 218 810 -336 281 814 815 100 -804 698 909 308 482 643 -304 193 783 440 -233 46 -614 -142 -534 289 -753 378 -654 335 -824 -808 610 -700 356 -148 -444 -343 223 33 -197 -258 309 399 -696 731 -292 -918 35 -456 -511 990 726 -45 -236 -308 304 -872 -410 -877 -465 984 -939 476 -948 -265 565 226 769 694 879 -683 329 382 905 -396 -185 307 -460 -926 -804 162 889 -207 917 -543 398 -840 603 823 58 97 -180 825 225 593 -606 -817 108 246 670 609 -746 -948 -59 805 -629 593 -995 -413 228 429 991 -768 554 -252 604 -897 -130 -597 -780 -48 -848 -57 426 743 -425 -415 909 -42 504 -51
-494 -90 743 270 -138 234 -667 -918 112 219 547 696 -399 -196 -972 233 546 -290 -637 997 -450 647 273 337 -624 108 -502 -518 -69 405 731 -954 -448 426 656 417 -173 557 -562 528 -911 926 -245 -208 -152 -530 11 753 380 878 247 581 -787 601 906 358 -375 192 17 580 -904 259 -308 -360 896 126 -771 -785 493 429 -895 -342 500 -905 -703 -513 729 -328 308 -757 -173 396 -600 522 -38 -91 -787 806 378 831 938 415 -988 451 674 -931 -954 300 158 -649 142 -490 -491 884 372 604 -650 -174 -185 -903 -408 733 604 814 -376 765 -543 748 -477 183 173 767 -781 -414 -925 882 -70 -130 -517 -637
684 -632 596 -375 551 -127 -827 94 580 -271 577 983 -379 -620 1 -74 719 108 44 863 455 463 -583 -151 492 190 546 -920 139 918 709 -751 316 471 593 -84 288 378 276 -583 -105 139 85 -223 807 -820 962 -332 -883 209 -427 -561 192 768 162 -538 -785 89 -882 69 160 -139 -413 -633 159 909 414 226 -995 -567 -464 584 922 -477 867 438 302 -289 -39 -892 111 553 758 32 -592 -137 -828 -431 -219 124 526 -203 -669 865 994 735 134 -664 -461 -266 630 628 251 592 -729 723 862 -321 961 696 946 -519 486 -390 -426 402 -757 515 89 61 -592 426 -355 -20 -411 -945 -958 -64 352 -446
-801 950 341 -879 237 17 -932 -370 88 -189 -522 -443 737 785 893 -154 -594 210 729 -376 -199 154 415 -774 687 -267 807 -556 -827 277 -792 -584 417 108 -749 485 -202 578 -521 -294 -3 495 -281 -965 462 699 663 -383 -972 18 -513 603 -449 838 364 -527 -207 565 975 837 447 44 -492 -579 -238 571 782 628 -879 277 -711 -108 308 -304 -836 -65 -102 -802 -797 723 676 -643 910 49 -403 809 -336 560 882 216 443 -755 -651 -880 -363 622 656 915 713 955 -571 274 -421 -844 -175 -334 -711 -116 -764 550 -141 387 -612 -50 -801 -813 -557 -902 817 160 829 -740 868 -153 -759 -223 -755 -944 110 -600
-451 279 -316 -932 -542 673 -61 -662 -954 -102 562 761 -121 -487 -453 497 561 187 -611 578 -556 735 -421 964 -487 -777 633 -947 -936 809 -710 -782 -762 930 -46 115 42 -42 -255 -30 621 763 -290 256 -410 -42 -112 -569 323 102 443 915 463 739 -142 612 -633 717 465 -54 274 699 355 284 -683 353 -653 40 -907 -110 605 938 819 -206 -227 -838 -116 -926 739 -780 -628 653 -746 558 201 -168 265 3 -257 744 -412 -134 -88 521 413 -866 365 431 -841 -125 -430 552 -289 426 127 879 579 -431 458 911 572 325 405 645 -586 895 326 -348 97 877 735 947 -881 -494 223 -458 565 980 -790 -242
-47 557 -641 -327 -512 741 204 -171 213 881 539 -23 383 259 -705 944 303 374 -671 -932 180 68 -998 -278 722 -635 637 673 193 229 74 480 -433 455 -69 775 401 837 -211 -341 -549 905 -68 850 -614 -118 996 -582 -47 -840 -895 -207 -364 -771 -488 -171 -211 22 451 362 -872 637 441 -3 799 557 228 -375 -104 -457 925 -976 -694 -518 -350 558 -822 -784 0 943 -51 -334 -687 -379 502 740 910 -821 650 971 278 995 -626 -425 -284 -396 766 -710 407 415 294 513 376 -843 -885 118 -158 -907 350 -9 530 -831 268 439 366 553 -700 150 -575 -142 750 -159 -547 -465 968 130 723 -28 234 446
661 -835 -622 -428 297 -598 722 352 647 591 -739 -176 -793 -905 136 -667 -926 431 -217 806 766 443 274 -168 -51 310 581 410 627 167 -380 -628 -881 371 -338 125 612 -814 -367 171 -686 378 -637 347 472 -168 625 -42 994 -650 613 -216 -287 -596 629 215 884 574 788 -955 912 -134 157 -451 842 -875 -241 782 461 775 937 509 -395 -70 -202 766 -241 -777 555 327 934 -836 695 -887 -401 -88 -854 -499 296 136 -118 248 674 -480 378 -726 -498 179 -162 321 798 -224 877 81 -33 -626 118 -336 -900 -556 -430 625 -104 313 604 -201 -793 252 -466 -245 612 -316 835 -241 -216 -662 89 766 114 -978
-459 340 529 -1000 703 128 53 -227 8 -721 666 -299 -205 441 -933 467 -926 74 299 485 -433 37 -105 356 -183 -562 942 -478 965 -917 296 967 -924 205 691 860 -849 33 337 -526 975 -631 -551 -889 949 198 -945 -29 -903 -28 486 -900 -561 434 648 -344 293 425 824 641 -164 923 -682 20 -422 892 -435 -6 -646 160 245 116 415 -499 -347 571 566 178 -743 609 -599 -973 843 -926 -727 532 21 764 54 -305 975 352 917 -601 95 -886 354 -142 994 -414 318 238 675 884 55 910 -621 -385 -437 614 -752 685 40 224 -814 343 64 -140 -757 718 67 912 719 -99 325 295 139 -264 -730 -476
943 319 -844 -294 758 447 -619 904 -421 763 288 -208 150 -58 -104 538 109 801 -889 -191 -5 -684 765 877 887 -103 -388 928 -861 435 672 441 353 -163 -850 -77 274 895 699 -352 -123 -475 -202 -844 625 381 -742 -453 584 684 -84 -948 1 -528 366 -744 -893 -321 -190 686 87 -363 -54 -818 475 593 341 -358 -811 -502 -764 -193 179 240 -628 710 108 -832 -135 -397 -672 389 -104 -267 163 -432 875 936 723 -622 -266 202 923 -662 648 -352 849 -117 -325 21 -299 -347 -148 175 -445 340 126 913 963 -670 -320 400 -305 -712 -805 -140 -19 -810 944 448 596 -11 949 208 350 464 -163 -99 -186 615
201 398 -328 -943 223 -190 -181 806 25 247 541 -430 -822 103 -905 87 -286 401 -151 -284 44 -890 -665 -503 75 -951 -560 905 -982 358 367 244 573 -635 -74 -808 -433 467 -467 86 689 479 -274 734 919 -897 -411 604 997 810 -623 167 -701 138 -218 207 -571 861 -523 -84 -742 -423 279 93 161 574 -86 617 109 521 60 -443 122 -346 -807 330 -298 100 -872 -478 459 -278 175 -751 860 -407 -248 -693 913 5 168 -146 -654 361 -469 -782 -358 -396 -133 425 103 -111 -981 587 -58 -550 -414 161 -16 163 96 491 570 921 30 -837 -942 148 -273 -564 534 -776 -635 628 789 -243 594 744 553 112
354 195 163 649 -694 245 -390 -442 939 496 -733 -300 -718 25 614 414 -174 294 817 533 486 -24 -316 56 -55 963 53 598 -774 -218 325 63 -678 -812 -435 843 405 762 -869 413 -40 -318 211 38 896 794 156 -136 250 -446 568 -952 98 -130 96 -858 814 -760 -388 -23 -582 -646 571 -898 236 593 799 958 -904 -980 -495 746 296 -759 -846 -551 -296 -214 548 724 556 669 334 -316 -524 -535 -1000 788 -543 -214 -449 261 720 -955 -948 810 -862 -740 -351 770 967 -234 -463 443 -526 342 -188 594 -930 981 -778 66 -891 883 -895 -956 708 857 -382 -931 -930 -171 841 -172 -739 292 -937 715 -504 -319
-627 -152 697 834 -113 981 495 -52 437 828 67 52 -154 293 -403 -988 868 343 507 -55 286 -533 953 586 -738 58 543 306 459 361 434 -736 81 -416 322 -950 -180 -930 120 174 -31 136 -593 896 500 236 -84 -53 392 -394 -665 -181 -927 490 -742 660 -355 -874 772 -437 -648 740 -620 -918 -486 848 -750 -891 -871 674 719 501 -854 496 -146 -775 -603 229 -354 -730 -369 -282 258 329 -95 -111 74 898 -28 247 390 818 -53 -582 417 175 65 599 -297 -386 409 406 -236 -547 -174 437 408 81 156 304 -685 696 138 -376 -715 62 358 -833 189 -739 -662 15 145 804 -188 153 -851 -875 -836 -523
110 726 330 -358 429 295 -207 821 -698 -864 873 -277 522 41 777 168 -11 535 599 -222 -633 174 74 -557 286 585 -708 642 -306 -701 24 776 893 769 602 278 -629 990 657 361 -511 404 723 772 116 -978 -496 42 937 794 -928 -334 185 -341 689 -110 899 442 -15 150 860 480 -734 562 -437 -740 557 489 -195 -190 452 308 -431 -892 209 -524 727 -105 336 107 -462 9 741 454 -574 197 -597 -719 993 -864 54 822 864 -833 -343 603 808 -992 219 856 392 926 -18 734 -649 172 357 523 850 701 -615 -351 -257 -101 -207 590 -771 682 -593 657 445 982 52 -914 233 957 525 462 -472 207
-168 -246 186 -362 -137 -718 -87 206 -960 -16 -218 899 318 -702 -886 -3 -691 -870 363 198 -164 105 746 -774 524 -39 -963 -126 -973 986 920 329 -630 -200 -517 -237 -972 289 575 467 782 -335 -909 878 762 815 513 -867 147 677 930 92 -448 -454 654 -431 -626 550 -109 -587 -334 852 928 669 -357 862 450 885 108 -506 604 -303 733 -987 804 62 611 -392 278 -520 278 646 716 -372 -63 -960 -142 -674 260 -943 -971 345 55 -768 319 -735 520 -428 246 -860 94 -570 436 287 -413 772 -675 -122 -348 228 414 501 957 605 302 -266 -724 117 985 947 -247 -502 -185 -530 -986 -164 -776 -276 207 367
571 683 -873 -423 900 41 324 -1 -436 174 -746 660 -728 151 783 957 -424 -845 -120 -523 494 -619 -521 244 156 -872 136 503 923 -767 -868 -496 -18 -632 644 -462 -382 -828 -788 545 188 911 -867 -477 -135 612 -851 -775 471 -482 532 865 151 461 -927 765 -201 30 536 909 931 -917 -128 -234 -136 603 -403 608 229 812 -506 460 166 498 -936 642 -759 -185 838 -263 -431 -756 -992 969 970 476 -545 -160 708 58 742 -551 -454 137 -752 -722 -564 962 -247 -785 -388 913 477 483 -326 -945 -937 -993 154 940 938 -294 -982 144 -489 -16 -494 879 -538 193 -257 -247 -115 -403 -503 -304 -524 0 167 995
930 -657 -578 -642 -777 -175 639 907 -965 773 653 -580 895 -826 -314 385 -373 -249 -361 -957 -613 -462 351 -864 -616 -812 110 -429 -531 -553 929 311 -478 -535 -57 451 -261 592 429 -490 -637 -623 -402 -12 562 -643 775 -421 -241 -212 370 -175 -936 -66 20 742 397 298 -723 -177 -390 -668 769 -193 191 820 -211 -810 71 -495 393 -887 345 -162 -872 -535 240 440 785 -814 732 403 174 454 -218 -625 846 988 -563 -452 -957 254 -991 525 -697 121 -185 -218 -513 -758 95 -621 -51 124 -962 -410 711 126 616 217 -859 -520 -10 757 605 -658 315 872 504 -477 709 499 -272 505 349 -293 810 -580 418 -229
391 -139 -535 764 295 548 352 577 -918 410 -43 -885 595 173 -130 774 589 527 -785 -965 337 598 -324 272 391 679 314 -131 -823 321 -118 966 -72 -896 -354 355 -249 380 -7 -431 -52 271 -852 -416 -205 308 185 -347 944 377 -225 204 726 -415 736 911 -572 -662 -994 -896 -895 681 508 857 851 -987 135 563 471 10 -21 715 183 688 273 673 904 992 -47 597 -5 -234 630 80 207 535 469 976 -190 -240 176 544 259 -950 -841 -143 -781 378 649 201 -281 176 -772 947 714 520 -400 -966 366 29 -240 -88 -934 393 507 458 1000 871 -312 -373 -79 457 581 -962 -600 -195 -193 -884 -969 -248
-643 -559 -678 769 -227 462 672 435 -294 -312 760 -327 761 288 740 -729 -832 -262 -817 784 -968 -712 666 280 -274 428 427 -953 -65 -372 -64 310 59 -549 -45 -475 147 -642 -981 146 -653 -628 -432 654 -158 -656 934 -401 -156 468 -720 927 797 -301 103 -875 934 846 -254 -995 -239 -659 360 195 599 -270 41 -776 -182 410 -876 -504 -893 -320 887 -379 -936 -549 -20 807 797 7 243 964 504 -14 -870 -606 811 397 -40 -156 874 -203 665 36 667 -93 2 80 186 -369 770 647 336 -52 -36 476 371 -898 573 -230 -960 996 978 171 -229 43 456 700 642 108 18 -428 771 820 -276 -881 29 -776
153 -192 -703 32 327 -606 -331 438 430 -583 588 969 -638 -608 -317 297 129 -641 136 -159 891 -729 -305 -482 -451 211 63 -523 519 -13 -189 -124 -939 244 167 710 998 440 -431 -207 259 -763 -567 797 492 921 183 430 -624 595 -358 -473 799 786 726 804 -567 922 -165 613 367 -463 -842 -703 845 998 155 -580 470 41 -515 -901 -37 464 835 8 196 8 340 -150 117 -12 804 227 -860 664 -452 -235 740 252 -849 460 -178 806 770 -107 194 -11 -640 -549 500 -737 -366 162 482 -268 -834 -179 385 -195 700 -930 -658 -806 193 449 69 -449 404 446 -1000 100 989 -61 -192 -8 -621 774 -629 363
-66 889 327 186 -28 -857 -39 190 424 -986 676 894 113 -550 786 419 336 858 -723 181 205 228 -220 -703 704 892 187 -805 -527 -340 967 -599 -54 827 180 542 -230 -689 326 -400 -139 599 864 -243 179 -489 84 -166 384 876 -966 697 -176 896 -642 -50 -968 -798 922 -123 -2 -377 -865 -254 -625 249 -116 -104 -41 20 955 146 147 236 348 869 630 681 -922 38 670 549 -248 157 637 453 -628 -609 -844 296 -988 196 601 -109 -873 389 895 851 241 -444 -570 -851 -405 -393 437 496 -430 47 563 -671 134 670 -83 672 301 263 933 573 -674 -738 52 -205 807 -178 -676 265 523 -276 -391 880
-404 682 509 -215 -294 120 -754 -234 -968 -689 950 -342 -632 595 32 -855 764 15 853 178 913 160 722 535 241 -53 -286 21 -554 -280 540 -610 -583 -987 -629 -547 624 -10 712 -195 -359 859 -593 285 -504 -915 -311 376 277 882 -71 344 972 761 815 -939 977 276 270 510 -768 569 409 453 69 555 -690 -575 43 569 -939 838 783 623 -908 -932 -457 -369 -597 137 -886 793 505 -137 184 -31 -327 836 353 70 832 719 -318 26 -945 368 -150 75 714 669 -54 -479 -939 -165 544 -634 329 718 635 180 25 -363 866 914 480 78 989 79 530 -740 -597 -806 929 -163 -700 -77 693 -795 71 -427
805 -946 167 834 -837 298 195 -785 110 618 32 -704 -232 467 -362 -915 620 652 -525 796 -765 958 947 -381 -337 222 -585 678 515 262 -332 -108 -153 144 168 -260 798 -37 -175 90 -185 303 -509 -226 -479 443 -408 -125 -11 521 -665 -423 -408 -163 206 530 -192 -333 752 342 427 678 -578 538 -391 286 92 303 -310 -662 -229 -854 514 513 36 939 -806 -395 -236 -499 540 -480 -108 -172 -614 273 -461 -306 -831 -476 -990 717 261 -104 -891 -847 -469 -609 907 284 147 152 593 -397 432 -994 -776 483 613 -289 410 910 718 648 291 -714 -595 -69 300 485 883 134 -691 -173 294 336 661 -185 381 -83
-339 -527 513 -643 -902 -347 133 -943 140 -156 -92 -73 -351 -504 -565 -445 -173 159 -282 995 -810 -353 -107 -709 -84 -890 216 19 -969 627 396 178 693 -426 -185 -605 -277 744 -592 -181 947 -134 -333 435 567 376 -223 720 -551 -939 -182 -758 633 936 779 975 -156 -400 528 766 169 -994 858 -512 656 509 -593 155 -932 -833 253 800 764 -193 704 -644 445 -542 -719 866 -579 849 388 -1 -719 115 17 -156 859 -849 895 -923 356 -499 526 364 -779 -852 899 -3 -436 135 593 622 -22 -657 -722 231 897 99 -660 144 -99 620 969 152 -881 -905 98 -372 -478 -106 -910 -115 -362 -375 -455 728 283 978
-193 909 -115 999 -371 674 195 117 -73 -749 133 -228 782 -857 -995 504 895 416 -183 935 -812 -43 192 207 -62 223 -713 -742 308 -589 928 879 -486 856 616 -119 -825 -180 149 583 -139 977 976 810 -195 857 -408 -988 -976 424 464 730 -365 -18 762 170 -52 -669 -349 186 278 855 241 -502 485 -47 518 -798 465 456 -405 -915 -14 -91 -144 -187 -737 951 533 -118 -57 168 168 107 -249 -535 268 -188 -753 379 -379 -834 695 -695 -392 -809 -638 961 -31 899 -216 393 933 -293 -606 -384 424 283 -320 -151 -687 872 -893 -501 -188 -610 -307 256 -505 152 -776 -943 998 290 -772 -981 729 -104 161 -910
222 477 852 555 -224 807 -44 5 -306 492 823 357 621 516 856 -853 146 128 -209 613 283 10 -848 557 -223 831 -351 685 -500 -550 -965 550 -220 978 -611 269 -413 -98 -884 -68 -417 -563 -789 357 -412 800 -656 -252 -197 -947 -359 -397 172 -505 296 935 972 -325 -623 -660 -247 565 -273 653 696 997 310 -476 -741 503 109 -658 123 -592 -764 -742 728 851 991 842 699 -506 440 -481 36 -77 -416 -168 137 -417 247 -426 848 -335 -216 -385 800 154 894 868 195 597 386 -492 36 -71 -842 -471 -315 -712 950 559 578 -62 -591 -176 -777 -817 197 -4 -899 -331 -523 -240 12 -689 789 -816 327 -956
328 -755 -219 -665 -573 307 843 333 345 -410 238 -994 -466 -892 -634 606 -632 -165 -844 -952 -495 967 984 -596 -983 -538 -181 411 56 371 670 -348 -848 405 -848 311 -843 864 251 506 965 892 -866 611 -307 -966 -168 294 550 -988 -11 785 224 14 501 -19 -600 -261 19 -89 -52 -117 -555 -327 670 414 404 -387 -237 -985 -992 3 679 -137 -19 -937 784 -1 899 644 507 166 -944 904 929 716 -533 -481 108 -899 -166 49 -992 726 681 -131 48 305 -370 100 67 17 432 52 -273 941 760 655 284 -202 389 -98 217 316 223 396 945 -371 -400 848 61 -311 -526 477 -526 -545 83 532 -822 504
878 -375 -169 -678 597 -758 0 842 -284 345 635 -561 -235 -889 -122 845 128 -885 485 -627 -29 -966 574 -665 561 -244 -434 -399 -366 528 203 -614 444 642 431 445 -280 -431 -811 -575 -64 725 362 82 -531 531 731 654 -496 -235 -963 353 -222 87 595 -368 718 425 752 229 132 -197 -898 -160 924 -141 -838 -776 711 95 814 675 954 -598 -614 838 370 269 720 -342 -210 -652 838 112 -605 643 582 -383 -512 -426 -578 318 -419 893 60 -591 212 903 -195 286 -414 122 359 -532 839 737 153 -361 716 -757 -517 300 780 -428 -729 72 -538 -761 -917 79 -566 151 96 797 -576 -95 -152 474 947 -407
-416 -313 -629 -825 991 -277 294 -66 -866 621 -869 401 -977 602 339 735 -930 785 -763 -916 651 998 954 -245 -783 460 -35 -481 855 -424 998 -542 205 335 -591 449 -409 427 498 485 -189 -232 83 -758 868 198 -29 164 554 667 -896 -822 -148 307 874 -348 -515 198 228 -467 -182 -25 -400 406 -695 -626 -650 -256 -74 800 698 -535 -52 -966 544 -396 -366 731 -133 -391 -861 -782 -373 -457 958 -904 -899 -847 813 982 481 -479 168 568 -50 57 742 -209 345 -166 678 461 763 516 801 371 231 736 480 -198 730 -778 494 60 -978 819 527 800 -355 648 -470 -164 788 980 -930 -893 799 670 618 -161
-912 -922 -412 954 -938 684 284 489 -890 -779 -199 729 -922 888 864 -793 -722 808 388 -654 -975 -49 797 859 -325 -158 509 863 737 705 794 911 -146 -512 -12 -239 880 659 837 -222 990 -887 -175 908 95 -714 388 850 591 -691 101 -168 -891 -684 -239 865 -302 177 -414 -890 -935 -992 764 -564 768 -891 -36 471 467 -674 -137 842 -838 -765 -926 -570 -934 736 268 382 809 518 812 815 -283 840 576 -622 510 -801 -753 484 -688 -550 943 -670 468 239 -759 -560 -859 517 361 655 885 918 758 -107 -581 -220 301 -874 440 355 -600 -692 -999 -861 711 -872 -454 40 183 -472 -218 -215 94 528 319 527
640 -955 -298 -857 -94 468 701 580 873 -593 -422 -701 -357 134 851 324 -785 50 767 -706 337 -15 418 -330 379 513 -4 -528 -64 -360 -75 -426 -717 331 144 938 -657 813 988 -476 -875 -780 -738 831 576 -372 578 -874 -12 768 -466 -8 575 -275 -507 508 643 -731 -820 -345 -583 -630 555 -540 -375 483 -274 -45 173 770 374 -777 621 926 931 831 -315 321 67 566 -475 848 723 -371 222 -142 782 596 -631 889 -21 -431 -150 -218 -115 830 -546 -957 777 983 -955 254 969 6 -968 483 828 -248 580 434 -869 508 -610 999 85 762 -990 -212 143 516 -285 -963 -254 158 392 891 -336 -771 613 -914
-626 371 663 755 44 746 258 661 -572 666 -275 470 -953 558 758 -276 -276 -836 246 492 -693 -949 16 146 -480 957 75 580 670 143 -767 -486 -801 -186 -845 300 -276 164 -89 183 -398 385 -916 28 703 -882 273 -609 -72 488 -952 274 270 376 282 -222 241 -654 290 -589 -465 908 -861 -615 643 219 312 -966 729 964 813 255 -48 -188 937 -1 -78 176 -485 -672 -288 -273 997 717 -571 771 -475 23 -948 -343 655 117 155 609 -224 -401 -500 801 69 -876 -77 437 210 970 -221 -543 -508 -936 902 329 202 -568 -608 -197 -215 446 997 -223 6 355 -877 -750 -12 492 -944 -614 742 267 -537 -859
-477 826 -565 -306 797 880 -821 -340 -773 860 572 620 -118 -388 264 -1000 166 -878 -335 -406 -223 -384 -935 -870 921 106 236 -954 876 863 125 885 -892 -484 -570 599 768 596 206 -580 -627 175 -917 -733 -230 -590 -962 421 605 -80 519 193 -11 -145 -933 -588 72 601 -869 121 595 967 -656 -89 -467 -194 360 499 61 158 -985 895 -348 -794 337 -245 -672 693 -98 -109 -451 991 -635 -800 -588 -485 915 -889 -425 898 492 -13 -698 110 799 971 865 657 593 951 -150 -595 -381 -376 -414 -903 36 567 -552 659 947 85 -500 -790 792 732 476 144 -96 -770 -470 -76 -890 681 701 86 276 473 177 -90
-197 836 -926 490 -99 -973 -1 -50 -463 -275 -724 -942 -407 -695 -155 -257 -27 -558 597 -933 -428 677 900 544 624 -87 277 -342 80 451 -787 490 871 -218 -660 494 -225 917 -529 -405 872 -471 -743 808 525 778 -197 -673 -724 -440 692 744 419 868 949 -310 -698 289 -832 -912 65 897 11 603 573 -417 361 -88 -176 79 689 544 560 -663 -755 988 -29 229 934 -626 592 -412 493 108 -405 124 717 -363 -367 935 -579 929 -204 -250 437 97 944 -313 996 -357 -752 352 695 656 -24 72 -906 523 -283 -296 -243 501 688 -606 -267 -764 -731 924 782 515 -38 -93 132 -590 905 -725 202 817 564 -578
817 358 -741 -459 580 31 824 715 -47 948 -649 996 147 204 903 534 -541 289 649 943 -561 327 -821 48 -539 426 -584 -667 -237 999 591 674 802 -933 -729 -474 -881 -30 -112 -899 -432 540 -452 -825 -554 73 -426 20 610 313 606 -377 283 -751 119 282 -237 830 670 993 -226 440 -575 289 -406 -904 -826 -121 539 744 -166 246 -891 -10 -220 -273 908 287 -216 -238 115 -21 -308 -50 207 61 -348 478 -83 696 -468 -927 -612 -674 540 -564 652 -504 72 -220 -726 468 243 -566 -526 -67 -478 -191 176 463 -434 342 -685 -89 366 338 586 336 -210 595 -8 912 -376 -394 593 652 -236 145 -920 280
857 -7 -500 131 -137 -612 718 685 963 686 754 -201 663 -316 -383 1000 329 -441 776 -445 828 637 12 -266 -793 -295 549 748 -974 -149 -277 -423 387 -309 649 -448 -448 729 299 -195 -247 -19 -174 -519 283 843 -26 -564 500 594 637 -753 -225 259 -466 -693 -723 827 -103 110 92 -949 882 13 693 -930 500 -300 -957 216 -22 -945 866 969 -378 740 840 751 -434 557 343 325 -615 -9 414 26 -228 685 -779 392 253 465 -35 -504 389 -648 113 587 -812 -561 500 828 -217 -136 -527 -569 709 751 -678 167 -609 448 -855 679 -523 877 -181 614 -789 775 476 166 745 480 -282 706 -99 -3 271 928
-226 -204 703 322 433 677 -440 -543 -107 411 -675 -785 -512 360 -111 -43 27 328 -428 -849 -268 -217 -110 -200 -410 -463 -60 -39 -946 -927 608 137 -255 447 764 -977 -682 -123 694 394 -577 -325 866 442 -66 261 -893 476 -664 -872 -114 -357 205 -757 443 -816 -289 840 272 -58 613 -104 857 -122 586 -659 -825 584 -125 -592 -920 -732 -662 -292 52 -415 -127 571 566 -817 -531 11 217 -995 -438 -647 793 376 -896 816 -533 71 -892 -701 -128 -559 -691 779 -469 -209 557 -4 569 715 -4 -52 -831 462 -837 -50 888 -652 733 986 277 541 547 -396 940 552 418 894 273 154 941 357 -810 337 -543 -153
-642 902 998 -226 -313 266 588 -802 668 -559 383 867 -434 -971 791 -102 -725 538 -249 581 735 780 201 -887 -239 421 -601 -818 -654 -678 -464 764 572 337 588 385 -13 -374 461 -207 409 -598 97 -329 -611 959 870 -568 -582 -227 898 -53 635 -294 204 931 795 40 -29 -205 295 -468 402 209 107 891 -634 -866 -277 -945 -693 737 216 -400 -954 29 -785 488 793 18 -58 -832 469 -57 170 124 496 -61 -529 -60 143 -165 136 -13 -267 504 105 -914 706 388 240 -201 -348 189 353 966 -800 -384 -935 -188 -10 -743 806 -997 -961 -415 330 -595 394 -19 -999 138 -356 911 585 -746 453 -801 816 376
100 -179 14 844 -17 -128 609 531 722 -805 797 -276 602 6 -670 168 -159 -327 784 913 -996 546 -862 806 -393 701 580 357 -647 -673 -941 257 334 -118 -573 -206 999 -862 909 733 989 428 -484 73 199 -817 229 -306 779 -279 -234 -667 -924 -472 -120 429 826 290 49 136 74 904 972 -829 246 -147 855 -910 416 -812 350 641 -650 -107 500 -931 154 917 -753 200 79 -578 -297 -216 -562 952 -977 -669 375 588 -533 -386 865 504 679 -324 -351 885 -458 268 -618 857 -658 -677 383 -644 47 -319 -334 984 306 -560 521 992 -170 -405 -85 -135 565 488 -82 -707 -352 -256 93 -777 768 540 328 -118
-189 687 631 -401 318 364 -94 519 -510 372 222 338 822 295 -804 -900 -898 460 -408 161 275 725 -305 594 -322 -622 -238 -633 245 -930 -501 -325 54 521 644 105 -567 753 523 760 -231 430 877 -995 -426 139 -168 440 -344 -725 901 -80 497 -211 678 623 -896 -318 -198 650 -837 -267 525 -544 847 -232 -684 339 -965 491 511 -445 -443 -704 -346 871 413 142 -84 78 12 -889 833 995 -293 827 -11 -524 277 827 -65 -141 -174 658 -360 -318 -147 -849 -459 -956 -388 -567 -191 973 445 -414 876 573 975 29 -626 -666 -47 -579 -709 -744 -758 312 -923 42 584 455 740 790 -121 -154 -821 -56 -926 54
-320 43 -221 435 -415 678 686 677 300 500 387 -92 -727 542 406 -601 -92 448 902 -711 -267 -984 297 859 279 -571 -398 33 844 236 -637 -579 290 -646 870 -685 -399 -331 176 198 181 -566 -161 519 665 852 825 -836 -170 -582 -191 962 -595 142 -905 -858 141 479 967 -836 397 585 -383 183 996 520 -398 -884 410 559 -732 -39 589 -376 -857 714 -426 -989 -730 612 532 -89 721 840 282 -894 540 379 840 701 -174 -684 -268 -172 953 -473 -831 682 765 -717 -6 138 -160 6 794 -340 -731 -546 893 38 518 523 -700 288 -475 717 -636 -481 820 -24 349 -916 -548 887 -308 142 240 -120 -21 -15
710 299 -881 509 -825 971 799 580 -274 -927 590 -910 125 -621 344 884 -619 -211 -4 -809 -6 145 -419 579 793 -553 -133 -751 -893 -355 -233 -11 947 -223 -913 -285 -628 -470 -515 267 521 732 -960 672 764 786 -478 -893 792 -42 -995 -488 834 -826 262 -3 -565 283 758 529 47 -585 146 -760 9 -171 -856 -991 -164 -798 -671 -811 432 -741 822 865 246 -507 692 -516 295 623 588 -279 579 515 859 -909 -503 521 247 -435 671 902 -6 -764 -768 767 -929 -704 -581 492 -348 714 844 -717 -944 -74 -741 -163 -639 -37 31 -890 -453 -182 815 914 -64 -948 109 -208 -183 133 -514 -870 -592 -647 975 -934
-989 -754 139 86 -981 -378 -712 919 294 896 868 -366 21 -366 172 -240 256 524 184 -167 416 -265 -907 -755 -548 107 -495 -508 -611 525 -573 791 -371 -482 727 134 -242 -907 92 515 937 258 -63 -74 284 568 441 832 -639 727 -248 522 116 112 -310 6 429 147 -828 509 -820 -268 585 218 -855 35 944 -643 -714 -756 -233 -664 -837 -370 328 -872 -446 87 699 855 934 974 991 271 547 759 371 -405 -196 315 79 830 101 -622 38 969 -718 -677 405 -777 -686 -696 -738 -770 984 309 588 -531 -890 -566 -767 -297 -345 260 -88 607 553 -966 -357 62 -84 55 590 -332 -223 794 702 -171 -538 -169
-255 185 3 -62 -328 -893 14 -861 -598 -191 632 228 -516 507 -926 -815 -382 488 -483 794 -729 73 201 957 -960 -278 932 -287 472 421 -838 957 542 -339 993 227 -678 532 535 257 -190 714 -896 -698 530 -837 907 596 -113 -579 156 -189 -15 752 320 -262 -676 276 585 20 57 943 295 -986 -426 903 314 616 114 681 136 -133 -591 617 851 704 245 893 -680 -116 -421 916 80 -802 495 -953 -173 -332 -959 -156 736 -973 359 520 838 -688 -914 -288 -468 -314 -234 816 347 -189 -30 719 -373 -519 343 882 816 -924 -901 -647 -405 955 202 -464 728 -730 -400 -869 126 858 454 192 -44 -737 -307 -749
560 909 403 -52 -142 484 -808 -888 112 -661 983 -963 462 419 558 -87 -607 217 175 718 64 -567 -232 -799 -244 16 -573 -749 630 97 -284 -147 -885 73 -729 -599 359 145 -428 -705 -614 -430 183 -192 509 -743 345 -168 180 355 841 -750 31 561 981 354 134 -837 646 488 133 -930 186 171 -313 24 194 540 -417 467 440 265 730 150 891 399 -999 -335 -583 441 -715 124 742 -813 -592 654 552 -461 379 -561 -177 869 -670 855 563 967 975 797 -94 -101 628 -725 947 -897 -682 -711 -217 15 -448 206 -621 -649 147 702 701 -84 31 -756 359 183 799 97 -717 444 -316 -762 973 -821 388 949
-804 -207 155 229 459 -612 831 -267 -38 2 942 -286 -290 -855 -562 362 -64 922 610 56 -304 78 -964 -764 218 718 -807 240 -654 121 -442 -37 40 585 -155 285 844 14 -758 629 -884 -808 -869 974 -216 -484 637 -537 -315 733 706 -445 -574 -972 -330 -168 885 272 866 995 743 966 -39 929 -677 11 -434 620 -983 -66 -743 -788 828 -71 906 923 400 357 -626 401 643 -735 -38 514 -57 888 913 423 997 451 933 918 866 -98 693 -124 -944 -810 -971 -920 -792 -980 50 -58 -672 230 128 210 -692 853 443 -980 495 -48 921 -520 -499 -287 545 -655 975 509 -194 587 487 -823 -960 -527 863 -945
-89 61 941 599 -880 -138 -637 -630 -604 -46 530 -733 -452 -403 -63 771 845 -945 -311 317 885 -601 -52 944 -140 -456 -661 -858 -559 69 712 -201 -476 971 -640 -751 -635 214 659 309 -867 -295 511 -10 -900 995 807 -256 663 905 -208 666 -671 998 -776 -126 983 523 857 -368 280 -181 -689 852 -286 26 116 -259 -923 -249 238 546 -139 11 -440 196 994 843 354 675 535 290 983 -293 629 -904 724 323 -364 -140 430 -904 939 334 934 -959 -754 78 173 106 -247 807 979 697 -564 557 927 -48 -416 180 -189 840 559 622 229 453 -612 65 851 511 -154 242 852 292 -383 870 296 -904 -254 304
-490 -735 186 -980 850 599 -670 -112 449 602 878 -426 134 -881 797 562 -88 322 -416 -731 866 881 -850 414 82 -317 -915 696 -967 -665 625 873 -281 -779 -521 437 744 626 563 489 -926 820 338 837 -81 -757 -561 -462 845 872 501 272 213 -115 -720 29 -763 848 935 -42 -221 -433 -358 -790 233 680 -222 34 -624 -607 -900 907 -289 264 757 14 -539 -963 67 -945 514 505 918 66 966 663 -904 933 -381 927 321 -453 905 -733 -667 -624 148 -535 -742 143 840 -782 855 -771 463 -472 357 -8 807 666 259 32 44 469 -241 -390 -104 -714 -674 -652 352 -39 -681 169 -855 96 -532 -514 767 456
657 163 280 -474 -594 27 -739 -471 -531 -333 804 89 930 337 -164 -333 -825 -636 762 -650 211 427 88 -724 -849 -222 275 -555 105 26 -567 393 -507 292 -945 482 520 -1000 632 -799 989 -27 150 -582 -996 -236 -852 137 -14 241 -947 750 -227 224 359 -520 121 -659 -888 720 -33 986 365 -482 -137 777 881 -241 727 427 -187 870 -447 844 510 -551 -313 -259 -603 34 -206 -322 -814 -743 867 765 177 251 -515 539 -547 -371 -468 526 830 933 -676 82 -305 972 446 -499 -414 566 46 227 -711 954 827 353 465 314 -481 -740 364 -224 51 869 -464 -920 -594 615 -249 -509 -528 -933 935 -409 706 37
226 -605 108 486 718 -50 628 -721 -900 578 -777 -449 -158 -673 -967 -184 -336 173 -325 -862 696 518 705 148 -351 -315 469 747 -527 89 593 -389 549 980 481 -967 490 239 -512 820 186 -891 161 -370 755 -779 442 35 946 -328 900 -957 590 237 -849 -18 922 321 168 -798 166 848 -660 560 176 -671 -179 -383 -295 345 955 586 768 403 788 790 465 21 -980 -573 -57 217 614 584 -233 606 750 -387 559 -187 822 -349 249 -920 -773 410 -323 455 50 82 335 -84 -43 -920 29 -884 -552 -299 781 580 502 733 980 206 680 -774 771 -512 -504 403 582 -862 816 -33 -49 199 -560 529 -947 -101
-497 481 91 -988 886 215 -590 -253 311 -373 558 605 871 -917 -551 677 339 -572 745 -615 -866 -131 -358 210 732 -292 -789 125 180 -466 10 -983 -655 276 809 485 -45 566 -38 431 -465 -949 -92 135 855 -881 278 -289 957 906 527 715 531 36 -290 76 -350 995 -795 735 -888 165 -971 -689 329 -121 446 -791 851 414 91 -585 -549 -239 583 990 807 745 -48 609 -391 -834 751 736 456 -382 393 -814 -57 336 317 -738 501 -253 -764 -772 -238 -59 -485 -622 -404 -28 957 70 -128 53 107 474 -334 806 -828 -779 890 459 979 -458 347 -386 -40 -61 917 905 720 -640 -992 -282 328 -855 -147 208
-156 -281 -877 723 916 491 -563 -531 -89 607 604 173 -332 -87 909 -166 -905 409 483 -19 746 557 569 -653 -875 249 584 -531 -655 932 698 888 -138 425 -849 -374 741 393 566 646 46 -814 -719 -987 523 -38 -120 -844 -316 158 383 903 916 48 655 700 757 118 622 49 879 144 -321 -730 -432 714 649 402 -677 120 -702 4 -581 688 614 -655 -692 -62 880 885 -272 972 156 717 195 523 -376 657 241 -793 509 965 317 -705 -184 881 81 168 831 -82 -118 96 337 -840 876 -680 -988 152 -711 -431 503 316 507 -400 435 681 -88 -179 -165 -190 -512 707 -476 231 -871 273 85 522 701 -672
903 -295 505 597 453 -652 -238 -767 -150 -314 -904 472 -394 -624 -850 -14 -213 -776 175 -665 -375 -500 -35 63 -396 -953 462 -790 -491 341 -799 -545 696 -556 644 873 -694 331 123 293 -925 -890 -121 -18 -295 675 184 938 819 -562 -524 618 737 -68 513 -850 475 -738 -281 816 -694 -425 941 -656 731 -175 627 343 784 827 -923 318 -458 700 -211 -695 548 449 994 -374 161 -71 370 -184 -864 -703 -579 -468 920 618 810 554 -762 -765 963 885 850 -22 549 949 -432 335 452 562 -66 -738 540 1 295 -737 -154 -846 984 976 776 671 -790 33 -605 -221 136 -287 272 869 574 -936 -543 -50 -921 -818
-338 969 464 -467 -921 -151 -13 -367 222 362 236 793 926 964 866 -571 -655 776 615 -676 -41 537 985 820 -404 -104 928 -284 -15 -463 952 -430 67 -742 261 240 -70 -719 -345 -682 77 629 498 732 569 893 -103 -978 -166 -598 -918 477 527 646 -544 -701 -537 -149 -500 -91 7 958 726 -234 -490 -413 841 -882 -835 513 423 -216 -521 -68 -818 -661 -144 331 -896 43 -660 274 -40 -863 231 126 381 -674 -169 814 -984 472 -343 200 -95 -292 399 443 744 -244 17 639 -297 127 -572 127 409 658 472 -442 932 -662 545 788 -222 -144 -975 984 659 -708 -81 831 -413 240 -483 624 941 21 -893 -79
-389 -826 -420 155 -198 -971 -644 -113 -181 -955 -582 556 -292 -964 -525 -550 486 480 -104 -138 -788 -114 324 -655 979 -170 -688 612 299 899 -963 636 768 174 344 790 958 419 -100 63 856 685 -433 635 -951 889 -600 -337 -752 424 -623 -657 200 -393 -568 -74 157 -569 -326 -760 465 -408 186 115 -684 124 -576 -934 -189 582 -164 686 684 124 596 503 -752 -951 -383 -73 -190 724 -904 321 -525 -402 -215 -66 996 576 -928 -877 575 -513 -321 -781 -331 -421 -557 290 568 442 460 -729 -483 899 -59 155 234 21 -913 -152 -17 -982 -587 -647 815 374 861 -854 746 170 -594 192 -359 -781 -760 -529 -825 -455
354 -451 -972 -290 437 -803 -27 427 -863 -138 -153 299 -639 -599 -413 -344 760 -424 -266 -681 -730 -928 -786 -511 -733 401 -74 -960 438 663 -321 -763 -686 910 65 975 -73 527 461 749 -859 -994 -265 -320 -805 820 -143 777 -457 -717 39 -360 -524 114 725 235 -112 -336 689 557 611 635 251 329 -169 580 391 -384 422 -227 -504 -616 -225 143 948 -901 182 681 -907 875 -519 445 539 422 311 -63 -695 -726 42 -413 584 380 -709 -708 124 565 -658 687 47 -575 -668 -771 -61 -458 6 190 812 -654 -759 315 -460 -812 262 486 -473 573 946 41 -561 -745 -426 -636 937 224 557 -871 293 -996 932 -84
993 746 37 -307 648 417 -309 880 -977 93 133 504 -956 -559 -406 -570 527 -705 420 -595 10 -918 -358 695 359 -729 -703 240 701 158 603 -657 -598 -375 158 983 -404 -665 -480 -567 -18 152 -464 159 986 207 957 775 -449 333 321 205 -320 98 21 -456 135 566 991 69 -382 -401 459 695 548 841 -88 -102 210 -960 786 243 285 -528 555 437 -146 -602 -186 59 -632 121 -288 -366 857 -572 654 -492 130 219 234 -731 -801 -580 -426 241 -667 235 -250 -187 -814 504 -529 -60 -228 115 959 267 805 -215 -319 -795 926 -611 101 -852 310 -192 322 890 286 -383 651 -938 -374 830 -573 911 -113 -734
-284 -643 341 664 556 -268 -456 -985 -885 -69 669 245 610 900 833 978 -588 -981 -22 -885 -798 169 93 -179 425 705 479 377 -918 490 -157 -956 -805 -803 -877 225 206 683 126 -708 -616 -338 174 -432 511 128 -549 -233 -309 615 554 -544 822 546 -732 -794 418 -965 720 -706 953 123 -461 -275 -503 275 -571 816 -4 292 -71 753 -623 397 550 214 -365 817 785 -925 -784 744 372 773 194 562 793 -262 -656 828 -782 592 -405 58 242 -484 959 336 828 624 -832 694 -61 137 29 538 -172 -59 -172 -865 -318 -918 -443 671 691 573 876 844 748 874 -134 805 -976 -55 974 261 -972 -499 -11 179
-186 570 363 -899 249 -473 -820 -706 40 -643 -203 -29 -833 436 992 875 793 -422 994 -366 -179 -104 -890 641 -872 -460 -624 -900 983 324 471 -982 945 731 -73 384 -797 218 -353 59 -963 154 -536 66 747 463 147 470 657 450 -570 377 170 -284 441 537 -307 -837 -753 -210 466 -209 -458 928 -573 264 434 159 -592 -395 -490 273 -428 149 182 978 876 -543 -282 281 -502 -646 611 848 -305 889 -286 -107 -966 -485 884 143 -182 -862 892 472 959 73 -742 592 -778 572 -484 -947 179 881 319 161 983 859 -671 135 -449 -753 45 -253 335 -716 953 62 -939 225 -150 645 118 -142 -879 -975 -247 -138
423 423 -797 257 76 679 -476 -327 -570 365 -223 -186 -484 -493 534 -480 -235 -995 -308 223 -426 -216 -112 784 178 -647 -33 -252 -594 -764 -282 -123 727 989 676 -484 -763 -680 -848 618 -632 -499 653 304 -161 455 960 -117 -609 951 938 -867 -595 -813 696 -88 -867 768 484 475 493 -701 510 -824 963 -701 -238 -228 684 280 447 -686 -142 702 -108 -542 97 -297 270 35 156 672 880 96 -528 710 -671 21 953 348 -274 -372 -995 -379 908 136 -382 773 -845 345 -670 -19 68 -989 3 -582 227 -646 323 268 -455 -629 -461 -366 585 594 -211 839 -307 -17 -149 -967 -653 -691 241 -365 213 496 520 540
-400 -31 795 41 -450 -278 -886 -233 96 -329 -239 928 -712 770 -212 360 695 541 -886 -533 -660 -456 871 874 -119 -203 139 312 -14 -121 -314 849 640 834 893 826 931 -736 -77 -368 -573 250 748 -781 -412 -489 -848 279 -811 441 -611 -767 817 -79 623 -322 -121 -205 826 -387 -739 990 -109 -636 612 -380 483 -707 857 -448 -7 845 368 -649 -281 -522 -219 -505 -154 0 871 490 -720 -955 -982 996 -997 -578 -939 -61 -938 -493 -555 281 -737 116 -794 78 -93 -171 -409 -190 799 308 525 -856 -325 379 -274 -760 535 -556 -988 678 421 -99 -984 -766 114 -909 -947 -471 847 183 358 -18 23 860 964 -959
-718 -822 -431 -753 -643 -991 415 740 788 616 89 421 419 775 -57 -947 214 -582 644 -119 -43 -64 -384 -873 543 295 577 347 -451 576 -518 558 -249 489 -27 773 -107 -217 563 40 -410 -104 -910 -929 48 246 -985 687 314 -394 650 -262 474 -105 210 -77 412 594 39 496 -165 -467 655 -319 865 -739 395 -64 -38 -3 -456 -979 -312 590 945 872 -464 130 -913 392 111 -540 727 -704 972 -133 -449 -821 272 -213 -263 -784 -499 939 -424 -889 -258 524 -121 -47 -644 -283 381 960 64 327 -452 -591 -8 423 120 -659 -624 924 -793 690 -429 663 579 -835 -725 -798 437 -397 -279 713 919 -45 198 -605
718 520 65 589 607 -571 135 -66 -924 -466 787 626 -551 621 -961 -422 28 -29 -968 119 152 478 985 -416 -56 -424 -984 -529 20 -477 -126 -780 -796 106 777 -223 953 150 246 -914 556 -336 157 678 -198 -563 472 -900 392 -800 860 -659 -286 -517 -714 -365 -163 931 -448 292 505 975 -263 -754 813 448 583 -782 -341 -444 475 -647 436 -192 154 -296 846 683 -761 17 305 806 407 507 346 88 -646 -993 -233 282 215 -624 561 685 772 214 261 607 800 750 387 929 -673 164 -627 153 670 371 453 -473 387 -544 -91 618 -750 612 45 483 -977 -594 424 897 124 -355 -527 103 -16 -534 822 71
317 -433 -420 -954 -357 -550 953 -963 477 -166 765 65 -577 -948 -891 15 445 874 119 577 205 718 586 87 -134 -706 57 -933 262 99 -749 178 -103 -442 802 -72 -495 468 255 -503 38 -112 -761 883 366 305 341 -880 -92 528 737 -364 105 -360 -134 931 -675 -603 -840 -827 136 474 289 -479 27 318 377 582 985 -224 -30 171 601 -181 -343 195 522 137 448 -905 699 -473 -96 -94 -220 75 762 207 196 209 920 -653 158 121 763 -977 641 117 747 -371 601 -775 656 -886 569 -74 -74 732 755 19 867 972 -587 -249 -45 203 288 586 -998 474 494 940 -48 516 -627 185 679 -361 941 -469
282 519 -953 -307 937 965 647 -809 -444 -901 -261 -66 -464 817 -14 542 765 -835 -656 539 -803 300 -29 907 409 -473 611 67 704 281 53 850 -253 335 -273 740 -655 -638 -1 -808 -776 156 -220 153 386 -261 -379 -559 -178 -389 941 41 235 826 343 -564 -886 -566 124 -822 965 713 239 629 -529 -742 -624 242 -127 6 -851 365 -868 -296 -706 -715 -331 679 -822 -3 177 598 19 137 385 -890 246 -567 5 -396 535 536 428 72 468 -535 964 424 -291 -479 23 71 306 -400 579 575 385 542 -845 478 -38 787 362 -495 -592 578 -213 842 17 -722 -70 -992 241 109 364 129 -921 -268 949 389
-958 379 819 120 780 -287 -861 807 824 -518 -150 875 -588 104 -464 93 -779 56 424 -98 -811 534 -918 814 -867 -194 176 532 -424 394 673 -71 -506 -464 46 202 421 -582 -606 648 195 -159 -299 864 247 568 700 76 657 523 47 211 -300 -753 331 319 -52 -822 -718 478 -558 37 475 -409 703 578 799 465 764 326 -292 435 614 518 95 138 78 225 -356 -302 -385 -525 -755 -275 175 -407 73 579 2 470 546 -138 608 791 810 -822 850 288 -697 -486 688 636 910 -241 -90 -771 574 -953 779 -477 -331 871 -777 -341 421 739 -737 -884 582 259 345 -286 565 312 -616 186 64 707 -833 229
-362 -859 -841 -594 154 -651 -679 315 835 -618 585 612 683 808 -510 -723 -690 -143 -50 -600 -468 945 297 -114 -690 63 -778 930 -546 -384 794 698 -751 -685 -307 -837 555 164 -437 296 -953 667 -144 -727 -114 632 137 558 -8 -255 652 -292 -552 -248 -579 942 -884 -528 167 504 -455 -136 511 -976 965 -726 -968 -405 -98 901 715 -149 104 570 -942 555 365 -562 486 -347 752 740 -388 -455 809 834 -612 337 -251 -697 384 165 770 651 -13 695 -682 -71 -888 192 647 646 871 -728 -466 121 -169 -936 776 179 645 53 66 548 157 4 633 903 -995 69 -122 -987 -105 309 -323 -858 -592 523 -823 646
-576 -269 589 739 -958 51 180 -116 -543 -437 -944 198 598 -682 352 -454 983 -991 167 833 -100 -413 -581 -562 -382 448 823 -612 -895 -518 124 -606 173 927 -948 102 287 -941 761 -954 -477 -322 -329 877 581 -744 -835 -132 563 645 655 -992 -62 -585 -61 -31 902 577 -116 -472 -720 -580 896 -77 -747 14 -27 633 -856 -714 -884 508 185 339 -572 -82 -39 936 -153 643 -410 241 248 -3 -892 823 468 793 352 442 -752 -837 169 860 -809 554 -416 -985 -75 -163 -769 -283 404 384 -774 -40 37 -591 881 -690 171 630 -836 -459 -899 -673 300 -917 -861 -60 -861 176 -105 57 424 -226 -799 -23 -459 207
-698 -623 895 339 634 859 -624 -107 -440 565 -445 427 596 -270 851 -837 -5 320 294 208 -834 -614 -90 -934 -453 -786 255 -390 -169 132 921 973 -654 -711 -151 -902 931 276 525 -619 591 984 991 956 635 -480 -307 303 355 253 141 260 932 -352 -178 283 -278 86 415 -98 -658 549 -98 -128 -353 972 -419 11 734 638 575 -546 -772 714 -966 171 893 -597 -117 -238 989 223 658 350 -555 -130 94 994 995 862 65 860 258 -798 -173 -799 -24 -894 405 -362 -147 694 850 781 -892 82 449 -226 288 926 -382 -982 -96 -89 -650 -859 -62 185 532 -9 -953 -601 -717 -401 -542 -772 837 -573 416 -97
881 250 -409 -312 -565 232 -435 -58 238 -756 91 -739 -765 -408 154 -104 -943 383 745 -591 -178 62 -663 -488 597 649 -777 848 -231 227 -993 190 -476 -834 -574 -441 177 51 -479 -110 118 851 753 -338 267 969 13 844 620 -572 909 -693 -130 847 268 -288 -326 300 -281 -156 994 -442 49 -808 -365 -158 639 -983 591 -274 455 934 221 774 999 146 475 -575 203 437 -950 850 -346 254 -536 602 -805 -427 322 400 -816 366 612 347 -434 -848 397 561 942 504 681 -32 -800 -792 532 -122 688 16 -570 -202 693 383 -115 318 -542 -939 -516 695 -243 -361 278 -867 -902 189 -67 551 87 -986 -626 -358
-807 -847 -15 -843 -48 472 -564 -726 193 278 -337 -660 721 -319 -511 746 -346 865 -637 293 -111 -604 195 930 259 -698 -408 -908 -83 335 289 548 123 -268 134 -418 30 302 662 -587 -803 313 398 -311 1000 -608 772 -802 -82 210 389 -122 -607 168 -752 -275 -371 379 597 779 411 344 -624 787 111 654 141 -607 268 30 -65 881 30 14 636 618 -122 349 700 386 814 851 -659 186 -383 199 662 -577 -438 -465 204 609 738 -379 -429 578 14 -681 675 -395 -822 942 286 -535 877 89 -795 439 479 942 -329 -617 980 187 -640 384 942 732 892 897 -286 116 918 247 -309 -295 861 -119 380 -259
-985 152 933 -48 -271 -642 -291 -57 -675 598 276 -726 -241 827 482 222 -501 214 -137 702 -967 -15 740 447 286 -495 -981 -636 -452 -598 -498 -288 -814 451 -633 245 483 -189 430 544 783 -168 435 89 -899 538 980 -999 380 477 878 -341 -30 -938 -241 967 235 221 -583 628 902 853 666 870 -571 -296 -938 -207 443 525 -276 -436 399 194 211 311 21 -546 253 466 -274 -9 412 629 722 -250 -709 671 484 -250 -358 334 -895 387 -22 -749 406 918 738 -864 -339 176 733 448 379 -304 -313 460 -212 95 -390 831 -539 2 -532 769 -757 547 720 -208 768 86 -402 893 -280 -599 -507 644 843 -815
-752 457 -793 -763 806 -603 -111 86 813 -288 -570 660 69 906 -540 -984 701 606 476 536 954 -729 -164 -886 594 318 -507 990 -520 -296 -570 -626 -769 -529 143 -477 -211 484 561 -480 83 -849 -73 235 685 -966 51 647 125 -673 -137 88 -832 -17 -786 214 487 -14 -742 840 -124 -345 -425 -395 -891 348 -129 238 85 643 991 51 881 727 135 188 -182 -891 -469 -223 -672 -208 -797 -399 -745 961 -24 -685 180 955 -746 -191 -496 -759 -491 -743 855 -181 -486 -976 791 186 -596 940 -983 767 566 -102 -362 495 -904 -218 431 -876 140 196 -796 657 -8 97 637 811 -878 759 -586 65 -245 859 143 457
738 212 851 131 29 566 379 -490 621 510 -816 570 -686 -732 765 -579 -768 404 -8 80 -322 -978 -139 3 206 -46 -582 897 -248 -756 -640 -926 64 -367 563 -256 -244 -501 -733 620 -78 805 635 -592 968 728 182 -628 -649 655 -85 839 73 -875 -188 566 392 928 -893 -709 -867 603 599 860 -848 -488 -914 -69 866 -757 384 682 62 -839 807 -278 -772 -128 172 -264 -972 -102 -391 -578 623 207 -365 -814 -244 719 -687 -259 -812 585 982 968 663 -961 -37 -835 829 -805 685 831 965 51 -963 799 -850 686 -48 -590 -828 926 -327 163 -198 -932 -24 -344 854 310 395 232 -946 -136 -485 -603 794 724
662 -578 794 298 323 -858 -53 490 -715 547 -222 -862 -303 20 -876 -541 348 699 822 -10 -19 -772 364 800 -31 610 953 -311 434 -233 478 983 546 680 109 937 -859 102 67 564 967 282 153 553 734 456 -68 -353 332 -272 -219 -46 782 -792 572 -473 -760 400 -489 -344 -439 730 412 678 -377 -240 -759 111 -559 -303 -674 481 -814 810 4 -378 921 392 584 -517 -843 966 -145 -467 -160 -765 -934 473 462 -922 924 -771 -94 144 -900 389 -943 -440 146 -644 286 -931 213 517 984 235 -562 -58 887 -51 347 -832 448 -362 148 -735 464 702 951 -663 131 202 36 -788 642 968 639 -886 -894 -633
399 -695 664 349 451 947 -830 -572 9 -177 -907 -953 -417 150 -237 -696 440 207 -490 -41 894 393 -85 -221 -923 584 -922 235 -117 164 986 196 -303 926 427 858 -158 -622 -500 722 -851 -438 -96 726 -328 677 65 -178 884 787 723 583 862 690 541 165 -336 -235 669 -335 625 438 194 -417 -67 -440 -984 -443 -40 -786 621 828 -328 -142 -890 870 -606 -968 139 664 999 -584 740 46 -92 47 -712 -377 568 627 -541 654 943 520 76 516 -432 -994 978 219 722 -56 43 470 589 -222 794 279 -360 240 287 -56 -91 -194 873 -750 982 -462 -578 298 282 450 -227 125 -242 -12 -201 -628 -56 -407
424 -795 -500 957 346 -904 -690 -975 -664 524 170 -56 -396 -845 -541 192 -497 -365 815 -885 -521 270 363 -544 735 448 -104 -649 345 -596 34 65 890 -530 -590 -861 -256 25 -980 232 -820 -359 677 -43 -156 204 513 367 563 -421 318 -923 93 682 -511 963 653 427 459 421 884 10 -39 -260 666 -851 -750 -1 713 -372 811 -907 -471 -999 377 -632 188 853 -416 -769 387 749 -642 528 -625 97 323 443 554 257 265 461 -864 -328 242 -413 -461 977 -590 260 743 -372 -471 532 199 370 -534 -87 -926 473 -100 -282 -188 17 -448 208 -987 800 24 -981 -684 352 -182 -376 704 87 239 -823 -60 -683
-344 0 68 -825 -371 -858 -225 564 -697 -381 -239 -411 -968 -861 581 -423 -309 -733 -375 -832 -513 -948 -925 962 -421 755 667 -84 298 538 334 -408 989 524 409 669 -490 -826 983 -402 -23 -34 724 26 740 -133 -7 -304 -906 -664 229 -847 -424 508 -444 -505 -116 -698 297 257 -543 202 -910 -556 508 948 -228 -299 804 -884 -646 826 150 -962 -76 -515 328 -442 -582 784 -480 -537 -795 440 -145 107 -615 831 813 953 -860 -360 476 173 -444 95 41 425 832 854 371 962 -597 801 -894 628 -61 -432 -521 -465 -887 306 485 698 628 639 611 -687 718 -437 16 -690 910 -834 89 -135 -633 -558 -223 797
670 -433 -736 -241 409 46 335 -788 812 234 -74 -681 767 -820 -609 -982 241 -53 408 210 -168 -362 -486 863 -123 368 -427 -998 104 -35 -954 578 901 981 -974 -734 444 214 -678 731 -263 -407 -297 -481 839 370 86 -469 -824 300 899 -651 891 -659 -362 714 967 -48 -109 628 46 -244 376 794 333 -667 961 852 869 40 640 -937 361 777 -84 534 251 -497 -810 -244 263 -985 232 188 -704 -518 662 -798 -679 -220 -595 -692 53 -116 90 987 -699 991 -67 811 -870 -964 -476 -143 -514 -96 815 -153 78 -395 253 129 481 -943 633 686 506 -710 -211 -859 184 -992 992 -949 850 324 917 859 372 -297
747 -443 40 107 613 -481 758 187 141 396 229 -927 -788 -772 -619 225 240 -553 98 45 -460 -42 627 -239 810 8 564 28 -163 -376 -29 493 297 -503 -592 798 -59 -349 317 -519 243 -303 -439 256 -876 -687 694 -154 667 -465 -925 820 -667 -566 919 -837 -738 -250 813 99 -475 387 -352 -602 -174 -473 -886 -552 43 -789 -721 -309 87 -521 -121 647 534 712 -614 174 264 -643 897 -327 -608 -165 542 809 -428 319 102 -371 171 563 487 626 623 347 -636 -733 729 -803 -407 498 630 -418 -267 -107 -592 -374 717 469 389 -611 475 500 -275 -199 -441 -498 -867 -9 -514 461 759 -995 -970 -428 511 218
-15 139 23 -529 -490 -843 -168 626 734 98 -665 525 831 -765 260 355 -571 -378 724 712 -940 -662 231 518 -827 -577 -760 -895 420 963 221 860 -306 650 943 717 349 110 16 -993 -267 -103 21 876 -814 761 -575 634 878 -459 -675 95 -744 -140 -347 -563 -740 -472 635 118 -365 919 -15 979 452 -75 -45 374 -338 517 -922 841 222 -641 -602 -270 108 189 -951 418 -830 868 800 478 -117 432 -617 447 558 901 -469 967 -27 -666 -175 -159 -667 -175 -313 -539 73 -147 -927 573 -869 -327 -342 29 -513 -616 263 -548 26 -997 883 873 222 685 -679 467 90 372 284 -258 861 861 364 -298 -241 521
-280 -481 779 723 307 -653 -653 -420 -168 -983 -669 409 493 762 -579 -126 -952 907 211 -466 948 -711 -147 726 833 -527 148 -415 962 -55 778 -572 -201 907 -680 34 -861 70 -883 973 91 903 670 -619 311 -642 978 -445 404 474 -204 -338 -267 112 -574 -495 -430 -407 730 465 341 -36 -135 -917 -361 -523 654 -314 65 105 -114 -571 720 -509 716 -808 -467 -814 -603 613 -924 -308 912 -216 98 -823 250 143 -269 798 105 -976 -962 198 -369 -856 995 -601 -318 717 -725 579 -157 -897 759 -376 135 871 -630 -638 -392 908 -599 -817 370 -716 -800 904 936 375 997 664 -93 718 -591 667 -474 552 -25 232
61 438 -475 -351 -815 753 -689 -356 -272 -646 625 767 -824 977 -479 82 -821 514 -490 788 357 -602 103 -850 665 -933 -952 861 163 -665 80 411 440 -368 -896 -488 586 903 207 253 685 -374 -763 878 154 891 -366 -188 671 -333 -393 707 -509 360 641 -993 428 829 -274 742 -369 -222 131 -272 306 252 -526 -317 -162 338 821 -748 -566 114 54 213 283 -230 -437 483 208 -959 -795 503 -704 413 -376 140 604 -234 32 -578 414 48 436 -734 856 -721 671 -874 -686 -162 204 947 -165 658 484 681 -49 -943 -752 -894 493 551 688 908 377 -236 31 629 717 844 574 263 657 -484 -585 154 535 539
565 -525 -359 -405 -76 156 632 657 924 -284 690 599 453 -643 606 218 -876 357 380 984 -765 525 775 283 -423 845 -984 842 -989 -927 483 -528 701 918 394 -233 674 -953 651 -767 -980 433 -877 868 141 -28 550 -929 257 15 244 -606 -482 124 674 311 718 519 610 877 507 123 -745 674 943 52 359 -676 373 227 573 -539 224 -41 -532 -374 309 111 233 131 -500 361 210 866 976 267 -717 830 305 489 -354 -119 -534 -185 -514 798 321 657 935 -679 -799 -473 845 -892 -878 861 -452 -813 -505 -209 295 699 -995 49 662 -863 130 -679 246 444 56 779 975 -182 762 -129 52 -17 771 -68
-196 -671 744 798 208 827 -582 -28 -53 -839 704 697 628 44 -364 -826 -819 139 431 983 433 -474 363 -753 234 771 394 -933 369 289 199 -841 693 -627 384 -295 651 656 -868 97 -435 458 876 -703 -761 -807 -620 -146 -846 -606 136 463 -541 758 427 482 -149 696 74 -344 343 374 -595 -956 -178 -136 436 -851 392 -116 108 -889 -510 979 851 147 -117 412 -800 -721 860 313 927 -299 -459 831 439 298 347 848 -658 905 -167 793 594 632 -927 264 -612 -347 -267 -246 -36 927 789 -369 -120 965 -796 717 -136 -804 753 413 178 -858 -985 423 -294 -507 95 -457 -687 925 572 102 -172 153 78 969
-750 -398 -191 -879 565 -811 32 -97 -514 44 703 200 71 389 520 184 -274 -527 677 -959 -66 -616 905 -407 -929 -595 -174 -454 816 -577 -986 -134 -14 837 973 523 -827 -106 -385 770 -553 105 922 452 993 -422 -504 908 620 -317 -266 646 -426 -479 291 763 -472 496 -896 834 -745 -657 129 -833 -648 -178 -24 -50 -834 -552 750 -679 306 682 -767 -721 -853 -973 -366 792 828 -856 447 -58 -873 842 229 717 -91 -94 -687 -945 -794 976 -568 -519 -33 128 753 -419 -81 -717 663 885 213 -631 231 -351 -771 -525 676 -327 785 -806 -635 -694 921 -183 978 173 -10 555 151 -562 -503 811 354 699 989 -659
647 -600 761 621 -950 107 -395 70 984 -200 -973 96 808 -739 859 -596 405 -56 -924 -742 923 540 290 -829 442 709 -349 -272 -347 686 230 -314 852 -499 -370 889 355 199 -477 -768 818 904 -973 -545 613 136 -119 45 765 410 -424 -75 -406 49 255 -228 351 50 -6 -115 -341 -456 -637 -57 -112 -832 29 653 806 -249 679 -360 464 417 -747 -556 -378 -977 -241 -847 914 -670 -229 738 181 -520 960 301 -385 -824 181 685 798 -274 31 302 333 -409 -474 -350 640 -867 304 347 185 -735 -787 657 435 -704 -300 359 -928 -576 579 -476 899 147 556 -30 284 591 94 972 -279 -500 514 28 -659 -185
330 -783 -90 983 547 217 -292 614 401 513 837 44 -780 -767 -257 -285 -936 -699 905 753 -372 676 403 -959 -141 -995 788 435 917 -168 -156 -988 378 569 448 -13 -677 -755 473 -931 -837 656 330 959 -989 -152 -642 979 262 -894 -385 866 700 586 351 982 -523 -151 -135 -811 88 -490 838 -351 870 -580 -179 -120 -382 -110 -839 -338 324 -224 894 906 -912 -657 997 530 -6 558 -904 -408 -564 455 66 -634 673 852 237 -77 76 -151 -579 499 269 -248 39 -526 339 720 116 -868 -916 -547 235 -474 -849 -519 193 -750 -470 -156 423 -74 662 647 -63 -406 209 488 809 -877 -777 -900 -34 -194 99 -957
749 -119 -909 182 328 192 213 -831 805 464 -849 339 -863 350 113 833 75 542 792 -394 981 -867 973 30 212 340 863 177 756 786 370 -337 953 -860 -530 77 -764 502 29 -173 -357 909 -928 787 316 -173 -707 760 147 -577 -120 278 469 -876 880 -550 -189 223 -93 -741 -400 102 958 285 732 -982 621 -776 54 13 423 -337 737 -918 -869 -820 415 -328 -346 -981 -472 635 -179 -624 454 -241 475 -328 966 -201 -874 500 -426 -844 203 -425 -962 919 280 -660 113 -630 -188 837 739 126 -619 -58 753 986 319 16 648 -765 -104 -670 447 969 789 380 699 686 -576 -699 375 309 -494 -749 -932 79
874 -120 -301 -426 100 292 -451 606 333 826 293 641 145 9 -761 -223 482 -819 -425 -512 -369 -551 -461 432 -369 -737 976 -548 882 -322 33 513 827 -142 703 -584 554 388 -456 767 -242 93 -138 -482 -927 -445 262 558 195 -906 -447 13 50 204 -206 710 194 610 -485 720 -290 -80 -225 -381 -917 900 -180 -911 645 536 -422 -532 240 -955 -140 -672 -730 -88 345 672 138 723 38 128 -112 458 549 -94 474 118 411 -318 -364 -190 -671 -527 -963 17 956 -596 776 -122 -299 -120 -887 -538 -520 -771 -654 -373 -701 849 526 -817 -943 38 -867 -91 -44 -161 802 5 -961 359 -929 -77 -819 166 -374 251
174 108 -126 -276 501 -191 -489 -758 248 -250 908 826 -676 -985 496 677 -68 451 -692 -575 911 76 -906 295 -983 -336 996 864 -248 221 -428 -293 -917 702 -781 -167 -116 523 -572 530 -440 197 -613 997 439 -932 967 -909 -230 -766 -262 -408 389 -429 -391 -233 -352 -856 461 -619 -391 -526 -962 -1 928 -106 -946 543 287 -571 179 -884 -841 574 735 295 778 -911 945 -523 -574 971 -759 -387 249 -344 193 367 47 968 574 -855 858 123 256 -152 -9 -87 -98 35 373 -988 23 -23 -878 -481 56 430 241 -366 300 131 -491 -596 62 -859 847 -408 452 515 -347 -569 370 755 -536 -384 289 593 -867 -153
157 -753 -754 -827 141 532 -939 590 238 776 381 823 -999 516 367 322 643 164 -316 306 -858 95 -400 387 -360 -534 384 408 287 -484 -277 89 -861 456 -132 -827 -871 -57 -231 -944 -819 624 -494 -939 -702 820 -719 -958 630 710 365 831 22 -207 -289 -88 876 620 448 -216 695 -750 -566 -438 -664 -795 883 629 -277 -454 -214 369 606 324 -349 216 -174 764 161 -781 -995 928 365 920 314 -755 -431 92 305 -49 486 728 -526 -818 264 -951 -171 945 -691 866 -861 719 -636 300 -773 69 962 -995 175 400 -135 -219 -240 -796 -338 -717 689 -463 -983 3 385 863 168 -924 -19 -960 -403 -925 824 207
569 -706 489 393 -58 906 62 -574 995 134 -749 -104 834 -398 -622 62 -855 -699 -395 -179 79 -886 -71 109 -214 392 277 798 814 -651 -106 80 739 941 134 876 574 334 -11 134 -589 488 615 180 388 -705 -609 417 -647 -554 -214 902 -301 -211 773 62 -584 -688 818 712 -385 -376 298 -892 554 536 -387 684 -99 -785 -550 -9 -569 253 -174 551 802 -597 19 482 867 883 -284 -544 -170 -536 810 -340 672 394 327 167 54 -4 -783 193 937 834 -197 -139 252 -323 187 256 465 -180 -559 266 -191 157 117 -639 648 -243 664 250 -948 -744 -975 -74 388 -61 677 880 893 363 -518 108 579 -839
557 -873 -744 -697 637 -766 65 -186 -243 -913 857 261 600 400 -583 -975 435 592 -594 838 -910 -220 994 859 -563 -617 581 -734 -454 82 -894 366 523 631 -658 -98 -645 594 940 -5 -986 133 -262 901 517 -634 646 62 -911 799 -747 -889 -684 226 681 411 -776 859 403 603 -240 -724 -127 -694 -909 414 -396 543 398 -615 159 577 598 -366 707 -343 -152 -525 706 -350 -745 -370 -917 489 877 -530 242 216 -81 875 378 -664 295 -325 -637 -428 -727 538 -945 177 767 169 -669 872 -862 575 886 -812 -503 920 -991 748 947 -381 99 -176 -492 303 604 772 -357 798 825 401 -35 -217 767 447 -912 -720
-746 -881 473 -728 -962 -919 387 594 132 -643 772 479 -561 387 -916 376 725 102 363 -472 882 -794 455 483 -586 -817 144 -852 321 -649 594 596 474 198 359 326 -168 264 502 -951 591 -2 -456 -874 -579 138 611 648 -629 642 498 214 310 -384 -383 619 785 238 -333 -293 125 371 73 -614 467 684 758 -107 -509 -739 452 -373 850 660 -99 124 507 370 -594 -357 -839 -626 729 -401 -610 509 71 -457 218 -970 -665 -805 239 747 821 -610 693 165 -333 594 -400 -473 476 -949 -315 -855 -420 -752 705 394 -722 -135 -527 557 877 344 409 635 -984 68 192 52 -83 -331 206 868 512 404 -966 198
35 686 764 388 178 26 662 -980 241 -468 111 -740 -924 -123 985 -226 9 415 460 -744 930 828 110 -864 499 -918 257 -672 -203 -917 -973 228 -718 636 -167 -147 273 337 982 571 -628 -73 -306 640 552 662 530 -439 866 898 939 166 127 -218 -441 740 713 -905 -325 -233 826 -104 -420 5 790 -592 -108 -507 -8 117 113 -889 -179 -691 51 592 -52 -978 999 818 48 478 -993 458 -380 -454 881 -187 -795 407 -588 -48 -218 328 754 -476 -963 -503 -828 19 -939 20 575 827 -254 -161 598 -1 -301 436 721 -12 316 316 51 -875 -236 -460 613 104 -882 -475 -600 -768 48 566 -842 894 -751 -833
870 -447 -151 528 -140 694 -596 -109 209 -509 203 620 -531 852 -239 -341 782 -284 -12 647 -728 -554 -141 -864 495 -194 554 580 -820 -990 243 -65 754 -91 110 -654 738 -599 -90 -663 -995 -672 135 768 -815 968 718 -251 -411 -39 -720 -349 268 -773 967 -764 -3 683 -216 736 47 608 -824 945 182 -861 372 116 436 234 -215 -191 258 986 38 -314 -559 416 497 -650 -473 -207 -762 592 232 546 361 -750 128 491 -360 105 786 -268 434 -8 346 334 144 -647 664 414 -840 610 370 -706 923 299 334 335 -482 814 -911 891 369 -616 37 -176 -966 -365 -881 -271 929 -434 -356 -636 394 104 -279 481
-986 -24 378 -514 940 566 248 139 273 976 -192 790 -733 -966 -259 476 58 -299 -244 -353 -246 546 648 -635 564 -732 516 -52 -61 291 316 -742 602 389 903 -728 504 -921 410 149 302 -592 -960 -413 100 701 -696 -520 913 780 258 45 669 373 858 268 55 -721 -267 -1000 -651 9 -334 595 -942 -134 283 -206 -800 441 498 -599 261 461 104 -376 -861 -672 999 -952 216 -303 405 -391 406 622 179 -414 264 321 841 -445 671 223 678 362 -148 -309 -822 858 -671 -248 -615 54 -605 101 228 -134 379 -363 914 -872 -816 257 684 93 -679 44 -925 -732 826 -739 -637 -380 440 545 328 774 -636 859
721 -310 -34 -52 225 -271 184 91 562 439 -567 901 -834 547 35 -266 998 272 -347 887 -35 139 -54 839 883 -126 521 -365 -820 372 -233 -256 905 568 166 -83 -397 40 -733 -100 451 -859 549 -437 875 980 -577 882 364 635 -94 372 -442 -640 -218 152 372 885 652 -999 460 683 -226 -852 63 717 304 -458 362 88 -431 218 591 -660 -947 -558 -904 182 734 -788 868 -171 881 178 -996 -77 564 -852 -20 663 -276 14 -482 14 -425 725 439 -680 723 886 -42 14 -913 520 -924 103 -819 720 -362 254 -699 336 -618 541 23 500 558 -730 921 -92 957 -236 -466 -8 417 -810 -96 161 -212 522
317 -292 -399 483 909 -362 228 -644 599 170 746 -144 993 320 -321 851 -860 704 -894 318 -277 -846 261 450 283 -163 575 479 384 -393 922 -847 -602 181 -137 -712 168 -659 807 -924 961 184 -609 -816 329 479 -654 -301 -525 -591 69 -572 633 -25 -358 -244 -130 -714 107 875 -726 880 -752 -757 645 -201 569 853 -690 201 -182 531 711 -544 373 875 469 136 -451 696 638 497 251 -741 -360 484 -877 832 898 201 136 -478 -394 -831 -110 -232 -225 -946 -100 143 707 -543 -969 -552 -568 87 481 -802 -8 -286 -630 416 -312 -211 840 -563 -740 -551 127 -5 621 -385 -622 -899 -495 326 168 -690 274 745
-702 324 -296 -715 -604 -99 -413 -27 -692 143 437 200 26 728 245 -393 -108 -180 897 955 927 -455 774 171 421 759 504 -305 486 399 -176 -783 196 875 -47 145 -944 841 -802 -558 304 45 179 744 -430 8 578 693 -585 640 13 -708 -278 -824 147 -807 520 -886 -268 194 -710 418 953 935 785 -760 936 52 -38 -884 -707 -953 -235 53 -873 -926 -254 -55 -244 -709 358 511 -137 -829 -28 -419 819 -262 125 708 -614 540 779 383 -201 -33 653 840 924 -483 752 722 -562 247 836 701 666 -920 451 209 365 -199 972 955 -110 81 438 750 329 -328 -581 -187 -640 -611 -685 90 974 136 -985 -914
-469 -828 -566 -306 122 164 447 -773 -973 191 697 462 360 -962 753 76 -313 -11 -136 -176 -229 755 -496 951 -108 -457 893 307 923 294 -309 960 359 -904 642 -738 -196 734 -158 812 426 28 -131 234 486 365 833 -840 -960 -758 -76 599 151 401 -533 582 -937 135 202 -576 -379 -852 -397 -979 910 747 176 54 939 11 -161 423 -42 -904 978 676 -176 253 -106 -245 920 347 -522 -397 545 590 52 -877 463 106 860 964 -163 -140 604 923 -360 863 775 -66 -253 -513 488 420 900 974 -3 -263 412 271 104 -955 -898 -685 -58 -925 175 -894 -94 -770 -678 111 -845 599 296 -772 -767 -813 392 -275
-399 -704 957 -482 -226 899 -132 521 964 -131 -326 -339 -885 -801 -597 746 977 -259 271 -340 770 591 -200 441 -451 -316 -171 -616 -95 -149 431 342 313 -127 -240 -195 722 -705 415 543 -51 -444 -472 -724 -906 693 228 980 -202 919 -492 808 -858 -695 956 -293 496 -974 -170 -600 -940 250 -408 -978 699 -84 -145 -876 -619 135 -457 493 544 -483 -621 -795 134 -243 -637 999 -420 82 69 851 -440 -500 -330 -301 -561 -519 927 997 245 315 -319 -447 579 -507 -664 637 772 -234 960 982 -316 773 -939 931 767 599 -877 418 268 561 97 -346 580 820 646 -207 -474 38 -551 311 -688 -888 -425 418 126 -737
-282 -460 -903 253 599 56 -564 896 566 151 -817 447 -226 -942 -82 -300 -400 944 712 -173 428 -497 520 813 -148 -879 267 -643 -57 -307 -886 -736 805 -703 -264 394 -303 -183 701 -952 305 986 676 630 934 442 -931 -620 606 533 -46 -935 -627 -739 -146 -916 -955 -943 953 -223 -329 -309 715 135 643 968 389 530 184 824 -708 237 296 639 366 701 -899 -746 -877 -106 -159 -753 -338 -295 547 -257 -593 328 -180 -543 -133 -253 -721 -134 790 -612 -561 -286 -911 284 725 -40 423 -506 742 559 838 -520 880 -887 -598 462 129 -29 -286 453 251 -398 -956 -812 -15 463 679 594 -260 329 863 -44 -123 -696
-58 -136 -332 481 129 -491 903 -125 -432 950 -492 -146 -190 -230 -80 -373 -908 -367 -673 761 752 -313 -346 83 -500 162 -410 64 175 490 113 -298 871 -366 -847 -211 624 76 -564 -335 111 -226 201 -531 -834 -623 179 -179 -338 -741 542 -811 43 244 597 -431 -579 -370 -879 -493 90 156 100 550 743 -941 531 -274 -522 69 -92 -662 -288 -234 -961 663 -463 359 693 -821 615 671 780 -774 878 590 881 -973 620 -450 -586 208 -475 -923 286 -819 470 -442 904 936 -854 823 920 -218 130 477 426 -601 500 196 -228 774 -331 600 -935 681 1000 916 -418 -99 -482 210 -960 -176 -883 -332 -75 704 -483 -375
936 -849 -336 -175 -74 516 -387 -562 287 655 -554 682 -168 662 -134 423 -554 -610 61 -657 -601 -174 -433 -415 -800 -563 894 532 767 -437 -637 157 -953 639 154 971 -8 -692 -910 -162 742 583 -642 690 452 808 -969 910 -956 -998 913 -479 -619 -58 612 -839 -335 -80 690 171 510 -170 178 -599 262 220 409 996 340 198 568 -802 261 255 516 -816 304 -452 -746 894 -620 132 -476 -913 -13 536 -923 -646 106 -978 -527 346 -143 74 -351 285 -601 -772 -308 402 -607 -762 -588 -399 -158 731 -417 -723 514 429 136 -681 69 -195 -179 -711 -93 62 -551 178 428 -463 -299 721 943 -836 299 -715 -299 330
-983 -56 460 900 533 274 835 544 -663 101 830 -549 1 -836 -898 100 935 -27 -921 -612 23 -461 984 -108 -879 158 -320 704 964 -10 566 -674 104 -854 -305 -105 -272 -847 512 -207 -569 -70 622 -368 -460 584 -913 717 72 -50 -801 858 542 333 651 -336 556 -654 -528 822 428 501 986 280 846 485 193 396 41 -920 -912 -104 746 -810 977 893 -629 -500 -908 -517 119 836 -441 733 263 412 93 -782 323 -239 150 92 563 166 -723 -255 -855 597 319 118 -320 596 -543 -174 -415 -847 552 609 693 -232 830 -769 777 43 -382 650 -333 847 486 526 862 274 162 -784 -132 742 788 -450 -174 -804
853 -478 -923 -264 -9 -888 706 -342 40 -753 -957 -235 502 -817 313 -677 -431 -860 -879 148 276 469 627 954 -614 431 -234 -742 230 -235 711 724 296 -234 173 -422 -588 602 -603 -25 501 -335 -719 537 -986 -633 -601 -662 -545 471 -670 893 -942 897 355 87 707 358 742 691 -95 -547 -383 126 -600 4 584 447 -1000 -108 684 691 982 -217 -70 -867 986 675 106 -358 988 648 -137 -659 -269 -148 -817 223 319 263 538 42 -933 506 -386 -4 193 823 774 -698 -52 454 -806 295 -309 617 136 -783 -187 -35 -747 759 -215 801 814 -980 -296 -153 -248 -459 918 917 -760 -775 136 426 -813 -711 909 -171
-560 -436 -142 -538 225 -415 406 104 -969 -737 944 -754 -201 201 -827 -318 890 -713 784 -505 -865 -627 -706 183 754 547 764 623 -602 262 -604 517 247 -196 -218 -246 -975 -214 611 -215 799 638 951 -561 -213 -299 791 -949 -399 657 617 407 214 -813 -507 -806 -933 903 -923 811 -287 -302 38 -469 -835 598 -78 888 918 823 353 -956 -143 -477 880 410 636 -159 -777 556 -82 252 956 517 -788 432 -644 248 -799 -716 -790 -247 894 -634 -287 -993 -490 32 709 -504 -185 -595 528 -471 24 977 430 -422 726 -268 876 -906 62 -265 -627 53 700 -688 -877 993 -658 620 -442 657 -502 518 334 -168 682 -313
-227 210 196 845 -671 467 -365 451 154 365 463 478 -775 -130 294 945 245 -520 -365 620 394 -476 874 354 58 123 39 45 -299 706 -480 -970 -214 -299 -172 29 20 695 294 -25 -983 -79 583 6 926 272 -878 995 -593 -463 449 -488 861 -330 30 -888 822 -215 -606 -81 -402 539 528 -430 969 -393 268 568 -24 670 330 624 189 -126 -626 -786 13 -382 -912 -458 923 510 -234 510 -550 -387 -278 568 161 216 144 142 -287 -157 -624 -473 -408 744 -876 516 515 18 269 -782 -938 344 -435 -498 -324 -817 547 -765 889 516 -939 124 249 630 355 123 427 -378 9 784 -873 -566 491 723 164 -844
-671 258 -732 465 939 -750 -313 354 -651 510 -693 124 -248 152 812 806 586 -495 328 497 277 746 831 161 -914 951 838 88 -149 438 -652 -411 -445 -681 -258 -220 833 -917 -226 -482 -219 -539 -126 -687 -298 -159 42 202 -927 121 -942 -701 558 -673 853 449 784 -593 -786 -987 901 -369 -88 -454 -217 -584 935 -954 -111 -662 -247 913 -733 -655 -546 -551 -740 988 551 -578 758 876 916 681 -478 437 -743 -21 932 -447 824 -568 305 805 -344 -72 856 -958 937 -317 184 -741 181 -372 442 -90 616 -21 -120 -693 855 -930 -382 728 487 945 427 35 767 -940 -740 196 387 535 845 -582 599 33 360 791
-799 -477 340 958 127 -203 537 -371 -245 998 197 151 -745 264 -501 276 947 342 -601 -779 -5 -97 -230 335 622 352 -746 597 -68 -488 363 -952 371 -284 -879 356 884 942 -747 563 232 298 521 -693 -339 -541 761 215 824 -742 272 128 -300 -534 -457 -804 510 286 849 455 -717 -590 -637 516 660 76 -101 -885 903 -435 508 -93 820 -675 -749 491 -13 745 907 284 -653 -792 -5 272 149 906 -97 -156 163 539 445 -598 632 -560 -955 -113 -380 867 -434 -208 116 738 617 -615 -854 -104 -901 277 821 844 330 -134 -967 859 814 303 -998 -276 -612 266 778 -822 807 99 -798 394 -374 -965 422 -766
660 301 -998 -847 949 815 444 -852 -700 489 -799 -242 73 -375 782 761 -760 -300 -535 -820 344 -409 -524 387 -107 -782 210 906 802 431 783 -805 643 257 141 -519 -473 -508 -266 -833 -840 18 668 -14 426 -600 561 365 -398 -522 -884 699 322 -394 259 -783 -502 223 -373 93 -624 686 176 -268 -900 -384 324 -41 -709 606 -610 152 -73 -319 -134 582 453 -414 965 -336 -560 -783 159 101 805 -26 -680 -298 -551 -848 -407 -584 -424 -154 747 -35 325 -658 360 391 67 126 -883 267 425 630 19 312 683 430 605 -209 -308 -377 -18 177 623 -815 -167 358 449 689 84 116 435 201 -698 -54 -381 617
33 -45 -51 997 -183 599 -578 196 -847 -183 -319 -9 311 -38 908 -180 335 -271 547 665 -727 -269 243 -8 608 381 605 849 647 710 -291 877 -355 -93 -131 475 -563 -4 -224 58 -542 694 -321 -523 244 945 -703 -349 -200 74 456 -954 395 925 912 96 254 248 246 -227 -471 239 -639 445 948 -846 -824 -755 -332 197 -457 -875 311 -949 209 -219 172 -843 299 -425 210 307 349 -245 840 -884 399 -895 289 862 -728 -358 333 215 782 383 133 -756 151 836 321 -549 707 -826 -290 84 815 -683 -192 508 743 -100 -841 -678 293 -426 232 -51 474 -388 118 -743 307 -585 365 842 -433 907 -1 -323
-469 -376 -707 -805 852 510 397 655 107 -385 839 -897 -483 -696 31 66 -152 -141 786 -523 -569 -734 -454 409 743 552 -340 110 -261 -314 -924 690 450 -299 741 -595 -753 402 198 892 -807 715 230 -688 180 222 37 677 128 -503 257 -2 -834 922 -24 -262 -76 965 -201 -851 -879 -486 723 -799 -6 459 -956 469 964 793 -258 -639 -285 -739 -527 719 -646 134 724 70 336 356 790 -931 709 696 598 871 694 772 -104 -142 973 398 -878 407 653 645 927 537 -929 -767 656 -843 148 482 -986 85 164 -216 -649 370 9 605 3 -996 400 -930 416 -210 550 -602 857 -469 -210 801 -395 -925 529 -518
-509 -76 -785 909 698 -488 588 -452 -37 114 -666 -145 863 -412 -695 729 -116 213 -899 -271 373 764 -251 -61 882 266 281 -908 -561 -215 -219 47 -22 -100 182 -189 149 -179 -545 -777 -100 295 884 -588 449 -62 172 -584 -514 -58 -415 396 -723 -867 -77 973 726 -268 803 925 -571 936 768 1 -361 625 700 -886 730 -128 -89 -799 855 -878 -643 -567 -923 76 718 -74 120 -545 23 -809 -276 -615 -392 199 974 -766 -209 377 33 -720 -962 450 -257 -255 752 359 -440 -271 -271 156 315 430 -308 230 819 998 -464 241 367 413 68 850 514 881 -143 -291 -992 -212 -750 969 389 468 536 -592 -173 -486
-284 -389 -174 755 -651 -704 60 -364 643 865 309 -305 -397 687 340 926 715 -460 -231 -472 654 -937 765 298 438 -132 -996 -2 438 32 -422 491 857 84 631 -551 167 -13 147 735 -805 -938 -536 520 -698 -407 756 -576 -760 951 -729 314 -996 944 -118 786 -797 -494 -759 717 -352 52 720 438 -504 -301 777 -720 740 -642 605 548 -156 831 898 352 692 -834 -422 -980 -134 338 -31 963 -655 714 225 -885 788 -553 589 -9 -40 286 749 -166 -419 -218 515 -511 8 393 -255 262 -272 824 90 -225 843 -238 109 779 498 558 -970 -205 -867 -724 732 954 903 -952 -965 -314 -657 -31 -166 -137 797 572
996 595 243 639 -755 156 -635 -95 376 961 -805 288 848 -900 464 -718 585 -524 674 979 -140 85 617 -320 -142 -972 841 -948 505 177 793 147 -222 659 -984 -66 -14 270 -508 -640 -108 -827 864 112 -165 351 662 -822 278 -551 -781 30 854 871 -137 -558 -394 865 -150 -606 105 313 -556 -885 948 78 486 -151 961 510 133 -685 832 -151 -717 -594 302 504 -246 482 -574 813 930 252 -987 709 145 -338 425 743 -194 228 -206 330 -724 -551 772 685 -526 8 810 119 -743 -321 -346 -801 950 855 -799 722 483 475 375 767 250 -699 245 191 -448 -226 783 -984 -354 48 105 382 -307 418 -797 453
990 -516 903 -847 -383 872 722 453 312 979 -147 449 -597 -833 416 197 -232 810 -588 -407 559 -79 738 313 973 736 -159 117 -628 -485 351 897 -599 754 438 575 387 -247 865 -736 770 -270 594 -5 -432 -915 -540 876 -979 606 -437 708 -895 761 703 86 -884 181 -50 313 -1 -531 269 91 105 91 -321 15 674 -575 580 152 253 855 -308 250 -862 -980 303 -210 400 -747 307 -798 -934 -390 -37 -275 -471 -494 -24 747 -73 -658 802 100 -280 272 875 -942 -525 -752 -872 579 -27 -408 452 -77 415 -875 428 684 -133 115 -580 929 692 478 -275 -686 90 -564 -638 29 -895 -901 962 641 504 942
-679 953 226 859 432 756 -101 -816 -629 -16 -880 -658 -425 335 655 646 -2 -477 388 -671 -670 -923 -512 328 -772 721 -13 453 810 214 984 218 -25 842 -476 973 -303 897 209 -331 -192 -487 233 -435 -971 -270 -333 822 279 -218 735 -663 92 571 -873 317 696 750 -943 166 289 -996 -857 -89 394 411 927 968 874 -441 -773 -317 745 -1 -956 857 -21 -747 -280 -814 531 -962 -295 490 -78 -435 -385 953 529 719 -345 -191 87 -843 412 184 339 -641 -515 942 293 645 -916 -688 426 -912 -676 926 264 91 -588 636 891 -122 -303 -763 786 512 -453 -790 253 -641 863 898 510 59 984 129 510 -754
-183 627 -31 890 -601 -114 -989 323 931 758 510 431 334 -682 105 661 -34 270 -371 417 952 -332 -970 960 39 776 8 -543 -446 -650 539 710 -288 463 -499 -246 -768 312 -995 543 873 444 -87 812 -201 856 776 286 -625 -584 -951 -674 911 -375 -637 -255 -151 300 590 -998 -382 -186 -192 -105 992 -864 765 526 680 -167 951 -959 -243 193 324 543 179 -63 720 512 -941 354 92 323 704 -22 392 170 99 91 -189 141 -202 -407 -421 509 152 -392 917 -886 754 39 177 -296 -718 -322 -9 136 649 -481 281 302 430 -201 896 515 -889 -215 -20 -368 -441 -341 38 -235 310 -456 -33 670 864 505
-581 200 447 736 -210 230 -238 -129 -663 -604 748 448 -314 -583 -590 -572 -420 474 -43 -882 -9 -338 989 996 -554 -352 635 -318 -868 12 -432 516 -712 515 285 -93 733 256 -761 -135 -395 824 586 52 -284 152 -997 133 -433 367 192 -715 -203 -318 -648 -318 827 148 19 882 -791 -357 226 -725 444 -370 -792 539 -776 -799 716 516 297 950 44 857 16 615 845 793 -962 -501 219 149 105 -368 -502 93 686 419 -937 883 795 -707 -187 -213 -102 304 35 500 -55 814 509 -113 515 -484 660 790 714 -182 -360 -922 -176 976 669 -561 921 995 -140 -297 -657 -525 -444 -310 950 743 225 650 -384 -929
693 -922 -576 -144 52 -823 470 518 884 279 988 426 432 81 625 331 157 -13 -720 259 105 -700 901 -231 291 393 -360 543 -525 -585 113 -937 337 -126 803 -879 -104 857 -487 -900 -328 693 816 399 -85 -359 -967 -7 538 -203 -877 -932 -214 183 555 -684 -526 -613 796 -363 26 -678 -135 -72 255 -244 -641 536 555 455 -969 803 603 640 -75 -338 369 326 573 -787 -284 560 -616 907 -536 -652 52 -985 -663 -989 -188 689 361 -529 -196 504 494 333 416 -337 790 251 225 639 229 535 -924 -715 245 -771 25 289 -995 281 906 628 -742 -147 -207 713 -94 470 -237 503 -694 588 354 -926 604 448
-627 -906 -341 124 -367 254 -862 74 -910 823 -371 420 -348 -709 -146 566 -828 -237 930 -126 -916 437 -688 -550 -311 -217 376 315 -516 -55 -955 831 -548 -514 314 523 784 -27 8 431 -181 -446 -318 59 -701 -204 514 -86 778 58 838 -575 704 937 -658 525 559 929 319 -27 101 953 566 454 -932 527 651 -778 -61 269 -269 191 -583 85 277 529 -383 276 -287 -634 -503 690 788 598 652 979 68 569 766 -93 -232 -813 273 -772 -262 -82 856 210 -784 162 -763 -377 -19 739 696 652 -485 40 -677 -70 -53 -391 238 86 428 -160 -937 -654 -181 703 -680 -893 -180 552 646 828 941 -230 231 211
-64 791 -869 473 -143 -336 808 -25 34 -369 240 -960 903 615 275 -225 -707 566 -693 325 -397 600 57 876 -52 808 -938 -571 235 0 -429 -840 -27 -622 -376 121 871 765 553 -13 159 -591 529 8 -878 199 260 -572 264 85 -266 -79 599 -867 -864 293 2 -554 436 -330 -867 -956 281 -616 54 -141 316 278 769 969 -31 -889 -806 121 -632 297 -158 -509 137 106 314 -272 371 728 -87 245 -491 873 -679 -543 237 503 -917 366 -545 678 -755 859 687 453 -346 -863 -971 521 -103 11 175 414 130 -50 871 -17 -258 -260 -429 -347 345 133 727 -716 432 938 61 649 -893 404 -333 389 -132 277
-528 266 -294 -567 416 44 -978 653 -66 598 -890 586 -906 954 449 64 -463 509 899 793 -74 815 514 821 -180 363 -930 166 164 -731 372 -881 -31 -414 786 465 -218 -372 854 -725 258 93 -468 197 827 -623 -67 -983 853 912 -807 -360 -699 -502 553 592 283 -129 -611 -59 713 -408 -922 673 -265 -616 389 -238 -90 -588 530 -835 -979 134 -125 -738 888 157 889 -336 216 -916 315 -547 51 65 472 509 919 356 307 343 -243 -564 -759 -207 71 -641 41 117 33 -755 250 -383 -620 -938 -820 -499 -32 -934 -142 -825 218 -252 491 -58 551 -592 433 -609 983 -596 147 -172 15 -552 -386 -794 283 503
-236 -125 778 675 189 553 17 -732 237 -262 -677 -71 -569 161 -144 -229 90 806 -565 -882 -571 -210 -486 -898 -239 606 426 -811 880 887 -979 -277 -725 405 -596 776 -2 -164 -949 -609 -247 -401 664 185 108 724 677 897 -660 -23 947 -239 -254 199 888 676 -272 -182 -76 -558 -989 -50 830 735 436 648 809 113 -284 -1 224 991 308 651 808 239 -922 572 562 466 306 13 74 -650 624 572 -558 919 319 665 556 -102 -760 514 -451 -580 -914 445 768 -780 -134 965 -503 669 272 -220 -402 -359 -413 -157 -127 -179 873 -618 -266 -929 795 -398 773 -557 333 -201 396 215 491 -840 314 494 -226 -324
977 -300 -834 833 -639 -597 599 -353 795 774 28 -667 -244 -784 -697 90 -264 -49 462 442 -742 -619 -775 619 900 -199 743 550 -655 -555 941 -824 -830 139 103 -877 -566 378 -876 490 20 489 354 999 555 486 -24 947 908 781 706 529 589 605 -759 837 -592 880 -102 664 508 -444 850 -885 -696 482 -493 -865 801 -828 414 -429 727 -363 562 -980 -986 118 -492 899 995 471 165 -714 494 -551 -327 214 537 -829 -704 -391 300 -62 -376 -175 289 581 198 262 103 755 -969 90 548 -857 -253 345 -772 -28 -180 753 -432 371 302 349 993 -11 620 -143 504 -39 -15 -466 -426 -551 -159 -876 -612 -860
977 -997 873 233 -538 -503 433 853 75 -277 -898 971 -509 116 -239 -23 662 -335 -400 220 515 511 385 712 -247 478 -772 580 103 536 897 -163 779 -555 139 792 849 549 -428 880 1 650 -161 468 515 -678 664 507 -722 -549 902 -969 859 864 -689 -126 -798 -692 955 363 -578 672 791 803 132 -485 631 -77 181 -580 457 407 -505 661 -759 -613 -943 -26 848 -174 457 453 791 -187 -48 129 -326 -95 -574 966 74 274 747 109 -715 796 -127 -775 -816 911 -661 -435 -64 951 -461 105 961 779 189 592 637 -444 861 475 -412 -556 -259 660 628 -661 89 -682 545 -508 498 553 982 793 -332 -242
777 134 192 782 -738 338 436 334 -299 211 298 -955 342 -784 -997 -458 941 636 763 344 463 -791 786 -996 289 -640 234 -150 590 820 40 -259 -620 825 -410 645 444 543 -965 394 -5 -389 -353 -198 -584 134 991 -65 811 567 333 105 -91 -48 918 -494 417 -110 79 -428 -60 409 -838 -183 385 -687 818 -874 483 693 -641 -419 193 368 567 -43 -41 583 -122 -611 -419 -948 -475 416 -791 100 -916 145 71 -888 -266 -56 -83 316 -790 87 -609 291 592 -284 377 -931 -340 -86 -208 106 797 854 -396 441 -295 -285 -975 -447 -359 -982 336 425 351 976 684 704 -322 -32 366 717 517 -456 -372 325
748 132 -762 -573 -417 -529 -883 29 -626 -129 768 -106 -562 -705 509 -338 -547 277 816 -624 361 -785 692 -52 -162 561 620 706 594 958 523 -718 918 -973 -16 719 -186 -33 226 616 75 -966 -845 112 -650 202 712 -867 -659 553 623 990 418 766 -261 962 329 -315 -672 -256 -411 137 657 929 923 -9 -968 195 -486 -493 -325 -530 40 731 811 467 900 219 298 -234 663 632 -602 -270 384 884 -747 144 -515 142 -983 652 -330 -71 954 -275 73 -671 -823 -600 -742 276 392 -304 661 410 -817 991 341 -166 58 324 714 -952 -652 401 708 94 510 593 694 64 -343 -857 481 -614 -814 926 -794 -204
862 -883 -892 -27 399 440 -466 -53 -810 -295 915 211 -680 30 -628 762 -236 -233 -425 -95 937 96 -221 215 837 -657 -629 -335 383 320 -217 57 -115 339 -355 -900 781 537 -474 -640 -126 482 677 -194 59 -581 361 -972 -95 -561 -398 475 -16 -112 387 805 -725 -211 506 -530 259 -865 -132 85 403 -672 340 -542 424 -941 51 -121 -677 581 943 -138 301 361 284 -239 574 520 -744 43 686 -902 -714 470 775 -625 -525 295 -301 -590 667 576 139 -590 -163 -858 -680 -866 969 -944 1 851 -222 175 -273 -951 300 610 -588 365 -512 481 -978 582 267 -80 -993 -412 -134 -162 -537 471 597 891 463 261
-128 785 678 822 504 -822 778 762 -479 897 468 834 826 553 482 720 -886 801 -357 303 -847 452 211 11 370 52 -408 296 -141 252 -825 186 -772 -40 -264 445 -678 409 -855 -825 -892 -855 -243 -245 756 690 0 329 520 -103 -289 277 286 346 -150 -152 576 594 -601 872 492 -466 -680 917 -547 -470 -1 -75 190 -737 -640 138 -462 922 78 421 -966 846 -579 -460 -909 237 643 -833 -537 727 963 41 -978 194 -870 -647 -279 -890 374 662 -854 905 502 606 -39 93 -727 843 667 -516 -627 -168 494 83 -865 -298 -428 -169 -317 709 106 403 486 653 420 904 176 -122 -852 160 34 468 946 -286
-484 149 -543 838 187 152 37 -42 819 -418 -262 -340 -303 1 -630 844 -786 -197 -464 75 -288 -699 -979 329 768 -474 978 -858 -606 -400 -373 587 682 986 -205 690 -75 153 206 -238 884 -77 -644 -171 103 -930 668 148 -24 38 -145 -448 -552 -35 -397 -190 -957 484 -410 821 -637 711 978 -78 -826 -673 -215 927 634 -978 -123 779 -317 -603 254 -88 -43 -454 278 -87 -729 -612 216 825 504 -907 625 -216 905 -850 558 941 -116 635 -332 -523 427 -922 420 45 939 -442 -107 283 -839 50 -766 -945 54 655 475 380 401 843 635 594 597 814 -327 233 862 647 341 925 -808 -666 -166 -717 -151 427
691 -499 962 982 -13 -799 -391 8 -971 956 22 -299 865 -535 902 35 214 939 -199 770 153 -780 -444 595 980 233 -780 -378 193 162 657 852 -764 500 985 821 986 477 636 -718 197 -14 369 -701 248 116 312 6 942 -896 -366 810 -186 -240 32 143 259 500 -492 -630 -402 -541 851 -455 821 97 -366 -429 786 276 -707 -457 784 -768 688 -412 780 40 -975 -193 -782 -726 -762 -901 761 -692 262 -961 420 -509 -255 635 33 703 663 -304 520 524 -678 -397 480 -495 -190 -289 901 427 -324 -864 -985 -946 -797 -273 -980 875 -796 -929 -541 568 -15 173 -289 438 135 -245 -260 212 664 348 -315 901
-290 -605 -839 -588 -685 769 887 153 -927 -921 -401 148 574 -847 240 -272 122 320 117 934 29 894 234 -893 25 986 -617 741 -467 486 -66 -471 394 -473 408 -652 691 439 -320 -541 -796 486 370 488 292 608 -873 169 -128 744 -266 25 159 981 641 625 338 733 866 906 282 369 -529 -107 714 393 348 -857 60 -178 35 874 -99 -73 894 338 -791 -504 777 -592 -917 -548 132 882 -645 -609 -633 -68 99 300 -781 528 118 7 801 999 101 -527 -407 914 -191 -685 -591 506 823 644 984 121 -453 409 146 643 -481 -606 -495 -136 787 -423 -93 -122 -543 -913 -468 843 -953 -849 -143 909 44 126
375 607 426 -168 212 720 -750 700 83 472 473 -238 -641 -997 -550 361 -529 -751 -474 -907 860 -395 835 40 -560 -763 81 233 -335 -619 -218 113 -750 -403 -337 -355 -990 -236 510 488 900 386 -287 281 -139 -52 -770 843 -532 -242 635 -307 90 -787 -987 163 599 487 -528 393 910 368 -348 -46 -52 603 -581 525 -601 967 -367 -492 406 90 744 -496 -599 501 647 -274 -430 475 -754 -297 -70 -941 -306 348 414 -693 -667 -293 -463 -275 451 -791 -542 870 -320 186 116 316 157 193 650 414 740 -695 -243 -190 910 -21 -691 689 211 610 302 -229 -634 75 998 -302 369 -48 808 -765 -321 -271 974 -869
-423 674 437 144 -748 -282 -925 344 -449 120 924 277 93 -590 462 -464 960 799 147 -365 -13 -5 766 331 -628 -1000 288 559 72 761 -637 -848 -304 -503 468 -814 476 -976 141 -989 306 573 48 -371 -973 700 -906 523 125 777 899 163 -260 0 968 516 -887 77 -752 691 -183 924 -91 989 742 -585 -239 564 923 -764 -733 -689 349 277 -704 -829 664 157 -445 998 -219 -820 -9 372 378 -923 -238 -12 -696 -198 489 -290 -438 -396 -178 761 -919 668 987 -763 -329 778 781 -954 991 153 948 -267 474 -179 815 -551 -244 188 72 -408 -493 880 -471 -590 -205 788 655 926 432 -937 430 -971 863 686
-389 642 -450 -488 -197 -583 523 -25 662 -719 -717 973 -105 979 707 -678 -526 -217 293 580 807 203 512 -565 -607 -449 203 -981 136 -531 -132 -186 -393 -635 799 305 205 683 -301 958 -572 459 920 -945 -689 82 -807 -247 -645 -427 38 -522 -899 -765 -568 421 531 389 -562 -369 -88 910 -985 -283 -681 -40 535 -866 -304 342 -50 186 -632 -6 -422 -17 873 284 173 713 -941 718 -524 339 497 7 -740 -385 -234 980 -714 135 45 -863 401 -101 -216 259 -828 733 6 -958 -663 383 864 -956 -975 971 -999 -879 840 674 298 -66 -409 707 -457 461 495 -318 -284 -222 -694 668 -701 715 -201 395 -412 -359
-692 829 -99 242 191 -362 755 -685 -561 415 -54 510 -10 -838 334 844 454 392 111 549 689 -543 -389 817 505 -672 -403 -228 773 -804 -643 -754 -792 608 -326 520 856 -511 756 -320 -542 948 474 951 77 772 801 -55 -964 -575 -722 -994 -306 -701 -1 -961 39 954 -448 -69 90 -783 199 805 -941 -78 704 -865 -709 -553 430 113 -805 423 340 -479 676 814 836 0 -613 218 602 -883 46 47 -626 -990 608 555 -161 -154 -458 646 820 -351 257 -374 61 490 -340 225 -724 548 -4 339 978 940 68 874 961 -748 -500 -685 721 300 -223 894 100 219 -711 164 277 -720 -284 -123 998 755 489 392
671 -444 584 674 699 563 -215 -897 49 -161 48 -25 -374 782 745 -949 975 -630 30 -39 -953 -791 -140 -852 135 -273 930 -218 -763 -475 545 -910 -792 -298 766 589 404 -789 725 -897 -472 16 -211 199 -728 -90 -576 -501 -840 -393 614 492 -261 -533 -425 6 -827 -948 683 -880 361 -127 642 723 -647 667 44 543 -67 -198 -949 140 -161 -698 84 861 -306 331 897 -280 -512 -67 993 -40 324 -361 -333 -59 300 694 200 -176 238 110 -489 -333 -802 55 -163 311 138 62 736 -177 898 -684 -373 383 -141 -234 48 -954 203 659 -728 720 614 -168 379 488 241 -953 928 -205 -120 976 189 -946 290 185
-925 -849 -682 -839 -172 -692 -688 -577 728 109 -632 702 -539 -50 -71 -748 341 -380 501 803 425 -350 97 -646 11 -589 -400 -714 572 846 -103 -800 49 -293 -150 348 -539 -108 -101 -79 957 -510 719 910 -39 -834 -75 789 -606 282 -537 -112 200 848 -804 -163 247 450 422 849 494 726 -849 637 204 -983 570 383 -383 415 150 -178 -205 -644 140 643 615 572 -351 846 -227 707 -323 268 -379 224 491 -132 -774 551 967 -460 -929 458 -795 -651 784 57 17 -257 -337 -695 4 -613 -561 -745 -333 -620 160 -507 -377 -381 -414 -188 994 101 267 143 -836 -5 448 -460 315 178 146 -114 64 -966 711 777
-622 938 -186 -169 348 29 59 920 -101 800 -949 -552 239 514 181 593 -812 868 -910 106 801 -270 -593 -964 -28 -787 497 -471 157 684 536 -585 639 -294 -414 972 321 -774 -652 220 -356 465 443 909 482 -658 304 149 -469 299 -326 -142 -96 770 -470 545 322 -763 -826 -379 541 681 61 154 592 -523 472 -962 -490 310 -978 686 -927 -854 -31 670 982 -185 -386 -918 -513 534 -547 -782 -321 -321 486 229 258 519 888 -430 836 -610 -763 717 -790 297 -576 -56 992 898 157 -714 138 -482 506 -554 -574 -117 538 -724 -864 257 -995 -512 -978 645 -364 775 -53 628 431 -60 732 -411 -74 -328 -882 922
105 109 -831 -273 270 -289 585 434 -918 307 -539 527 332 944 381 -108 193 -963 -856 -399 127 -38 -280 -164 909 630 -433 247 -740 486 620 -641 168 168 -577 -629 -356 -634 -176 -121 -37 205 254 686 -420 -556 -835 126 362 936 -231 561 924 -275 126 921 -410 676 321 -174 827 -702 -556 691 309 -161 958 -960 -556 -556 765 696 -143 43 467 35 -836 -772 -465 85 965 -902 -805 -183 -447 -621 834 832 100 -961 571 -648 955 -778 -716 100 -822 57 117 -195 697 145 -7 478 -962 -82 -308 -876 512 -233 721 889 -352 -114 -357 -982 723 -759 -136 452 475 -840 880 -158 654 -442 -759 -569 282 400
-588 -216 -486 128 -419 214 -111 349 -433 -885 717 -119 814 -909 254 -806 -62 913 648 71 -205 756 288 270 -559 -43 148 -22 610 864 937 -373 7 -338 759 -431 -614 698 -163 -395 -49 114 848 -318 405 47 427 220 649 -197 -159 -869 603 -190 416 -285 -302 -678 237 784 710 -930 -532 800 34 -830 783 -141 613 885 -312 -137 -304 554 -648 -138 -918 -151 173 174 518 -320 443 -953 430 826 -241 300 -859 -539 848 -509 -472 644 -948 -515 944 478 880 -663 376 799 340 -425 270 -446 -463 347 -589 -415 885 617 -569 -999 671 -419 -357 -569 27 -3 226 700 552 -856 234 -710 -353 134 212 970
24 732 -473 -12 -221 -323 -751 -155 -872 -258 -293 -701 -930 546 -266 -668 -176 -637 958 -95 884 -103 -945 727 -572 204 242 795 -169 279 -574 73 608 -381 588 -875 -348 -37 355 -108 -49 -357 -762 -466 285 -993 -991 -640 588 838 -960 -903 -266 805 -781 -685 219 -425 -559 -420 433 -298 -326 920 -402 -619 -773 596 677 -545 -269 677 -504 -319 304 995 662 -298 349 659 2 350 -693 -263 -917 245 -495 820 -410 755 185 -221 157 631 -697 -279 261 60 652 -947 -650 -312 -937 -153 -950 715 14 -304 -835 407 -867 16 -901 -998 -604 600 112 562 286 886 451 -695 -840 -509 356 632 -425 -511 -179 -158
768 -243 359 572 -639 -796 -97 -306 -286 311 730 164 979 -666 702 -459 -250 634 167 -957 -179 551 -822 -565 368 -780 108 -223 147 -245 -578 -292 714 75 785 557 -520 -282 32 -747 -426 -323 403 -465 175 -62 -723 371 564 -747 483 -978 -252 -283 -670 -603 -321 417 933 643 417 -359 459 -788 -66 375 -453 925 79 855 348 -110 242 -99 192 583 -604 -940 700 -443 -907 481 546 650 479 -953 -189 481 -648 465 -382 -597 790 224 -105 -151 -684 232 -434 -101 235 -50 -552 -731 -849 123 386 695 322 842 116 -519 -451 -339 -834 -561 818 -745 -663 457 -851 986 30 308 -281 -30 -357 117 648 -204
-296 573 -862 399 -988 101 -504 701 116 38 -223 426 -832 740 -278 -514 626 769 -579 -337 -523 739 922 -217 -305 -217 675 -745 980 363 529 673 -811 870 -769 823 293 -434 954 -323 638 -312 -682 -508 435 -115 -136 330 80 215 -633 218 -256 393 340 -220 -382 505 600 -89 305 -296 -381 957 986 -114 585 -830 150 739 87 -68 273 -454 600 -139 -559 39 15 -876 -651 901 182 -205 456 -49 746 841 -520 -689 911 -986 -88 774 -910 466 988 995 398 -458 604 836 844 772 -660 481 492 -184 -692 517 -568 1000 655 -227 -258 681 -200 488 684 -194 408 -110 -480 -344 -490 800 583 -940 311 -65
-1 606 -725 906 799 -29 381 319 -795 -707 -535 -369 -835 -654 980 -168 398 402 -459 345 -428 -653 -4 787 -984 598 756 90 -604 -723 -95 608 -65 -40 -922 -259 168 -550 -566 223 -476 -541 341 -433 669 306 -352 -322 -404 540 -344 564 -772 265 -85 -528 785 409 -412 -282 252 -959 -16 818 585 -946 -745 -43 -788 -534 236 -391 -164 942 296 941 -125 304 210 -982 267 446 78 441 -73 57 -267 -110 113 -581 -386 -126 455 -513 65 350 788 -290 -283 -328 835 -668 -953 531 721 -431 -133 -545 -78 -497 580 792 538 -679 -829 -108 -115 56 55 101 956 19 440 896 467 516 323 999 -555 -188
328 -475 -607 21 -341 -631 551 -131 350 -887 913 -699 -142 151 956 388 994 109 -80 82 -751 71 -447 -475 -457 -893 223 -767 -113 -653 -568 -284 -197 -496 218 730 -672 425 780 959 -561 18 62 -519 -230 -223 93 1 816 -310 196 911 667 -378 129 -871 920 -178 -84 -650 355 -514 -858 351 195 -205 -855 13 623 -225 -635 242 -609 246 296 -804 490 265 -669 -274 -378 -204 -582 -194 8 -245 458 -465 -516 -831 532 471 -942 -538 -57 -501 759 307 504 -403 -900 -317 873 293 -463 592 -904 -691 -529 772 -481 142 -297 -820 -786 -818 461 -442 204 -660 -16 407 -608 345 485 557 -656 576 405 -263
938 -251 -81 257 -329 941 -567 953 174 -304 614 440 -206 965 -320 -644 -207 96 -357 -243 340 -776 724 832 -426 668 -104 746 851 -885 -707 762 -964 -688 787 256 611 259 34 44 -456 -328 412 198 921 500 -834 158 -171 -258 342 -539 252 -302 359 -832 -142 640 965 200 -28 498 -394 194 -920 -687 0 211 136 -799 -446 989 555 799 382 -954 -406 -154 904 -963 721 -983 -797 -984 -833 -104 881 -111 822 -1 183 636 -871 957 352 555 693 102 -117 735 331 -812 935 811 -139 -530 -251 734 -538 30 525 707 -113 934 -827 263 168 825 -370 -998 536 13 832 153 444 134 750 -740 -839 -191
-150 -461 -938 -929 -785 937 768 -755 441 -568 691 -429 541 -500 238 990 471 281 -110 34 -63 -726 236 -124 -892 625 -449 -400 -567 403 -9 -96 -880 -714 -668 -425 294 -317 -618 489 -517 193 177 710 376 977 -478 750 -620 -777 -528 604 726 -942 302 680 760 387 -390 -357 846 947 24 614 -954 422 -53 401 -249 -388 435 -712 -182 85 887 372 -343 -529 848 932 -90 84 -863 16 -627 -490 855 222 -829 -378 -455 161 -740 151 -891 -675 759 -644 682 672 -204 -534 849 380 -240 702 -483 962 6 -571 467 688 -999 487 506 -201 -665 -703 698 10 -944 813 292 -217 439 312 -976 732 789 509
-211 608 773 257 196 -406 -87 849 918 -809 544 -400 -465 619 -864 589 233 871 146 -996 601 74 137 -711 522 -443 -391 15 44 -186 -509 292 196 523 -679 -431 -583 -291 570 319 -231 -516 261 -484 48 821 287 654 489 -292 241 -652 712 -906 -660 -280 -49 -706 592 -910 15 937 552 -584 957 30 -914 -222 -447 -132 283 266 -679 696 -296 -71 11 -478 414 774 -836 -361 828 623 -88 -772 -705 -243 558 -841 557 -633 683 -566 -22 13 -15 371 -387 -732 428 878 -665 1000 296 -877 791 311 -717 -980 -434 902 463 800 -881 -766 -747 -833 623 926 715 -398 695 150 -490 -865 883 477 195 -145
-35 -355 -980 -232 -359 893 -177 -340 944 -591 145 351 368 -723 -274 -708 292 225 -425 205 -632 -293 -463 -906 11 949 119 -627 -645 395 694 880 -77 32 258 755 450 -978 940 -98 873 -426 -584 -293 -380 -745 -308 513 -899 -714 -759 571 -471 696 517 -698 -860 -178 -550 -396 585 208 -723 -123 170 581 46 -437 -82 -402 -492 258 917 863 -256 857 -741 -935 91 550 974 211 -934 -69 -972 -369 620 892 526 -137 437 831 977 -353 -888 -113 -874 600 -26 -625 600 -33 637 -841 -510 -374 -334 -910 -927 -130 -524 318 436 -813 -222 243 112 63 200 256 -788 -748 469 -650 -361 70 240 125 -933 -137
831 555 13 -369 -184 -826 358 367 -496 398 -300 -904 -360 -917 -14 -898 449 -156 -353 -671 82 -240 -135 -472 -648 17 -86 -434 -471 968 -474 527 -176 -131 303 -774 -578 -88 754 -538 -155 628 -420 277 158 -293 934 505 -222 530 -49 -293 -498 -67 563 -511 -265 -321 -127 -794 272 -944 506 -211 983 565 -355 -769 -835 -313 -35 -896 25 -903 467 -778 385 -937 -840 -627 565 -407 -749 541 923 778 -886 -833 489 -686 932 -743 -37 13 -6 79 70 -702 155 997 690 92 -24 -275 895 -285 -707 26 -206 190 418 610 260 106 -664 899 769 192 -667 778 -204 137 -338 -139 559 -606 -710 992 -45 -880
-20 -560 -624 -760 757 -1 932 183 741 335 384 -710 -285 706 2 -738 -917 -506 384 67 4 -794 75 -417 -676 693 -69 -812 556 -235 156 440 404 -36 820 -643 -33 887 402 643 323 579 -277 261 -835 -311 20 747 61 601 -801 -1 75 -123 490 -691 -727 188 671 -376 634 -427 852 -784 -919 -503 -217 228 -735 -904 -256 -467 -301 644 729 211 271 507 -390 -889 408 392 725 -811 139 -852 -187 -773 981 -461 -957 583 -246 395 714 -714 826 129 230 445 -926 -116 -61 25 868 627 -280 -64 811 -380 -192 -821 497 -524 928 -746 -238 -6 62 -844 793 475 749 -707 901 -389 694 212 -110 163
-201 700 469 -556 550 -469 -532 862 154 791 939 -57 624 -40 -782 -707 136 429 16 15 -745 -195 34 832 -637 -484 -231 -88 -842 -50 -487 -15 830 -381 -68 181 687 -352 -294 -37 -93 661 905 318 -392 385 754 717 811 -644 354 -278 -133 228 -217 940 -902 -618 -700 597 135 -575 746 920 471 -950 938 776 549 459 -225 -864 -558 746 -383 -315 -640 -770 -963 -335 273 -8 979 320 -854 430 387 -602 483 520 51 806 738 -801 -292 764 467 -863 -121 -948 657 575 640 -763 628 -802 156 -334 -676 -63 609 191 -205 -368 -888 -207 -88 -864 425 -8 230 -94 508 -258 -554 -95 773 295 -313 -863
670 994 943 930 725 -506 -300 669 832 511 615 -400 327 -763 343 105 191 926 -837 455 405 -618 524 420 374 293 -675 874 -363 641 -320 744 953 -805 -629 -161 -431 143 99 170 -36 480 518 -802 -435 -108 436 420 -6 419 -830 133 787 -816 -505 560 -11 -137 451 -111 -526 -857 53 299 741 176 565 -34 -65 -685 718 295 294 153 -592 -260 207 166 83 -776 763 -87 -846 -304 154 -72 -262 -511 -61 442 532 419 -40 -105 -452 -832 -493 -78 416 853 -259 -263 559 -684 -70 562 -939 128 483 628 -394 323 81 -541 -558 -484 549 735 -524 833 362 -415 501 -127 109 37 -509 -782 -704 -803
637 634 559 404 32 405 570 640 -113 -941 -815 629 -909 944 41 -120 -811 445 -783 912 497 754 -621 545 -992 -67 -264 -988 -750 509 -943 -254 -392 45 -201 -147 732 -243 -142 812 -974 601 565 -915 798 -735 -865 -492 -113 -740 -290 121 -708 -722 -604 275 843 -659 -672 445 407 249 499 -984 852 218 -798 -625 496 -217 -894 968 -896 85 83 -5 242 -197 10 147 -596 -747 686 252 -410 -773 360 220 334 -233 -886 558 -572 254 -68 -973 -288 194 -293 -972 569 484 -121 -622 -751 -579 747 -892 785 -23 505 -216 784 -417 553 546 122 -198 -96 603 -399 623 -301 130 920 -570 951 668 -89 53
691 -482 781 -953 393 963 -513 465 -220 -157 -468 116 -98 506 348 -773 499 -589 -216 -133 555 457 -619 -189 -597 -604 -89 -509 14 276 678 -461 -564 852 -376 380 821 -716 -725 -429 334 869 929 644 -708 -776 672 -726 882 880 420 -826 176 -616 134 925 -581 -328 978 -37 -621 -586 -760 -985 -671 817 -696 -484 56 81 382 661 -466 -544 -655 -534 -58 -950 569 194 -575 608 -155 -470 781 -891 -386 -215 57 44 457 -269 187 -925 6 -904 -598 -298 87 217 544 -503 22 509 -483 -369 -279 -969 967 -24 425 -233 -436 915 993 521 -835 406 -679 -654 52 -383 -505 -842 228 558 352 521 688 270
-260 -70 -68 65 186 -815 -595 66 -494 807 469 -880 -48 51 -569 737 -399 118 -902 -598 -114 722 -107 -103 -102 -232 281 -889 -994 -45 963 -865 737 179 124 -410 -611 113 -626 668 -755 701 489 869 -132 -737 561 629 -798 -130 -582 789 862 -292 277 170 529 806 -291 153 869 -169 553 938 -488 570 -325 -618 -712 -187 -997 950 -98 101 59 -684 -486 -762 721 -435 481 -509 -554 -938 743 -471 89 531 566 -764 661 -391 -150 -108 606 602 160 563 56 -905 936 864 577 676 648 -1 966 20 -506 882 -804 318 -883 -463 -703 276 -564 -722 289 728 -674 916 801 -612 314 523 936 447 102 184
130 -214 428 -554 637 289 -510 -643 -16 384 232 703 -416 813 379 310 449 -238 93 -64 471 -451 537 667 -948 121 -993 -832 995 -784 124 767 -856 -925 -419 -800 793 -402 -267 -493 -105 -280 86 -536 -259 664 953 -372 226 -507 705 539 -587 -81 -308 -973 475 -190 -990 419 -127 -770 506 778 -518 -266 553 334 726 380 -829 -309 -113 -886 -664 391 758 707 -241 -81 450 891 605 -492 241 60 -856 559 786 969 447 300 -172 -813 693 687 -479 461 -789 -582 -325 341 236 -175 -158 102 -681 -610 587 -903 337 -51 -763 -590 -588 -922 -329 223 195 756 701 -719 -856 -147 68 276 -352 -629 -122 377
-292 861 -544 921 142 720 198 649 -187 840 303 718 -550 55 -730 760 77 422 201 -49 -420 309 -454 -435 -61 -708 -106 640 878 -58 121 820 -170 244 581 545 457 653 290 240 -383 789 636 -159 537 956 -912 -243 783 -249 491 -427 966 527 -91 -661 521 214 964 -318 158 359 -392 294 -194 -360 -313 -220 -411 970 409 -170 -188 -235 -197 492 505 -375 -14 -842 348 -734 869 -601 561 568 -997 -209 423 23 133 -594 -168 613 -603 236 193 734 -259 -881 -459 410 -670 473 -148 199 596 -590 -177 738 413 -521 -592 -247 536 -629 -686 533 788 -57 203 678 829 -279 988 -43 -740 125 -592 75
925 -942 665 356 -14 243 -341 -984 164 -502 112 427 80 418 873 -198 -98 -899 402 183 -437 632 -86 755 -79 517 663 745 -423 -310 -767 -6 -250 210 -143 -403 -83 635 598 -10 685 -878 484 798 101 541 889 750 854 626 -477 583 779 -184 943 376 -496 -623 841 969 -502 -367 -738 -341 696 924 577 468 586 -193 -586 125 -280 828 -564 773 638 34 -146 805 931 408 496 627 230 931 -413 846 106 560 -780 387 26 -726 264 -182 541 692 -62 -129 447 924 419 49 806 944 -432 755 912 561 -50 529 993 453 763 398 456 643 908 -858 56 -799 478 -149 -394 847 823 -231 414 -131
-623 -422 -998 27 -290 177 -69 -670 -119 -536 -456 882 -818 460 -101 -860 559 -21 -145 -308 710 482 -224 206 -372 893 348 -252 433 -956 56 -140 808 837 -82 748 -894 -441 772 -795 -476 -838 -639 229 144 163 318 -75 239 466 302 999 -362 -725 -154 -227 -615 -213 518 -313 618 -739 -250 -207 175 -455 -598 -146 -807 -731 342 -946 -893 -561 -499 882 -572 283 406 -457 -51 -428 -767 220 -184 -182 -531 -640 -27 -152 -534 149 -430 -900 71 -938 299 -941 -518 -103 387 215 -874 -623 -930 949 -831 -760 -286 -888 738 265 323 -216 977 81 -625 713 340 -115 621 29 3 -158 -841 -426 -438 136 760 -40
-438 -99 -389 -101 -265 -784 68 530 926 262 391 -352 -530 230 418 -951 -703 858 508 -304 -889 520 355 549 414 -539 -723 595 -227 -812 784 -533 644 767 734 950 -902 -772 781 443 -61 807 -174 41 -746 -697 -988 957 182 245 164 -102 800 -424 563 -106 89 156 -604 88 221 -366 -405 -364 -746 -773 922 -697 253 -425 -590 -263 187 -67 863 500 998 518 703 733 261 -661 878 859 828 -810 938 -780 689 -248 370 798 -533 824 739 354 -462 -216 -339 893 -975 -515 383 978 -923 -692 762 -792 663 310 586 -382 502 -829 752 -586 -297 479 211 -769 -449 391 711 -304 911 -108 88 -55 -837 -310
671 -849 -734 744 -109 3 80 76 45 -190 313 77 888 280 -198 -237 914 369 -180 -29 -436 574 -310 -148 -751 -757 -603 -708 46 687 -261 823 -954 426 963 -189 845 586 -836 -709 861 931 -305 -334 -941 -814 266 177 -132 315 1000 880 -324 -382 -521 -546 1 -320 396 -255 -207 -238 26 335 646 264 -76 714 378 -888 -747 -282 -954 412 728 300 -366 552 -484 680 313 -746 -505 -776 994 -937 -241 -75 -692 509 675 567 167 -752 54 710 -487 -477 -833 -724 756 -158 612 -949 -989 -472 523 -469 -747 679 -766 -519 -140 944 -334 -204 -783 -542 509 651 178 -733 -85 -82 -135 -26 806 -543 -449 -860
780 991 -507 430 276 484 -998 -763 623 541 -107 494 718 -729 542 847 -685 824 -628 986 355 -418 471 -524 -977 130 681 -308 -555 546 806 -292 325 -109 -874 -570 70 -424 19 600 -559 -629 -188 -96 300 -649 -135 -723 -755 242 700 323 174 591 -885 -866 -720 822 888 508 655 324 -40 36 -554 813 -984 545 754 424 887 161 26 -959 676 -542 -483 24 -583 256 978 212 764 -771 -488 -40 -755 -739 784 -476 -816 582 89 -168 656 144 188 -922 218 -943 -448 924 381 -901 -916 -715 79 -420 -823 930 753 -897 -650 894 -749 -168 448 -912 -983 814 571 398 -800 623 583 -814 -167 528 -678 -914
588 7 -926 157 -505 44 -164 -218 -539 -341 149 679 -243 -92 -985 -256 -210 83 -196 -802 77 36 558 -66 956 966 -41 -243 -820 951 11 -564 492 -139 -880 543 862 -815 275 225 -130 225 541 67 469 -612 -464 494 735 -390 947 610 492 879 -21 928 632 340 -490 -107 673 -134 -553 -884 -802 -40 -811 954 -45 123 86 154 -657 521 625 198 -44 594 933 -781 387 -923 780 -969 967 -372 -464 -579 -177 266 396 744 815 42 999 123 -756 -117 -507 317 -51 -914 664 -247 -440 -710 -353 -172 -118 -103 -860 158 -640 -157 -788 -219 757 -902 931 -252 793 265 -352 -344 -13 824 368 423 -844 420
405 -36 -952 794 -845 970 724 -754 822 357 -740 736 -897 615 49 883 69 743 -835 282 -667 -923 -861 -908 -796 792 -239 -126 -84 212 -70 -417 735 -618 -756 -587 890 935 -384 -400 -741 52 -959 15 516 -325 -70 986 -595 327 -122 133 -15 -610 -199 970 261 414 801 -372 498 381 -835 -139 919 311 -424 804 -851 86 -138 -308 519 -543 -194 -394 352 -171 -340 967 -153 -233 -828 -738 -551 382 335 812 -318 454 -245 808 -730 278 -57 278 46 -730 686 -399 592 427 60 218 88 244 -168 -772 -678 -237 -211 669 741 -356 851 791 902 -438 -555 949 304 -729 -784 -678 -245 696 -991 906 -610 -438
-484 -978 486 -133 781 -978 268 687 734 -176 709 -566 362 -605 -617 66 -445 -163 -157 908 815 -683 427 -784 -611 718 -331 693 909 202 -225 -820 490 125 -982 -665 147 -16 675 -181 -646 -56 -258 439 785 -610 -91 -142 -843 -275 930 -703 -704 -587 354 -194 -425 -458 -601 95 -227 551 -351 -405 -958 -637 458 546 940 -849 713 913 -563 160 842 -533 -949 637 -126 776 -125 -579 -891 -479 740 -648 -969 -429 -8 457 -216 -242 374 507 -810 -962 352 668 -485 269 321 964 -345 -917 732 592 890 -426 67 385 687 403 444 244 -281 -986 -881 487 456 827 -328 405 384 248 399 -976 -457 272 178 153
-671 -73 919 322 -612 -922 -5 455 797 -847 -865 219 -881 303 379 759 -609 441 259 301 20 -12 -150 -227 -311 -396 518 41 541 943 423 999 -488 -832 -820 860 626 -134 198 -690 -680 -489 948 701 748 703 -406 -628 -214 -945 273 394 -743 -262 -437 5 476 269 635 932 -685 812 -339 210 571 -610 -152 -936 676 356 752 698 -263 737 -869 -881 -569 113 521 -5 -279 876 -740 421 -975 -929 -649 430 -780 -292 -380 -413 471 903 764 -454 975 844 -561 -203 -472 -870 757 63 728 -456 637 -392 440 493 875 -224 1 485 -222 751 119 -729 932 -147 411 177 -590 -371 -92 349 540 -962 313 -615
-270 418 306 -551 -633 697 280 109 237 783 567 -104 -151 919 -165 523 -697 -20 -209 236 -380 -907 74 680 -41 -470 939 569 -608 111 -339 844 289 867 -529 769 -758 -124 -674 -209 -573 194 -790 779 836 997 -181 775 -176 36 473 -199 28 -549 567 802 -569 -619 -854 23 -854 -950 -937 529 231 -115 600 -672 519 -94 220 2 -891 -47 -883 -186 -732 998 847 -568 -277 566 125 13 -754 715 -403 -565 -682 -547 392 627 -920 576 -165 -340 -631 -368 224 -802 -646 810 -980 130 428 -314 -822 -320 -886 606 840 -84 125 740 621 -696 -601 34 881 992 260 423 -770 125 700 611 880 646 -492 568
-181 466 972 166 519 -147 693 -863 -482 224 -452 410 -684 -752 832 551 462 243 -254 774 -978 -414 48 781 -281 -509 464 504 940 495 -296 -254 265 -638 -272 -639 939 -159 307 474 -63 722 -80 885 492 -241 -180 547 572 232 -48 -746 491 79 183 370 -260 159 -460 -924 804 -844 -982 500 35 20 -249 645 -462 486 -185 -698 972 -413 707 243 -308 250 -317 -742 -24 617 -869 -987 898 -859 917 -184 469 -138 -965 716 921 -882 21 -567 -337 -609 -427 17 -562 252 -37 121 101 -871 160 -334 995 -658 748 -260 -111 -724 494 301 -239 600 958 -12 -112 -836 -101 692 504 -654 -670 -805 184 -152
533 451 -567 504 147 -92 793 -155 196 -80 -490 -470 -780 701 373 -975 386 328 959 -439 109 -832 85 332 -722 843 -198 -790 -479 -580 -161 857 901 47 897 427 -967 759 -583 -198 -940 -174 -678 -532 -339 980 -684 583 -308 -25 608 571 -371 -490 -764 -932 884 370 918 143 103 306 477 348 -203 -272 -557 -907 -581 359 353 735 -568 443 433 -80 311 253 -322 -856 -382 -252 -210 442 -810 -776 525 244 -214 -149 -6 -216 776 869 -844 650 617 -798 -19 21 -112 561 548 492 -572 197 918 140 -75 734 171 69 -743 718 -571 -598 598 -374 893 -62 345 -957 -438 804 -23 430 -197 935 89 -146
762 -457 -310 387 889 481 619 -762 651 -836 405 -800 -803 -271 639 374 -612 -413 595 -685 47 680 -704 241 -358 462 312 340 -962 153 613 -56 -932 -782 131 -201 -207 907 401 241 -472 113 10 291 -382 -309 -505 -610 559 25 -837 -308 673 -21 -430 800 -839 -484 803 -591 -15 -311 674 359 -199 -698 206 464 253 -450 -232 384 259 703 -212 562 288 543 107 707 481 -925 -862 598 -919 -191 -957 -931 249 -873 -387 -835 -536 931 958 34 -674 -711 245 -5 -765 -400 96 -705 978 930 558 521 245 -655 115 -767 120 840 -643 838 337 -254 -239 281 484 -778 -977 505 -971 -872 -841 -834 134 583
-856 114 328 -697 687 -585 620 773 708 -977 -139 -921 -563 -524 610 475 -272 -615 309 519 -138 -791 -423 -460 814 -899 -156 -4 -252 -188 109 382 929 -593 530 579 -593 -335 180 914 -512 46 -28 678 883 -295 -668 -281 -513 -191 906 -974 225 -517 593 -3 656 391 398 -941 -826 -969 254 -420 -562 -507 503 486 979 -134 -267 438 522 -178 110 804 826 -727 -694 -202 560 -571 -706 191 -491 -306 -28 992 896 -412 476 858 -360 -121 -846 -250 0 619 -266 956 -903 -807 -260 -830 -624 -717 -736 -264 -409 -805 255 -740 355 -412 -899 -17 297 101 -846 -534 -274 490 786 -730 -244 -563 647 -327 98 -227
-555 285 -372 913 134 -446 -414 -239 629 -491 -453 472 -53 -546 -439 -761 -888 225 757 26 137 247 -283 996 797 -852 255 -133 -327 -600 -901 458 749 -133 219 370 -480 -678 -999 330 -734 -862 -321 -589 -696 -874 359 -639 -62 -360 611 -552 -693 -570 480 89 -8 -527 -962 96 259 430 -524 -487 -307 -37 217 824 51 174 -367 -649 -944 340 -368 -909 -11 787 -597 -666 634 370 -259 879 826 743 -942 -15 -965 -691 -706 610 -482 -840 760 -945 279 209 -642 702 46 42 -881 -795 -587 497 -971 800 -617 758 43 -578 582 713 -803 183 223 -207 521 -136 -953 -829 979 -6 -482 190 376 233 -508 869
906 459 -938 240 -538 527 920 750 -124 -635 226 296 656 -286 380 -935 342 -455 -733 915 -277 696 -563 355 318 742 -2 601 -696 178 751 -500 -222 812 -657 565 -374 611 348 636 672 441 923 714 63 966 -592 188 777 -125 191 -763 535 520 769 -529 -601 803 246 -34 -808 -289 567 -935 -904 -574 212 915 338 69 811 289 -36 154 740 135 933 181 -145 -481 -151 -141 184 -476 702 995 -827 378 231 -309 725 -160 -856 -438 -587 -560 61 -977 416 -259 613 400 739 -213 -657 549 359 -32 304 -718 123 -795 173 698 -632 726 -443 -243 -783 16 -71 558 -203 781 757 -765 -551 774 -619 -589
243 240 -799 -680 -249 -407 988 798 734 -685 -213 865 187 198 -1000 757 -712 772 -316 488 466 -455 697 -177 727 -326 376 486 -251 517 771 -675 -340 -842 -646 474 764 410 -403 -633 758 430 800 273 -962 317 -414 996 371 -112 455 -119 550 955 -143 -504 -327 -843 447 -163 -101 440 -953 -211 585 -782 492 -890 674 99 89 -488 -115 501 972 435 -82 -224 -648 -630 276 -879 192 -140 -636 400 -369 -273 292 -363 982 -960 108 -618 335 398 101 -323 -442 -962 -585 -537 -596 264 625 -353 -143 -992 790 -260 -696 619 -841 -41 -995 -915 894 867 444 -959 89 529 -740 403 -894 978 747 375 -38 914
916 426 -938 891 -629 -288 -662 380 -961 -415 -667 524 -652 670 -870 532 758 -518 65 240 295 497 -616 -339 -665 313 -851 174 834 -767 -47 825 837 909 187 239 935 -683 78 208 -285 -898 796 796 226 123 609 517 547 -990 -502 176 -211 -578 362 354 -837 196 -794 -201 221 -789 -940 -100 -353 -161 877 -617 936 952 607 306 464 313 -139 167 -843 -721 920 248 -895 824 831 969 -442 220 201 -695 644 680 -658 -452 395 387 -76 466 224 -185 790 76 -259 849 776 489 -351 -619 152 -155 -745 462 -999 817 -253 -433 955 -182 -28 768 -529 -104 -631 -429 556 475 -750 -609 894 174 469 -835
-835 -20 990 905 235 -54 792 -420 231 -605 153 -317 -693 -989 358 850 280 628 596 -48 162 -638 938 -734 -948 420 -607 507 -923 638 -272 -721 696 970 348 658 965 594 -805 -476 180 600 434 -762 99 -590 -656 450 -82 -115 -47 -319 202 569 926 36 76 -963 -61 -582 938 222 -309 -985 519 -802 -391 -709 -315 303 681 224 -621 -600 591 921 203 -991 -825 119 -674 874 -110 5 884 287 -608 -605 -962 -118 -430 220 -911 -565 -563 407 613 456 409 354 -749 -357 6 -798 903 -975 -795 -824 87 -525 931 611 -95 975 -300 -292 972 809 -291 335 165 -346 761 -903 998 536 114 -457 -587 302
-781 916 -935 -394 -119 -221 -812 -836 838 -568 -964 902 238 302 359 -7 -57 -767 -600 -798 -622 55 691 867 379 -357 106 747 -45 245 775 -772 -485 -605 -493 -624 985 -364 962 -983 -33 77 809 634 -748 -941 430 260 864 -343 219 -834 -590 551 715 923 -560 68 412 -983 469 -53 262 -132 -979 -9 -78 876 687 -531 -321 -855 151 -732 880 567 96 -860 -608 957 -398 282 -577 50 384 466 -220 -742 -228 -124 187 284 -368 -372 -152 819 202 406 -59 786 931 259 742 -935 305 935 33 -638 -857 -906 287 -941 107 -289 -566 -939 -774 -698 -114 459 986 -776 -234 419 -559 293 716 -551 -307 -150
54 448 -239 837 -464 -220 391 808 818 12 -742 -322 -948 -169 381 79 -956 -343 -646 -190 52 4 -571 -673 -625 532 973 377 -520 -789 931 -471 -168 212 -226 251 -358 521 -730 921 -492 -507 -458 -978 -286 -810 355 -435 -704 201 707 -248 145 641 70 501 647 685 233 -553 -113 -655 439 530 843 84 -981 -749 392 706 -638 -947 630 -305 -406 -119 -145 -67 -868 959 -111 700 -841 -874 491 -755 -16 -9 498 -383 -266 -525 -98 -425 192 -880 53 -257 638 -345 -457 -993 -651 -654 559 170 96 -180 969 155 264 -123 -267 877 907 13 -102 -962 993 0 -724 45 -594 925 207 -159 453 971 -184 -439
-484 -272 -171 942 974 808 247 553 32 -378 -957 -698 -865 -288 -195 107 -645 -756 857 -624 -202 713 818 744 981 948 867 -627 800 -745 921 -919 11 443 -952 -630 -519 -589 279 -935 192 -546 -275 742 -321 919 -969 35 -667 805 -860 -85 -104 658 -538 -733 -934 -958 -614 -826 -521 -429 -574 -73 -806 -757 -878 -615 293 -482 471 454 -886 -459 61 -746 94 -946 872 448 -794 270 -967 -211 -200 -267 584 -196 -15 -354 222 691 -334 562 -206 240 262 -724 21 -770 -200 370 85 351 880 -462 681 501 -549 -888 -916 -694 55 560 -18 817 -352 717 581 57 -358 67 242 840 -46 -250 506 651 -129 818
-55 -711 851 853 -784 -501 464 -765 -809 957 -872 -403 -487 -948 139 155 -142 -332 964 785 413 -503 244 579 759 584 -743 -453 954 -30 169 38 145 987 -633 821 147 -9 403 331 -395 611 -157 -1 -854 750 -644 86 -5 -714 518 -970 -174 480 1 134 834 54 739 -480 -486 -892 487 943 194 158 21 -6 -213 -466 -436 879 683 850 -333 -224 -356 635 633 -559 -296 -8 890 367 -577 53 -475 -697 877 366 -565 -639 -312 -182 -316 -955 -499 -679 851 412 -896 -815 -581 -722 -813 -533 44 401 -8 -62 -870 -306 256 -889 348 -645 -221 -233 -691 -96 -110 -138 -437 613 -794 -677 -954 -302 -234 -670
-704 495 -937 571 815 504 -844 199 -958 403 -220 996 -231 -563 -605 560 594 394 -207 -671 202 960 -241 -239 130 442 -956 304 -672 458 -328 691 371 712 -678 -364 -163 -404 78 188 254 836 214 873 997 591 -530 147 267 918 27 886 516 -551 583 626 886 950 359 782 -398 784 -663 969 171 -526 100 501 656 272 -874 925 -316 718 574 -310 616 -663 -755 946 583 476 741 -238 971 -153 227 682 901 -116 -70 851 588 -302 311 275 658 -949 -501 328 62 154 741 -318 907 -648 918 433 -440 -108 -342 -798 208 348 987 -734 -445 -41 711 248 -420 -560 635 570 55 712 -21 -180 250 277
-921 -42 -794 -893 837 706 -259 454 -343 -340 3 844 -897 401 632 598 -479 96 331 369 78 -963 582 -725 -527 987 -944 -861 -995 -786 774 203 870 -481 -306 453 -548 -381 835 -424 245 -218 433 -166 -165 -963 -855 -816 -344 -376 766 624 551 111 663 -808 -138 -913 -705 -728 -403 -618 -565 428 -453 -458 -665 499 -430 531 186 455 -610 60 582 -833 985 829 657 -54 -54 -10 736 786 664 -939 -402 -903 688 -242 929 904 83 -254 367 345 570 -691 -749 192 609 54 701 279 716 435 271 406 -129 -753 70 6 -715 -244 -63 201 341 154 -554 -598 692 -768 941 -177 -301 321 -624 532 833 -218
655 -656 194 -189 -48 -526 306 336 718 -48 -58 -403 543 116 -493 89 123 160 -825 -475 616 -329 596 -134 702 -178 -242 -700 497 -116 165 731 325 -302 -678 854 335 799 826 799 -84 -699 -467 469 787 -972 -255 554 -277 -384 -864 -444 651 -496 403 934 -890 717 791 820 -886 -157 -933 377 844 570 -504 -674 -723 -422 838 58 777 -376 822 711 -172 -665 889 377 -210 498 610 183 -511 191 343 897 830 -952 115 -46 -643 -983 833 612 -607 721 -145 -497 -91 1000 -853 576 131 500 -427 682 290 443 -190 493 435 -735 181 -835 854 192 -455 11 179 323 704 978 -315 -963 658 -558 947 968
-826 -102 -377 -877 -658 -446 815 269 373 162 827 319 57 322 606 840 -576 -611 274 608 -141 -926 -99 -389 -686 966 101 870 850 -320 308 45 -535 -759 233 342 -307 -451 975 729 -992 -320 178 -47 96 807 745 634 230 733 517 250 -263 159 712 -240 -475 -87 31 -258 -889 532 283 -835 -62 918 -938 -978 -552 -809 42 78 -785 -285 745 312 -191 994 730 -679 -668 204 -761 -701 -358 -422 296 979 409 420 645 -900 269 -611 -698 -784 457 580 -330 -190 818 -694 661 -640 -38 -690 -539 593 -996 -990 -595 407 -900 139 446 227 887 182 332 65 -25 -185 -561 -300 -875 926 922 49 818 -52
-873 -13 256 649 34 216 -354 930 735 -3 82 777 -98 -574 -263 -789 217 -330 -266 689 -984 832 55 -416 875 356 608 -147 742 -472 180 -364 351 -69 -13 738 -660 573 -772 891 607 -990 857 922 693 867 254 648 -104 606 93 -416 444 514 597 -323 -592 -205 -333 -442 -680 -700 161 -41 -796 -99 -698 1000 -414 430 639 -306 160 -930 -889 -136 -671 -141 -604 -177 119 682 545 -652 360 457 -804 337 737 406 846 585 -378 800 -266 574 -201 -54 963 139 865 -561 672 -902 136 28 898 99 -671 -607 873 -727 360 -983 -96 227 282 790 293 -265 904 767 711 395 62 -765 -531 681 408 157
160 810 -384 339 524 -630 -95 -78 779 669 -856 -164 -819 253 617 41 -235 -970 -425 -918 803 -781 498 -774 280 955 633 584 353 -436 834 -92 409 691 314 -830 -46 -815 -60 -287 -496 -998 -681 167 676 -148 -506 -304 17 -388 -178 -389 -472 -777 -397 543 198 -939 909 -159 686 -246 344 662 548 -607 -770 780 149 -360 -949 926 -339 505 -2 749 946 996 490 332 -723 841 -683 -849 -132 81 -621 502 -978 -141 167 185 817 137 -898 115 286 870 -492 -481 -480 640 786 454 -749 -31 -521 100 -607 -635 476 918 -544 -111 -339 546 38 -411 -47 442 978 779 17 418 821 -453 -710 587 -327 -335
-271 -664 359 -906 -497 856 751 33 -23 956 675 111 -724 -547 -947 -343 -936 -998 389 851 -244 -829 -225 958 -37 -197 -728 325 -932 -128 417 538 20 -711 822 -882 931 -126 726 -631 -591 356 632 924 218 -453 -513 922 -248 -657 827 392 -283 -696 569 628 -441 968 -329 137 991 -544 192 133 -878 772 87 737 -927 -889 -195 999 -731 -877 -181 -837 -973 441 -356 275 722 632 -991 835 -263 939 -983 384 -172 216 -739 241 78 313 66 -178 -82 648 -82 967 320 -574 -299 -541 -168 -848 -627 626 703 763 -159 -837 -819 -243 -928 336 455 -433 861 -929 560 -588 -138 -421 972 671 -953 -164 276 784
-613 -954 475 -799 59 494 -512 -65 -506 -214 111 38 468 -79 -310 -563 -908 -688 -923 -895 982 198 -876 -189 -348 -402 290 -550 642 -751 298 -760 374 376 -367 535 687 -985 623 222 -558 170 981 -206 -339 -690 -443 506 215 -26 104 958 718 -854 -814 865 -376 805 561 651 -806 -249 -502 273 931 54 -882 452 919 -168 691 -244 -49 -135 -943 -130 954 514 -316 -381 -678 -121 -621 695 -141 325 -38 -979 757 166 -1 -478 219 569 -701 -929 159 118 803 923 -419 -627 -169 881 116 91 -316 923 -960 -334 -24 31 762 888 -253 459 -494 -390 72 -974 -653 -352 462 -250 375 427 240 -11 -322 -925
-342 589 113 518 427 910 257 102 -613 941 -490 -595 284 -912 -359 -652 17 419 496 0 -608 656 -308 491 -597 -387 301 406 281 -89 178 209 280 -246 340 965 380 597 176 -444 397 -379 -315 95 -942 243 855 921 -374 74 30 -162 613 391 619 -690 -33 -997 721 -464 356 439 -31 105 218 -620 628 -320 662 437 725 -390 -440 -578 267 720 998 561 643 672 260 936 -251 152 -513 -758 997 288 -723 199 60 530 -216 648 -689 428 728 -491 -267 -534 -254 -593 653 -576 -424 -28 889 -606 126 170 537 -207 -269 -90 -85 -226 -725 135 -875 -916 -326 335 56 220 -126 172 1 -546 -793 415
616 516 -598 653 350 -666 -348 582 490 309 664 460 788 713 -513 -486 -413 -789 511 -239 -586 -916 -654 -449 526 -854 -342 -834 898 127 -569 -599 938 -676 -749 62 194 304 -609 -556 -939 622 39 -574 783 -620 283 -849 770 -722 -933 -543 941 149 -284 30 -667 -801 431 993 -417 901 -253 244 510 697 670 -883 -947 -446 -560 -854 -318 449 -593 -700 734 -790 -226 683 -642 -379 830 -458 204 727 408 277 383 232 457 281 974 536 -560 398 11 -61 978 -184 -76 -177 823 -911 -702 423 -468 11 -525 391 43 -848 -613 -305 -149 -335 25 869 806 552 755 581 -954 166 583 -249 -861 491 -102 -804
725 -976 380 -731 483 -166 181 -554 65 -158 768 -754 -397 -654 -162 -181 -225 46 70 -312 597 226 195 224 -48 -921 995 -199 983 -801 -997 177 720 -359 20 193 -612 -197 815 -809 -187 36 187 101 819 -491 741 -397 12 77 616 -466 285 470 -251 203 137 -647 745 -468 228 -941 882 776 273 -265 694 -331 394 -921 -484 523 -362 840 602 -33 755 876 -316 -674 -687 173 85 -653 -915 947 271 614 -299 771 -159 -406 -238 -54 -234 722 -793 -235 190 -377 -489 -199 -448 -882 667 -967 -493 -667 369 -216 -708 572 -696 296 -978 -799 -266 -792 301 -108 -948 -330 -861 549 -515 -338 -976 674 593 -971
-974 902 -853 -630 -738 -532 397 -279 -517 359 -549 274 -829 -585 -928 -836 478 615 -849 389 -805 339 -579 385 441 367 -551 -410 -146 116 -210 293 649 677 999 415 738 -660 667 833 825 281 334 283 843 286 -916 -187 646 579 561 -342 988 225 403 505 75 34 903 -816 683 658 557 -696 -103 428 75 473 -865 -803 68 270 -848 -558 459 -803 609 241 668 56 -545 -769 -639 -420 -141 -479 324 802 930 -767 608 -911 654 -177 346 397 850 164 726 -177 68 -162 901 164 639 -445 915 -486 -596 -729 -512 149 837 -833 -858 -772 760 51 -919 -510 312 698 -667 -785 -327 321 710 -291 472 -917
-385 650 954 443 517 -203 927 -581 118 448 491 652 -578 540 -940 -490 614 126 -866 738 305 -267 -3 120 -36 572 802 582 -386 -176 551 -56 -184 532 -902 -232 875 -492 995 -382 309 103 -107 2 -15 -317 -579 -559 -108 210 238 -302 8 183 485 357 353 -207 607 -939 654 231 253 808 193 -497 894 680 -267 -466 -763 301 479 -710 287 -817 -799 627 933 -429 -875 -606 586 -668 -516 429 550 80 682 526 -353 218 -312 -725 -733 402 681 -365 -845 376 -315 -273 -101 529 -23 -978 330 -613 849 27 767 -431 272 -527 -225 -147 631 154 207 -714 871 233 -939 299 -440 -358 214 -256 -766 443
-628 698 -341 660 654 -209 233 -405 -307 -215 717 -156 -530 860 145 -947 -289 -190 -394 230 380 808 702 582 334 178 459 716 260 573 841 504 313 828 -458 -551 138 480 -458 -673 383 -410 306 -609 -820 -792 -85 760 -710 644 513 234 509 38 -614 -158 -532 218 -324 215 -819 -773 -197 97 663 92 204 206 760 423 -727 237 -413 -251 -258 -432 441 42 -816 167 8 896 -611 -454 -159 -626 -268 -231 182 718 290 -671 -678 31 -982 -615 668 -696 -884 -2 528 -654 267 -129 -641 948 -272 505 -984 59 -590 76 834 -24 891 542 359 193 243 733 278 -719 -970 219 -521 -796 207 244 -380 -957
-392 -386 -96 885 582 79 588 -815 -393 -136 -44 572 381 -165 596 -124 -535 551 150 -503 701 651 -6 -942 678 -34 -863 690 102 25 989 -965 294 -250 -910 -280 143 -903 340 -344 -522 -411 -634 -907 250 473 637 156 -596 997 -565 -452 -725 -724 335 202 763 -311 -474 536 310 22 -362 -99 -494 365 272 300 989 103 666 844 -601 -938 967 -446 434 255 -33 195 945 560 707 103 -114 -390 630 -220 -888 -70 -218 397 -8 590 210 -734 -794 -273 -84 54 163 155 -661 -211 -146 -897 25 55 115 -507 -413 -447 -791 -708 -839 453 -308 -63 -509 521 -463 744 -157 -318 -400 229 -699 -537 284 11
-695 619 -712 489 656 -445 662 737 -508 248 933 669 -32 -14 548 -39 380 690 -908 -102 427 -860 -958 665 199 153 622 984 400 857 455 230 857 -147 780 -1000 81 435 364 608 900 451 -244 -350 833 485 -482 186 -567 259 -273 664 434 -413 -397 -253 -368 -143 -328 311 698 322 -82 -296 620 -600 572 205 -123 -300 -89 254 164 -367 295 928 -858 517 -1000 835 -374 -195 707 -404 423 -40 18 390 997 759 641 -676 -293 535 942 -755 -506 686 112 211 432 -497 -575 551 312 50 609 -117 -924 370 978 258 171 -812 -939 107 536 209 -914 14 975 -665 -542 279 -399 -866 -382 -611 52 -176
-96 -844 -224 -977 124 -937 -253 610 -435 145 -598 824 11 -763 -595 -194 220 -751 841 657 -399 206 -393 458 842 -205 -449 386 125 786 -101 906 -785 -954 827 645 422 -188 278 933 502 -572 225 -261 976 -985 851 -735 -207 -202 539 798 -323 785 711 -538 -279 958 899 502 721 349 808 567 282 532 204 367 -690 -92 -228 702 -965 819 -911 -81 -267 -174 423 127 -83 758 82 598 -955 -841 -247 -568 -900 624 29 -58 791 295 738 487 869 345 -977 613 840 -648 258 840 -481 -573 -295 -534 -663 217 -237 68 -748 -373 745 -733 -482 -774 608 131 -883 208 253 -710 -705 825 -784 107 -960 -967
546 -296 -274 846 677 712 297 69 -746 -445 388 -905 -731 770 -988 -784 33 430 781 347 -394 578 -260 -649 903 308 999 -111 -635 -56 997 -885 499 278 -803 6 147 199 -245 858 501 -133 655 -950 -481 -488 -318 -941 -956 -281 803 -938 -847 -473 -697 858 408 133 -763 -378 -22 -274 945 409 485 -702 778 -338 19 307 470 530 -127 -309 -381 -120 -751 -30 325 -317 293 -301 -4 638 247 331 -694 939 776 581 534 637 313 -957 488 -462 755 -95 -104 -564 413 825 -735 212 -911 -864 -413 807 721 783 -306 -295 -936 -974 -561 571 -873 955 212 796 509 -960 33 444 -743 -1 448 859 207 -679
41 -215 765 -448 -895 753 165 831 947 -959 -299 921 577 -466 -125 -763 -589 -533 -907 667 830 -335 -23 -710 857 -143 309 -517 -100 672 757 342 421 -524 771 -127 -799 -239 -53 -214 191 711 870 120 412 -231 -590 197 43 932 284 -310 -930 -76 -472 -149 255 664 813 553 -519 -135 -157 401 -315 482 -6 767 -275 -873 -937 -850 -666 -864 -17 -471 -667 74 987 913 527 476 836 464 151 415 -378 -54 -852 877 865 581 -175 83 -821 -336 281 -387 -17 850 727 -134 414 73 903 813 -71 -862 220 -653 -259 -843 -566 -265 -138 774 141 539 -916 388 -613 984 -697 -612 846 817 -612 -394 -267 191
-917 -449 592 -356 497 686 532 922 70 655 -242 738 522 226 -312 414 -560 -181 -795 -607 -738 172 -619 -778 -90 43 -648 961 410 -224 -890 -678 -23 -615 -638 19 -783 -881 -929 -247 18 965 -447 -560 -578 43 -807 249 -453 681 -72 -361 -261 -869 809 -140 -74 -725 53 -205 709 883 -753 -564 -838 535 587 -810 684 347 659 -842 134 643 -405 692 571 -856 -652 498 -93 988 -464 -53 806 -205 -565 484 -810 121 -425 424 -873 627 -295 -624 -161 -529 65 -209 557 31 323 384 499 239 -898 518 -240 -674 319 720 -869 520 811 -156 462 366 -691 -768 -346 30 -498 -83 -630 544 -678 -194 936 987
941 -221 263 -477 -646 195 707 318 297 306 846 -571 306 237 63 658 389 221 536 305 906 -238 512 -904 416 539 -494 -682 -162 -611 472 967 -878 -269 -446 -740 905 723 -515 -49 188 953 680 303 -991 -699 306 417 -432 435 -300 -662 -336 -859 -172 -582 913 -13 -147 596 46 -563 -417 -455 -108 178 863 25 209 -337 -3 531 -168 -265 -834 -534 230 -154 654 -571 45 134 -128 -577 -377 -479 -82 510 -131 35 -836 130 -562 -910 458 650 95 704 995 -749 489 -514 525 79 -554 479 192 965 -491 -899 407 39 -319 869 -6 592 392 960 677 697 -776 106 -458 -785 -635 -832 995 262 201 202
-538 -76 949 -637 502 -137 209 -965 138 734 -236 992 -467 -970 -318 -393 622 -437 53 697 719 849 -378 68 908 781 -311 821 761 -965 695 -713 47 -721 -585 527 677 516 -66 -50 -366 -42 271 995 184 400 -980 103 -576 -669 -897 -725 -119 -46 -77 356 -220 1 114 -296 232 -735 -813 585 733 -287 44 73 -469 -640 263 -149 -113 -316 -851 -507 -968 -657 552 -539 303 21 -641 268 533 27 544 164 -14 579 -237 828 905 357 -375 -68 484 578 -937 447 -380 385 77 48 660 889 579 137 816 348 166 877 459 16 727 383 -234 -589 -520 158 281 -572 -536 -88 -74 -868 328 -712 -598 -704
-632 93 -498 815 -473 429 271 -361 48 694 818 -222 -797 -62 -51 -399 668 -763 282 -921 -415 -880 -504 -821 -567 725 -785 -873 -401 -598 -378 -184 946 103 -359 527 487 793 347 -1000 157 581 -710 -704 785 199 274 -791 253 -214 -756 -492 197 -756 886 -93 -389 552 411 -298 1 782 -480 622 -787 -87 409 507 467 -393 -184 569 -279 -127 703 714 937 503 339 484 -619 937 640 223 -68 291 882 -652 -837 31 137 -523 972 639 -380 -753 -135 -615 -278 207 -928 546 -614 11 536 -544 564 709 285 -128 -312 -930 -195 -178 -905 -190 418 352 546 -792 971 -994 -681 891 491 966 -560 37 701 -520
928 468 485 861 177 -692 -877 453 -382 993 -18 -24 275 -432 136 -54 861 -113 -468 768 -948 723 443 470 -654 -171 -73 -838 -899 -581 -492 480 -176 -582 -441 -115 942 -945 -346 -901 -276 -432 167 -420 451 -57 977 583 -13 74 926 218 -341 -919 442 822 101 -147 -467 498 517 176 -795 10 728 244 258 -500 -572 -962 300 -482 -810 271 -894 -580 -180 785 -18 -614 -189 -907 -132 688 -5 114 784 -630 -731 -255 187 -427 -929 846 -353 -135 -989 -818 -259 -816 462 426 63 456 -756 983 -652 63 777 -554 563 260 348 817 304 -285 -171 -330 715 987 701 883 930 828 890 -930 356 691 748 -773
-910 784 -52 -380 -975 -55 -277 -106 -503 963 -385 108 -169 493 323 38 -798 57 -14 -379 -744 -593 959 -459 652 120 569 -35 348 -441 815 994 196 -547 916 518 -495 -262 -238 -13 -19 584 859 164 -890 -610 -476 206 -347 680 390 985 695 -758 408 -427 -133 185 952 532 -1 680 -124 437 748 -750 -696 -410 678 -925 89 863 -832 -972 -836 -43 -371 416 -605 750 -428 -316 686 -714 877 -133 285 283 -84 -740 -159 176 -942 440 615 -666 -42 461 961 345 -589 -720 873 573 397 73 -859 333 724 933 548 -59 -742 806 -127 -843 -330 -413 -151 941 -973 -250 814 963 -4 729 521 196 251 982
-127 67 -899 332 827 976 779 -594 43 -430 -397 -613 -654 -915 491 -715 15 987 327 -610 975 513 -615 82 -558 -135 912 112 341 -809 -392 213 -65 897 897 -712 347 -7 889 -724 -85 -976 -897 919 770 292 27 -71 -681 -398 -687 445 222 302 -248 -412 -362 -842 -86 284 788 -706 -543 497 -95 94 544 -622 318 -25 -681 -202 804 325 -10 -607 87 -553 231 -677 -702 17 730 700 -833 -157 -243 -482 914 -750 -641 -645 -79 -438 -633 -83 422 937 -754 279 808 345 183 562 -534 940 450 884 -391 391 572 644 -919 -797 -324 265 -73 -47 162 830 697 581 369 824 576 690 825 -14 -674 819
-873 -564 484 -650 -623 692 420 -393 603 972 -283 270 49 -634 -631 509 -474 890 -625 -87 -235 706 6 -573 987 810 -524 335 -829 960 -916 -960 -839 -763 731 -578 605 568 -409 -517 -997 -404 -366 156 146 -395 -744 -293 -696 414 -604 -82 575 526 -400 -24 -639 -338 742 -62 -179 -961 -920 -646 298 -15 6 -577 105 840 173 968 700 -127 -63 604 -464 -321 -450 746 33 96 -167 759 -997 541 510 532 47 491 274 -579 203 462 581 381 -465 605 -803 499 100 -718 36 -893 737 -18 59 975 25 -160 -692 -851 613 -207 603 736 -438 -697 -860 -340 -505 419 237 205 614 -431 -804 -437 -39 -529
-233 353 -428 210 -814 -538 -143 488 306 -891 -466 760 595 -738 -765 -764 -831 -643 589 653 -932 -259 190 -264 172 590 -701 749 -804 222 493 -281 -896 -381 719 -774 -545 -340 294 225 -90 588 -376 567 -867 348 982 -949 303 -771 -624 858 -571 174 -648 266 30 180 -857 -693 220 -949 -306 -150 132 -332 -285 -569 228 877 234 -900 125 323 110 88 -162 -962 354 -82 -667 647 474 -542 -924 -968 206 771 905 -83 -758 -493 -958 -349 -997 341 -399 -672 -868 156 570 -231 854 -905 -801 573 694 -235 -492 515 125 -141 501 878 -697 303 556 484 -110 841 12 743 909 -259 -391 -298 772 -771 0 445
-562 -909 -640 -153 -276 261 -758 -754 534 -189 566 -617 292 -385 -168 -549 -466 926 -474 516 581 -301 -687 38 -216 -638 935 -417 9 600 -886 378 913 233 565 71 -240 158 -952 190 718 142 679 610 602 -933 -470 535 773 -307 250 -974 528 -793 -355 -103 -682 -627 -427 608 -825 -425 710 -307 -268 -752 -339 721 218 -996 -103 -390 33 -349 588 -472 928 -353 -815 981 -193 43 -185 -395 -956 584 500 754 -575 778 -593 974 557 576 -730 508 44 793 716 -936 -451 36 478 460 -554 49 -919 -81 779 -275 -18 46 972 -208 529 653 417 268 -55 -916 -105 -407 -843 -702 -713 -18 565 -75 457 569
577 127 224 -252 421 -829 255 -803 352 790 33 -494 270 823 -512 -785 570 513 271 -80 811 279 464 9 -211 -896 -378 631 -340 -35 -137 -833 9 144 454 -984 943 955 -506 827 432 -448 -108 -793 578 -503 348 -403 -810 300 -179 431 496 74 -13 -788 774 -814 4 183 474 536 -425 622 750 971 -652 422 -748 399 305 555 -325 -562 -167 -238 -979 210 -433 -781 211 503 -987 633 579 407 88 599 542 -599 -467 -936 -220 -426 -93 -602 759 -730 680 483 67 -151 -225 11 704 613 440 -262 -402 261 394 -906 492 84 142 711 383 -756 -240 24 -760 675 366 -394 -414 -451 -836 93 855 340
991 621 860 -442 671 -454 309 734 750 -603 764 -697 310 -300 709 213 -282 697 998 -160 235 -969 382 -873 -903 410 -279 779 -221 81 187 325 530 -273 742 514 -611 -662 485 -985 -284 677 902 -796 603 -151 620 912 334 -854 -790 980 -382 -232 -824 -980 372 925 454 230 71 -375 920 -262 339 38 -796 -747 -600 -998 -335 -126 69 154 -703 318 857 -576 -100 591 293 747 345 -833 693 -965 924 -655 -1 -48 -326 10 336 305 943 899 -203 -967 -284 -809 -405 230 629 -49 48 791 -939 683 -269 -879 -759 -30 -574 476 -146 167 184 -286 381 587 689 232 -767 -764 -27 708 -121 -50 225 147
-219 -240 -147 -807 67 965 -112 -741 365 -994 666 -225 634 88 409 994 424 -545 346 520 -184 -646 918 -288 392 -464 377 328 -235 43 -238 788 -357 -429 -115 112 -561 -977 941 -983 450 -234 621 -351 -255 653 -718 24 725 -535 79 -413 -668 143 770 17 716 -406 909 214 -295 -540 988 774 146 -248 -941 -448 551 946 -690 -564 -8 -373 -188 53 -619 -159 -738 908 895 -178 -870 -216 -669 499 897 898 -617 631 814 695 771 -826 -55 -657 646 228 539 -277 318 416 501 820 133 419 552 -740 848 -98 -342 297 109 381 -582 -235 626 -105 -643 -212 85 -655 -507 -837 -426 -192 862 15 -172 51
691 -503 -819 -604 -349 918 692 -858 -297 -566 -68 391 -954 217 507 -945 99 847 -822 5 -195 -894 -443 -139 -419 397 241 273 -894 -418 -558 706 -12 112 100 362 705 -200 965 -778 -677 -943 -23 633 458 -356 -136 -119 -549 129 670 -364 -197 252 779 104 -459 397 232 -230 647 -757 709 780 -184 286 547 111 488 -445 615 -970 -802 916 587 -825 -943 180 677 -9 -31 223 -142 823 -558 980 -843 -59 -660 -900 -913 156 70 -710 -945 793 -578 -816 -148 -204 695 -401 856 645 -545 -538 831 625 -90 848 520 -843 614 -867 -64 -109 654 -96 -342 163 715 918 301 288 -569 -637 156 -221 -973 -19
-448 914 225 273 -977 878 -583 -713 974 463 81 -86 -734 -447 -182 589 -377 -733 38 300 644 535 -985 -782 970 -839 -376 -108 -490 917 -561 278 -338 561 -995 348 419 -291 -1000 131 646 720 -219 -974 -587 72 -144 -853 911 723 -827 -812 836 -172 828 706 594 -696 -253 648 -963 761 -771 -999 292 775 -653 -868 83 -336 -832 -875 65 -365 83 -648 231 -956 992 63 -487 -276 -370 -245 157 -409 -799 -710 -501 -933 -769 31 730 -756 -216 -828 -50 305 712 462 -795 26 -563 -387 -495 18 -444 -880 286 -825 -435 -571 -898 -558 247 -289 249 -143 -88 684 79 447 499 486 318 991 -870 -706 936 -495
-385 621 747 149 29 -599 -259 545 673 -440 556 -443 348 -130 -942 -471 -56 -792 -432 -69 444 -168 -780 114 936 534 -503 -94 -355 314 -621 -846 642 540 -375 800 973 -718 292 339 717 563 692 689 -964 -278 141 476 541 -145 -781 -398 -138 -928 39 504 -373 -739 505 226 594 438 -934 -105 -835 -29 -138 739 -21 -360 988 702 185 317 471 -864 864 586 194 999 229 -562 457 -387 772 -706 868 820 -400 -277 325 222 -140 -382 -739 146 440 809 -996 -284 489 -53 -876 639 -716 873 963 699 450 -457 -171 -627 775 -613 -947 583 758 26 118 489 -65 -195 134 -133 -978 837 791 690 -179 -4
515 408 736 877 891 -772 -570 636 517 175 547 -642 430 373 -348 -172 887 -417 -906 -874 347 798 -118 -276 -825 -128 -38 -573 -614 305 -231 -439 -747 -971 765 419 300 -444 -990 1000 493 441 -868 -845 126 123 258 322 454 -165 10 -646 723 24 -417 -301 338 -72 78 661 463 866 303 -90 -311 -51 923 -410 887 -511 -669 -221 0 555 -862 -685 -482 -82 -594 -361 271 557 -66 -852 594 -236 780 -36 763 356 -294 639 211 -369 811 -934 -255 -867 584 -541 -183 30 -752 977 536 382 -873 -502 -991 -655 -603 986 333 28 41 -319 -97 -265 898 199 -563 -519 613 -408 -633 244 -796 -988 562 88
730 -627 167 -12 152 820 -44 174 331 -355 -278 820 819 -94 24 627 103 99 589 -57 -824 624 -49 684 159 -550 -132 -870 -125 241 -760 -36 559 -151 681 102 240 -615 -903 113 294 -469 -748 -33 -499 -886 -889 792 -317 800 754 868 933 698 818 -451 28 725 -975 -828 -22 -714 322 -764 -961 -663 971 694 425 192 84 -424 403 -874 -406 -589 -310 152 470 -632 -490 -486 -858 -628 845 -311 -977 91 717 185 -783 957 -720 -673 -217 -37 -379 292 241 -841 288 -32 -73 63 -24 809 -605 -991 -609 -44 -596 -451 64 -536 248 -339 401 325 979 735 960 -249 618 14 -825 -806 -641 -800 -914 984
-657 -142 278 997 -386 -160 186 -683 -661 400 -582 -347 -974 -780 -461 879 449 -920 811 -781 -81 161 -989 -796 197 458 -551 744 -84 334 956 -270 233 157 16 -704 311 687 985 -437 -111 248 -800 848 -935 849 570 303 633 -201 -607 -364 -787 752 319 -890 -399 640 947 433 -289 214 -780 -434 420 -944 -407 56 -475 15 -808 -26 -98 -50 786 258 -426 855 367 334 303 344 -416 -66 -397 403 14 -603 -928 64 -641 511 843 397 -452 -653 22 -35 541 -206 750 -768 666 -769 833 802 -574 -715 -155 152 -410 -46 986 474 46 903 -669 -901 61 623 978 -279 871 871 -554 -946 -355 -196 411 -364
22 -46 -167 354 -763 -27 -593 620 422 -231 288 -158 -924 -466 -108 -291 952 -991 621 -941 -135 454 912 963 -896 966 -11 220 126 -58 -213 -413 -191 -291 215 834 -706 -210 726 -150 771 -243 -710 1000 873 -470 649 -160 -400 -354 -362 397 550 -57 846 -621 -883 -759 599 -137 -736 82 793 -273 118 854 59 62 92 -915 858 -67 -688 880 -930 -327 -50 156 -134 -971 -782 -544 -583 -738 -938 -686 -320 71 471 363 -857 263 -401 -725 -818 11 -586 -998 -734 34 -948 -425 476 691 -209 -188 177 -621 -563 954 632 -216 -590 459 829 763 -364 689 934 816 199 900 -577 286 -265 -528 339 -593 -456 362
52 -225 759 -891 -744 319 -75 125 -152 815 -352 417 966 -223 46 805 480 -530 -198 -939 732 -401 449 63 -793 269 24 -436 215 552 -24 -333 -131 -796 -406 -491 -355 -606 -144 -468 -312 -212 51 931 -589 -160 -926 -43 -965 305 -26 333 -270 834 -90 509 596 998 438 483 598 -604 737 775 -26 943 122 -956 803 -92 -192 -838 -728 828 941 811 929 -713 -115 756 -456 855 -259 -113 216 851 346 601 449 54 -880 735 -875 -8 -96 194 -291 963 983 -430 691 -185 -567 -650 -788 -841 -939 994 64 600 30 -346 705 -550 610 -521 566 -807 -132 101 -858 -972 -287 413 -826 -291 -152 343 -736 518
-43 247 -247 -326 43 34 901 -38 186 -95 149 -131 56 7 -989 -400 -285 -279 -370 793 -723 478 743 -208 111 436 79 939 166 797 13 -1 -490 914 -881 654 -370 877 562 640 -672 479 173 350 -449 -934 -646 -937 -937 -644 835 -832 -419 -212 290 114 -810 220 -615 -988 579 -555 728 898 887 156 373 738 565 982 -734 81 -315 392 852 -250 350 716 -475 -827 434 -937 822 -249 -239 386 -364 605 461 656 -374 -635 945 -553 227 -722 996 491 562 639 812 -470 979 438 243 892 470 -744 -621 -616 -183 -454 -1 -386 -864 -857 220 53 502 -599 -774 -797 478 -68 -630 -857 468 -216 -574 -385
-647 -140 615 -301 231 -475 -461 -736 585 -419 -876 -944 -438 495 -582 -562 765 415 681 67 -977 -417 -360 652 -138 421 -423 -449 84 417 393 618 -800 669 740 -896 195 75 391 653 663 -645 462 -42 610 316 545 -348 109 -34 -370 -532 863 167 801 -213 -790 -757 -333 302 426 234 -891 497 -148 -28 690 -183 -918 -297 493 605 -975 851 -547 -435 -148 502 -533 227 234 448 -31 -889 -778 -734 -978 -397 -850 562 -723 150 -217 -555 607 -949 885 -252 -577 579 339 320 -15 -71 143 -650 -757 427 375 -69 -23 757 -70 -739 -694 -64 588 -922 68 926 -932 -766 -652 84 -517 939 -963 -894 -257 -771
135 256 -813 261 814 -380 -911 261 -22 -385 -22 -582 -563 -604 612 147 -751 621 -160 -495 640 -239 -253 533 4 -226 522 -867 744 214 -666 191 918 -116 96 543 26 -860 -136 -984 844 478 543 -513 -872 510 961 -416 -916 -370 634 -793 973 482 134 232 -520 -925 278 2 91 222 641 -596 990 -54 124 488 407 -753 620 -490 959 -83 705 -131 -247 540 905 405 -157 -658 156 502 -51 838 -672 804 -367 79 805 742 639 288 -69 726 516 473 -444 -21 -992 419 855 303 -593 -246 294 248 883 -850 -830 378 -135 -753 299 935 -429 -554 -309 235 -756 301 -163 -266 960 -548 -463 381 -459 -592
-297 -363 241 268 110 483 -917 -511 719 -129 -440 -621 799 772 901 -66 108 -181 -894 -147 277 -556 74 -287 208 -713 -352 398 -750 953 112 500 681 588 270 829 -416 -880 459 809 663 644 695 -134 -694 779 -818 -911 -312 -971 790 470 -100 992 705 641 58 -92 579 344 409 252 81 -557 205 -200 -422 151 791 978 835 -241 187 -864 679 286 -844 -983 -999 -6 259 197 961 468 60 -748 -815 103 493 -182 -149 -855 368 -736 -938 345 -759 980 -430 -907 -288 939 -68 628 -611 -178 -4 968 5 235 973 -903 519 -243 -650 -730 -528 943 -527 -250 301 -794 724 -964 -175 -377 -172 -916 151 499
-174 316 724 803 -249 -322 -15 558 -245 -115 -450 -46 -685 -673 -62 -926 779 643 5 909 211 117 -337 960 156 823 616 -865 -489 -187 -747 -480 432 -629 -393 996 -274 158 21 850 695 67 496 900 809 944 -300 83 -891 -555 322 735 594 -218 624 936 -916 605 982 638 -774 -794 633 -83 -390 -397 -425 -444 92 102 731 -900 936 59 943 699 -406 -805 395 881 -946 208 267 -870 923 103 989 374 506 -806 -972 -955 498 818 414 -23 213 -564 -475 494 -353 -161 -614 -549 -106 -721 -48 745 -571 331 -677 709 765 -218 213 -620 -276 811 218 979 594 -490 -278 742 503 -903 -330 -658 697 -496
-151 -47 -969 303 281 -508 -655 608 537 550 -580 955 -839 505 -586 -290 -695 672 547 884 801 371 -172 -167 836 -8 -799 478 686 -893 -615 -738 -699 -784 79 -420 66 906 548 -36 -96 -540 -437 791 -288 -404 59 -826 -593 -511 984 -519 249 214 -881 367 89 -488 -660 104 -746 669 131 950 -486 -998 -860 -738 74 941 317 -56 681 -511 -885 -274 -940 697 -915 -646 318 -775 533 657 -76 503 -514 -288 -392 379 -76 -903 -780 -346 -300 274 806 -878 340 -889 650 385 -449 896 -826 -359 994 324 -995 -7 -584 -6 57 868 -175 643 752 727 524 -682 499 -559 936 546 128 208 278 476 57 968
-172 424 -726 159 -309 327 -505 576 -647 142 -210 -668 -213 141 -4 -976 974 -375 -382 -737 37 -634 900 -514 -729 221 -345 -248 -218 -870 -98 -39 178 941 -168 -827 635 507 173 -287 -620 454 -132 413 275 -834 958 -995 -858 152 594 -132 -192 -945 699 41 -314 827 -484 -268 390 -827 390 777 -881 -838 855 -639 -891 197 -971 268 541 -612 -592 627 -235 603 504 18 301 -572 824 300 790 888 218 -993 137 -893 820 -653 -50 946 -140 108 -926 -192 -242 -211 989 42 -114 156 977 -54 730 138 525 -49 776 -767 297 789 470 -40 478 -698 -563 -927 -185 908 -121 283 248 170 202 200 -785 733
30 -631 187 -55 -290 -123 290 905 210 -159 -646 -143 73 -546 -527 80 212 -137 755 541 829 -169 -817 514 -120 871 27 916 -148 853 879 -102 768 -163 -701 340 563 262 -425 -930 826 589 999 508 118 786 387 -230 599 304 973 617 231 -875 946 981 -559 -687 252 -688 581 592 -731 123 921 99 -683 407 109 -649 -479 964 -452 -955 998 -12 209 552 -119 49 224 -241 -45 -112 -969 -35 -466 304 623 -853 426 -567 335 909 -952 846 -18 238 -41 -636 -871 52 -585 -758 105 -964 -214 413 146 869 -997 -388 -276 373 538 85 828 -898 -640 -139 744 -315 926 -914 -142 250 124 71 -139 871
-455 788 -734 718 854 163 578 190 225 -983 -988 -933 -145 -761 -46 160 -917 872 661 -845 -532 823 -444 219 -104 -917 592 790 585 134 553 -945 793 347 -583 -301 -694 -507 -14 -343 90 82 106 -603 -396 255 394 -157 988 -154 -509 -38 747 -850 -17 -867 406 500 417 337 139 322 -175 -159 -3 111 -947 197 433 460 -653 -915 -765 327 -912 -289 -184 674 -448 330 -396 -364 -184 548 -223 42 396 -610 -334 246 293 -593 -610 -970 -968 491 -207 397 -23 -596 163 309 224 -978 305 676 -727 242 -88 -972 -187 -213 -862 -224 234 -240 497 709 -840 700 894 284 125 -440 526 334 -631 773 -633 -404
-622 571 -287 82 95 -424 -708 -428 -18 916 -23 -732 569 164 -574 820 554 740 -843 -783 -758 -727 585 44 742 974 556 69 -368 117 931 -917 -173 -424 -504 -183 364 282 -236 236 182 -593 -932 -234 -252 270 -412 -602 -909 461 -596 861 907 76 268 410 -781 352 -954 551 261 -819 -271 441 956 -294 -389 499 996 -807 935 -693 99 -463 417 -830 846 190 203 -438 -405 -802 -800 434 -611 -220 949 -147 -722 620 -569 503 513 -255 -651 285 -915 -493 -295 -110 963 -124 414 -236 64 -355 368 -146 573 -364 151 -411 515 -885 300 -25 -603 503 34 139 -908 112 883 -514 -593 664 896 522 316 780
390 -197 -779 -670 538 790 -780 604 690 548 563 971 -836 31 -497 -45 654 359 -840 606 -423 722 208 -367 -176 -55 -551 -806 -127 -339 890 -532 -509 38 -740 241 -186 14 -209 223 781 -690 24 677 -579 -58 -349 -631 -372 962 218 50 741 -203 -29 -508 351 -635 647 278 407 130 -676 829 844 519 993 -690 -380 229 420 -17 775 -499 -45 -342 707 -37 646 222 -22 -381 -177 -821 -895 392 -696 129 -629 95 774 -230 647 -960 -495 -83 -897 386 -176 -483 460 729 535 924 64 301 829 632 264 -481 287 773 995 -162 515 -915 -722 200 -707 -267 -401 350 -916 726 390 -646 -555 470 543 395
449 824 346 -955 701 10 132 271 132 467 800 600 -473 748 -46 -101 319 -524 -494 -805 -379 -642 -178 -989 957 546 -32 628 -988 191 871 -836 -6 504 -534 320 284 -931 390 -725 870 575 657 20 -439 -788 252 388 927 892 588 -489 117 778 878 -579 736 801 201 -558 -205 80 52 46 973 376 511 356 805 644 -151 540 713 -490 -235 -970 128 -512 -217 -120 -787 -685 750 285 820 317 637 -705 697 602 967 332 897 801 419 654 892 49 755 522 -120 641 -449 733 278 60 161 491 -281 -211 765 -908 166 157 524 535 -562 -202 674 -586 265 -98 -701 6 490 -435 704 168 993 -576
-782 -611 -383 -622 878 222 691 651 490 -591 340 842 -266 495 -271 975 -556 -158 -284 -246 888 653 -18 -847 -641 249 674 579 599 -68 471 874 -198 185 -691 678 -825 88 -691 -30 -40 -81 -87 383 -186 -212 508 211 -74 -57 539 277 539 -267 -239 916 -999 -197 -132 -750 -200 -892 -7 61 821 -88 -922 905 -262 -427 597 -348 512 -35 -145 -389 -797 423 418 -566 -504 240 228 -145 -801 953 508 -943 215 -473 -471 297 -57 576 350 812 224 -549 318 -390 624 112 290 -62 -987 294 -219 268 951 -765 -154 -965 142 8 313 554 -967 980 75 -998 -280 263 483 543 900 70 714 -472 38 -373
-564 859 208 -501 238 -603 258 -512 149 -616 -300 363 -399 -34 -539 930 -217 -189 -13 454 -235 795 -272 263 205 -443 -982 546 -277 703 -363 -972 744 918 117 -181 -928 -789 606 -579 306 521 -787 -921 673 478 650 -685 615 -11 -954 77 -7 179 -173 773 -197 243 584 -146 237 18 443 -363 422 275 583 935 773 -61 -515 143 -508 461 -542 -296 -832 -956 945 -621 -373 -460 266 713 68 -958 925 821 -421 -520 332 737 -911 -593 178 212 -110 -72 570 591 -759 -819 -795 -335 -503 -798 -610 43 415 -320 723 -508 867 831 -365 110 -34 -965 279 -57 210 816 724 -664 -456 112 -980 -768 200 290
63 -263 286 649 364 -126 -326 803 383 15 73 -415 296 -999 811 -761 -335 654 157 -105 -570 943 -630 -203 917 749 -540 -289 -401 -92 659 -873 -825 -158 718 -983 249 328 -95 857 -64 308 -271 909 873 272 -124 -248 513 -937 -236 -314 49 -143 -169 964 209 -750 -431 -401 -118 -791 -152 682 -783 931 793 318 -828 584 -214 -989 972 160 -932 620 -152 963 994 727 288 -70 -962 518 153 470 809 290 611 -668 -156 796 -150 -603 604 -667 79 -278 584 -786 980 99 343 -27 31 -731 813 799 682 -508 -294 924 -165 -213 -86 -956 58 470 664 162 -649 688 665 652 -605 560 950 -911 -97 499
-943 868 291 694 258 -621 -882 -467 432 901 427 118 481 -901 484 242 -164 -197 -917 -478 786 54 -287 -888 230 -603 120 77 449 714 -20 585 704 457 435 -208 382 590 201 401 108 -616 -995 417 -802 -570 -681 290 -399 794 764 928 -589 -341 -633 600 -249 146 -564 442 891 -209 -383 -220 -588 527 -88 158 -108 -486 -342 344 64 956 -882 975 532 -532 -130 975 614 -650 816 -744 -347 -811 -220 445 -849 578 -818 188 342 -483 -527 -503 -367 -313 373 837 -469 852 -318 -309 64 -667 686 562 -422 907 868 234 -224 -830 266 246 540 -120 971 -703 228 203 542 -109 591 -44 246 -773 403 705
481 274 675 880 0 -384 -56 -894 809 997 661 239 184 689 -86 -584 686 740 -626 -792 -532 384 522 924 554 370 -121 342 708 491 688 990 357 890 -509 729 612 -332 -891 999 570 -879 -793 -325 147 -383 381 336 236 -662 191 -707 378 674 -903 407 -232 107 -510 -480 760 -841 871 928 -723 -98 -972 767 -151 -713 849 -29 -516 867 -288 388 -384 487 -538 317 -303 72 -694 226 754 866 523 -736 150 -625 488 -135 -568 205 588 -81 -801 587 809 215 -327 -591 -538 -141 -565 643 -868 978 488 -834 741 92 402 -36 414 443 -848 -483 -129 -24 -816 -383 -312 439 -699 -101 38 434 -308 -512
-519 -810 411 -211 -29 232 330 941 667 583 899 -715 963 -603 -581 -444 611 -556 -733 -631 -449 -558 -373 252 238 782 198 987 667 5 482 250 30 -714 896 871 -292 507 -437 321 -703 670 -596 527 334 -430 483 959 -414 -886 -503 273 -260 -86 486 889 42 726 -207 767 320 -262 643 -19 625 -909 -707 -776 433 483 948 -775 -220 856 -525 -761 -30 -310 696 497 -999 53 -690 -578 791 -781 958 239 -97 346 -644 852 794 787 -829 -491 -486 -229 -941 38 -400 -368 521 -701 166 -685 348 264 -949 -967 -767 556 -239 -786 -755 334 325 79 -670 -530 894 -61 58 -510 -932 -664 50 398 -324 -66
775 331 -901 -614 594 40 693 31 -299 -550 -236 -589 -80 367 -298 317 -305 -775 -121 -442 -407 -105 -399 481 -928 968 -373 544 256 786 -919 262 -765 -927 -791 -721 669 881 -423 408 -712 -635 -918 399 -925 -199 -501 164 323 991 -806 5 -669 769 41 -981 880 653 693 730 219 320 -746 -798 179 -517 548 -732 197 698 124 -660 401 -65 -813 -668 37 -122 -785 -166 -677 -180 -626 -639 -562 106 -646 -17 -159 -518 -99 693 -184 991 526 -332 837 -612 726 684 -904 488 212 -855 -825 -224 -729 865 722 646 -889 -982 326 -713 -130 -642 349 -545 247 -548 828 627 764 -685 908 -942 -111 860 -859 -747
-152 531 878 -311 -354 912 839 -498 -128 -866 -326 -997 -544 667 414 620 112 961 -532 556 498 940 -110 180 -831 -511 -634 379 720 89 -358 -87 132 -533 -195 430 -655 610 -687 481 -529 -144 -961 162 -765 382 -869 -662 -33 -562 -768 -385 615 82 -52 -114 -126 -454 889 -8 879 520 800 58 -198 -765 -758 -927 359 -818 -87 -205 280 6 768 -577 961 79 739 -620 -83 440 778 -433 -842 -291 -475 997 372 548 -794 843 -696 -214 534 947 -363 -413 -423 -462 -298 -436 -171 909 145 -576 956 964 415 391 -531 -865 50 653 -346 659 936 -296 -680 42 921 -190 -389 -797 -406 299 593 -992 695 561

2
testdata/performance/01_mm3.out vendored Normal file
View File

@ -0,0 +1,2 @@
-160953527
0

89
testdata/performance/01_mm3.sy vendored Normal file
View File

@ -0,0 +1,89 @@
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;
}

2
testdata/performance/03_sort1.in vendored Normal file

File diff suppressed because one or more lines are too long

2
testdata/performance/03_sort1.out vendored Normal file
View File

@ -0,0 +1,2 @@
1576633458
0

106
testdata/performance/03_sort1.sy vendored Normal file
View File

@ -0,0 +1,106 @@
const int base = 16;
int getMaxNum(int n, int arr[]){
int ret = 0;
int i = 0;
while (i < n){
if (arr[i] > ret) ret = arr[i];
i = i + 1;
}
return ret;
}
int getNumPos(int num, int pos){
int tmp = 1;
int i = 0;
while (i < pos){
num = num / base;
i = i + 1;
}
return num % base;
}
void radixSort(int bitround, int a[], int l, int r){
int head[base] = {};
int tail[base] = {};
int cnt[base] = {};
if (bitround == -1 || l + 1 >= r) return;
{
int i = l;
while (i < r){
cnt[getNumPos(a[i], bitround)]
= cnt[getNumPos(a[i], bitround)] + 1;
i = i + 1;
}
head[0] = l;
tail[0] = l + cnt[0];
i = 1;
while (i < base){
head[i] = tail[i - 1];
tail[i] = head[i] + cnt[i];
i = i + 1;
}
i = 0;
while (i < base){
while (head[i] < tail[i]){
int v = a[head[i]];
while (getNumPos(v, bitround) != i){
int t = v;
v = a[head[getNumPos(t, bitround)]];
a[head[getNumPos(t, bitround)]] = t;
head[getNumPos(t, bitround)] = head[getNumPos(t, bitround)] + 1;
}
a[head[i]] = v;
head[i] = head[i] + 1;
}
i = i + 1;
}
}
{
int i = l;
head[0] = l;
tail[0] = l + cnt[0];
i = 0;
while (i < base){
if (i > 0){
head[i] = tail[i - 1];
tail[i] = head[i] + cnt[i];
}
radixSort(bitround - 1, a, head[i], tail[i]);
i = i + 1;
}
}
return;
}
int a[30000010];
int ans;
int main(){
int n = getarray(a);
starttime();
radixSort(8, a, 0, n);
int i = 0;
while (i < n){
ans = ans + i * (a[i] % (2 + i));
i = i + 1;
}
if (ans < 0)
ans = -ans;
stoptime();
putint(ans);
putch(10);
return 0;
}

2
testdata/performance/03_sort2.in vendored Normal file

File diff suppressed because one or more lines are too long

2
testdata/performance/03_sort2.out vendored Normal file
View File

@ -0,0 +1,2 @@
609797596
0

106
testdata/performance/03_sort2.sy vendored Normal file
View File

@ -0,0 +1,106 @@
const int base = 16;
int getMaxNum(int n, int arr[]){
int ret = 0;
int i = 0;
while (i < n){
if (arr[i] > ret) ret = arr[i];
i = i + 1;
}
return ret;
}
int getNumPos(int num, int pos){
int tmp = 1;
int i = 0;
while (i < pos){
num = num / base;
i = i + 1;
}
return num % base;
}
void radixSort(int bitround, int a[], int l, int r){
int head[base] = {};
int tail[base] = {};
int cnt[base] = {};
if (bitround == -1 || l + 1 >= r) return;
{
int i = l;
while (i < r){
cnt[getNumPos(a[i], bitround)]
= cnt[getNumPos(a[i], bitround)] + 1;
i = i + 1;
}
head[0] = l;
tail[0] = l + cnt[0];
i = 1;
while (i < base){
head[i] = tail[i - 1];
tail[i] = head[i] + cnt[i];
i = i + 1;
}
i = 0;
while (i < base){
while (head[i] < tail[i]){
int v = a[head[i]];
while (getNumPos(v, bitround) != i){
int t = v;
v = a[head[getNumPos(t, bitround)]];
a[head[getNumPos(t, bitround)]] = t;
head[getNumPos(t, bitround)] = head[getNumPos(t, bitround)] + 1;
}
a[head[i]] = v;
head[i] = head[i] + 1;
}
i = i + 1;
}
}
{
int i = l;
head[0] = l;
tail[0] = l + cnt[0];
i = 0;
while (i < base){
if (i > 0){
head[i] = tail[i - 1];
tail[i] = head[i] + cnt[i];
}
radixSort(bitround - 1, a, head[i], tail[i]);
i = i + 1;
}
}
return;
}
int a[30000010];
int ans;
int main(){
int n = getarray(a);
starttime();
radixSort(8, a, 0, n);
int i = 0;
while (i < n){
ans = ans + i * (a[i] % (2 + i));
i = i + 1;
}
if (ans < 0)
ans = -ans;
stoptime();
putint(ans);
putch(10);
return 0;
}

2
testdata/performance/03_sort3.in vendored Normal file

File diff suppressed because one or more lines are too long

2
testdata/performance/03_sort3.out vendored Normal file
View File

@ -0,0 +1,2 @@
925010131
0

106
testdata/performance/03_sort3.sy vendored Normal file
View File

@ -0,0 +1,106 @@
const int base = 16;
int getMaxNum(int n, int arr[]){
int ret = 0;
int i = 0;
while (i < n){
if (arr[i] > ret) ret = arr[i];
i = i + 1;
}
return ret;
}
int getNumPos(int num, int pos){
int tmp = 1;
int i = 0;
while (i < pos){
num = num / base;
i = i + 1;
}
return num % base;
}
void radixSort(int bitround, int a[], int l, int r){
int head[base] = {};
int tail[base] = {};
int cnt[base] = {};
if (bitround == -1 || l + 1 >= r) return;
{
int i = l;
while (i < r){
cnt[getNumPos(a[i], bitround)]
= cnt[getNumPos(a[i], bitround)] + 1;
i = i + 1;
}
head[0] = l;
tail[0] = l + cnt[0];
i = 1;
while (i < base){
head[i] = tail[i - 1];
tail[i] = head[i] + cnt[i];
i = i + 1;
}
i = 0;
while (i < base){
while (head[i] < tail[i]){
int v = a[head[i]];
while (getNumPos(v, bitround) != i){
int t = v;
v = a[head[getNumPos(t, bitround)]];
a[head[getNumPos(t, bitround)]] = t;
head[getNumPos(t, bitround)] = head[getNumPos(t, bitround)] + 1;
}
a[head[i]] = v;
head[i] = head[i] + 1;
}
i = i + 1;
}
}
{
int i = l;
head[0] = l;
tail[0] = l + cnt[0];
i = 0;
while (i < base){
if (i > 0){
head[i] = tail[i - 1];
tail[i] = head[i] + cnt[i];
}
radixSort(bitround - 1, a, head[i], tail[i]);
i = i + 1;
}
}
return;
}
int a[30000010];
int ans;
int main(){
int n = getarray(a);
starttime();
radixSort(8, a, 0, n);
int i = 0;
while (i < n){
ans = ans + i * (a[i] % (2 + i));
i = i + 1;
}
if (ans < 0)
ans = -ans;
stoptime();
putint(ans);
putch(10);
return 0;
}

4
testdata/performance/04_spmv1.in vendored Normal file

File diff suppressed because one or more lines are too long

2
testdata/performance/04_spmv1.out vendored Normal file

File diff suppressed because one or more lines are too long

50
testdata/performance/04_spmv1.sy vendored Normal file
View File

@ -0,0 +1,50 @@
void spmv(int n,int xptr[], int yidx[], int vals[], int b[], int x[]){
int i, j, k;
i = 0;
while (i < n){
x[i] = 0;
i = i + 1;
}
i = 0;
while (i < n){
j = xptr[i];
while (j < xptr[i + 1]){
x[yidx[j]] = x[yidx[j]] + vals[j];
j = j + 1;
}
j = xptr[i];
while (j < xptr[i + 1]){
x[yidx[j]] = x[yidx[j]] + vals[j] * (b[i] - 1);
j = j + 1;
}
i = i + 1;
}
}
const int N = 100010;
const int M = 3000000;
int x[N], y[M], v[M];
int a[N], b[N], c[N];
int main(){
int n = getarray(x) - 1;
int m = getarray(y);
getarray(v);
getarray(a);
starttime();
int i = 0;
while (i < 5){
spmv(n, x, y, v, a, b);
spmv(n, x, y, v, b, a);
i=i+1;
}
stoptime();
putarray(n, b);
return 0;
}

8
testdata/performance/04_spmv2.in vendored Normal file

File diff suppressed because one or more lines are too long

2
testdata/performance/04_spmv2.out vendored Normal file

File diff suppressed because one or more lines are too long

50
testdata/performance/04_spmv2.sy vendored Normal file
View File

@ -0,0 +1,50 @@
void spmv(int n,int xptr[], int yidx[], int vals[], int b[], int x[]){
int i, j, k;
i = 0;
while (i < n){
x[i] = 0;
i = i + 1;
}
i = 0;
while (i < n){
j = xptr[i];
while (j < xptr[i + 1]){
x[yidx[j]] = x[yidx[j]] + vals[j];
j = j + 1;
}
j = xptr[i];
while (j < xptr[i + 1]){
x[yidx[j]] = x[yidx[j]] + vals[j] * (b[i] - 1);
j = j + 1;
}
i = i + 1;
}
}
const int N = 100010;
const int M = 3000000;
int x[N], y[M], v[M];
int a[N], b[N], c[N];
int main(){
int n = getarray(x) - 1;
int m = getarray(y);
getarray(v);
getarray(a);
starttime();
int i = 0;
while (i < 100){
spmv(n, x, y, v, a, b);
spmv(n, x, y, v, b, a);
i=i+1;
}
stoptime();
putarray(n, b);
return 0;
}

2006
testdata/performance/04_spmv3.in vendored Normal file

File diff suppressed because one or more lines are too long

2
testdata/performance/04_spmv3.out vendored Normal file

File diff suppressed because one or more lines are too long

50
testdata/performance/04_spmv3.sy vendored Normal file
View File

@ -0,0 +1,50 @@
void spmv(int n,int xptr[], int yidx[], int vals[], int b[], int x[]){
int i, j, k;
i = 0;
while (i < n){
x[i] = 0;
i = i + 1;
}
i = 0;
while (i < n){
j = xptr[i];
while (j < xptr[i + 1]){
x[yidx[j]] = x[yidx[j]] + vals[j];
j = j + 1;
}
j = xptr[i];
while (j < xptr[i + 1]){
x[yidx[j]] = x[yidx[j]] + vals[j] * (b[i] - 1);
j = j + 1;
}
i = i + 1;
}
}
const int N = 100010;
const int M = 3000000;
int x[N], y[M], v[M];
int a[N], b[N], c[N];
int main(){
int n = getarray(x) - 1;
int m = getarray(y);
getarray(v);
getarray(a);
starttime();
int i = 0;
while (i < 10){
spmv(n, x, y, v, a, b);
spmv(n, x, y, v, b, a);
i=i+1;
}
stoptime();
putarray(n, b);
return 0;
}

1
testdata/performance/crypto-1.in vendored Normal file
View File

@ -0,0 +1 @@
19932 100

2
testdata/performance/crypto-1.out vendored Normal file
View File

@ -0,0 +1,2 @@
5: 1718388159 -1362524295 -445514711 1302474172 439146552
0

188
testdata/performance/crypto-1.sy vendored Normal file
View File

@ -0,0 +1,188 @@
int state = 19260817;
int get_random() {
state = state + (state * 8192);
state = state + (state / 131072);
state = state + (state * 32);
return state;
}
int rotl1(int x) {
return x * 2 + x % 2;
}
int rotl5(int x) {
return x * 32 + x % 32;
}
int rotl30(int x) {
return x * 1073741824 + x % 1073741824;
}
int _and(int a, int b) {
// int c = 0;
// int x = 0;
// while (x <= 32) {
// c = c + c;
// if (a < 0) {
// if (b < 0) {
// c = c + 1;
// }
// }
// a = a + a;
// b = b + b;
// x = x + 1;
// }
// return c;
return a + b;
}
int _not(int x) {
return -1 - x;
}
int _xor(int a, int b) {
return a - _and(a, b) + b - _and(a, b);
}
int _or(int a, int b) {
return _xor(_xor(a, b), _and(a, b));
}
// performs a SHA-1 hash to output.
//
// input is a list of ints, but only the lower 8 bits are used. Input must be
// larger than the smallest 64 multiple.
void pseudo_sha1(int input[], int input_len, int output[]) {
int h0 = 1732584193;
int h1 = -271733879;
int h2 = -1732584194;
int h3 = 271733878;
int h4 = -1009589776;
int a;
int b;
int c;
int d;
int e;
int f;
int k;
// preprocessing
int orig_len = input_len;
input[input_len] = 0x80;
input_len = input_len + 1;
while (input_len % 64 != 60) {
input[input_len] = 0;
input_len = input_len + 1;
}
input[input_len] = orig_len / 16777216 % 256;
input[input_len + 1] = orig_len / 65536 % 256;
input[input_len + 2] = orig_len / 256 % 256;
input[input_len + 3] = orig_len % 256;
input_len = input_len + 4;
int chunk_start = 0;
int words[80] = {0};
while (chunk_start < input_len) {
a = h0;
b = h1;
c = h2;
d = h3;
e = h4;
// populate words
int i = 0;
while (i < 16) {
words[i] = input[chunk_start + i * 4] * 16777216 +
input[chunk_start + i * 4 + 1] * 65536 +
input[chunk_start + i * 4 + 2] * 256 +
input[chunk_start + i * 4 + 3] * 1;
i = i + 1;
}
while (i < 80) {
words[i] =
rotl1(_xor(_xor(_xor(words[i - 3], words[i - 8]), words[i - 14]),
words[i - 16]));
i = i + 1;
}
// main loop
i = 0;
while (i < 80) {
if (i < 20) {
f = _or(_and(b, c), _and(_not(b), d));
k = 1518500249;
} else if (i < 40) {
f = _xor(_xor(b, c), d);
k = 1859775361;
} else if (i < 60) {
f = _or(_or(_and(b, c), _and(b, d)), _and(c, d));
k = -1894007588;
} else if (i < 80) {
f = _xor(_xor(b, c), d);
k = -899497722;
}
int t = rotl5(a) + f + e + k + words[i];
e = d;
d = c;
c = rotl30(b);
b = a;
a = t;
i = i + 1;
}
h0 = h0 + a;
h1 = h1 + b;
h2 = h2 + c;
h3 = h3 + d;
h4 = h4 + e;
chunk_start = chunk_start + 64;
}
output[0] = h0;
output[1] = h1;
output[2] = h2;
output[3] = h3;
output[4] = h4;
}
int buffer[32768] = {0};
int main() {
int rounds = 12;
int i = 0;
int output[5] = {0, 0, 0, 0, 0};
int output_buf[5];
state = getint();
rounds = getint();
starttime();
output_buf[0] = 0;
output_buf[1] = 0;
output_buf[2] = 0;
output_buf[3] = 0;
output_buf[4] = 0;
while (rounds > 0) {
int len = 32000;
int i = 0;
while (i < len) {
buffer[i] = get_random() % 256;
i = i + 1;
}
pseudo_sha1(buffer, len, output);
i = 0;
while (i < 5) {
output_buf[i] = _xor(output_buf[i], output[i]);
i = i + 1;
}
rounds = rounds - 1;
}
stoptime();
putarray(5, output_buf);
return 0;
}

1
testdata/performance/crypto-2.in vendored Normal file
View File

@ -0,0 +1 @@
9125 70

Some files were not shown because too many files have changed in this diff Show More