Compare commits

...

247 Commits

Author SHA1 Message Date
f317010d76 [midend-Loop-LICM][fix]检查load能否外提时其内存地址在循环中是否会被修改,需要判断函数调用对load内存地址的影响。 2025-08-17 17:42:19 +08:00
8ca64610eb [midend-GVN]重构GVN的值编号系统 2025-08-17 16:33:15 +08:00
969a78a088 [midend-GVN]segmentation fault是GVN引入的已修复,LICM仍然有错误 2025-08-17 14:37:27 +08:00
8763c0a11a [midend-LICM][fix]修改计算循环不变量依赖关系的排序错误,但是引入了很多Segmentation fault。 2025-08-17 01:35:03 +08:00
d83dc7a2e7 [midend-LICM][fix]修复循环不变量的识别逻辑 2025-08-17 01:19:44 +08:00
e32585fd25 [midend-GVN]修复GVN中部分逻辑问题,LICM有bug待修复 2025-08-17 00:14:47 +08:00
c4eb1c3980 [midend-GVN&SideEffect]修复GVN的部分问题和副作用分析的缺陷 2025-08-16 18:52:29 +08:00
d038884ffb [midend-GVN] commit头文件 2025-08-16 15:43:51 +08:00
467f2f6b24 [midend-GVN]初步构建GVN,能够优化部分CSE无法处理的子表达式但是有错误需要debug。 2025-08-16 15:38:41 +08:00
fa33bf5134 [midend-Loop-IVE]修复循环的死IV消除逻辑 2025-08-15 01:19:45 +08:00
a3435e7c26 [midend-Loop-IVE]循环归纳变量消除逻辑重构,修改运行顺序 2025-08-14 17:27:53 +08:00
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
fc7afdbb35 [midend]修复错误的RelExp类型转换 2025-07-31 13:55:59 +08:00
bfe2b248cd Merge branch 'backend-float' into backend 2025-07-31 12:16:11 +08:00
6d60522ce2 Merge branch 'midend' into backend-float 2025-07-31 12:14:38 +08:00
807fb3f560 [backend]微优化与可读性维护不影响原逻辑和分数 2025-07-31 11:23:17 +08:00
82288464c3 [midend]修复常量变量的声明逻辑同变量声明,重构表达式生成逻辑(将中缀表达式转换为后缀表达式判断类型提升后再进行统一类型转换和计算)。运行脚本通过率[117/140]。 2025-07-31 02:47:39 +08:00
7e8b90ffd4 [midend]修改全局变量,全局常量类,提供维度访问方法,消除维度信息(记录在Type中),createItoFInst命名修复,增加打印全局常量。 2025-07-31 02:45:40 +08:00
b3cf3cba29 [backend]修复了多参数传递的错误 2025-07-30 22:16:37 +08:00
03b62b138f [backend]修复了一个栈管理问题 2025-07-30 20:40:56 +08:00
8e94f89931 Merge branch 'midend' into backend 2025-07-30 18:27:42 +08:00
b388dc4542 Merge branch 'backend-float' into backend 2025-07-30 18:26:06 +08:00
48b0aec6c3 [midend][backend]修复了全局常量数组的访问错误 2025-07-30 18:23:56 +08:00
1fb5cd398d [backend]修复了多参数传递的问题 2025-07-30 17:58:39 +08:00
206a0af424 [midend-SCCP]暂存1 2025-07-30 16:33:56 +08:00
877a0f5dc2 [backend-float]修复部分问题 2025-07-30 16:00:02 +08:00
a3c4d5a2b8 [Optimize]对PreRA指令调度进行优化 2025-07-30 15:27:23 +08:00
39c13c46ec Merge branch 'midend' into backend-float 2025-07-30 15:10:38 +08:00
dd38bdc133 [backend]引入浮点数支持,但目前寄存器分配存在问题 2025-07-30 15:07:29 +08:00
38bee5d5ac [midend]IRPrinter增加了打印全局常量的功能 2025-07-30 14:46:28 +08:00
98511efd91 [midend]修改constdecl的逻辑区分局部常量和全局常量声明逻辑,提供方法访问全局变量,常量的维度信息,修改GlobalValue,ConstantVariable的继承父类(User->Value)维度信息保存在Type中。 2025-07-30 14:40:10 +08:00
507096a0f6 Merge branch 'midend' of gitee.com:lixuanwang/mysysy into midend 2025-07-30 11:31:46 +08:00
7f2e501cea [backend]修复了指令选择不支持ConstantVariable操作数的bug 2025-07-30 11:31:37 +08:00
860ebcd447 [Optimize]对PostRA指令调度进行容器/算法/缓存优化 2025-07-30 10:28:06 +08:00
31b6711d74 [midend]IR修改常量类getint和getfloat逻辑,如果类型和方法不一致那么应用强制转换返回转换后的值 2025-07-29 23:52:37 +08:00
42dce9820b Merge branch 'midend' into backend 2025-07-29 21:31:04 +08:00
09ae47924e [midend]重构了src目录 2025-07-29 21:30:30 +08:00
f5922d0178 [midend]修改类型转换判断的逻辑 2025-07-29 20:23:25 +08:00
63906d0648 [midend]修复82样例生成IR的错误(未正确初始化全局数组常量和数组常量的Type计算) 2025-07-29 19:35:39 +08:00
6ba05e0d8c [PreRA_Scheduler]添加寄存器分配前的指令调度优化 2025-07-29 17:00:27 +08:00
e4fd16e36a Merge branch 'backend' into midend 2025-07-29 16:37:11 +08:00
32bdc17dc3 [backend]调整了后端pass的顺序 2025-07-29 16:15:01 +08:00
8deb4ed076 [backend]添加了2个新的pass,用于解决大立即数加载问题 2025-07-29 15:48:37 +08:00
37e99e37a3 Merge branch 'midend-mem2reg' into midend 2025-07-29 15:48:34 +08:00
8e69992b29 [midend-mem2reg]增加说明 2025-07-29 15:47:51 +08:00
15fe69187a [midend-mem2reg]目前reg2mem仅将函数参数和phi指令及其对应指令进行reg2mem,旨在消除phi指令。 2025-07-29 15:30:28 +08:00
fff19ca1ea [midend-mem2reg]Reg2Mem建立完成runit测试127/140,reg2mem基本思路:函数参数默认降级到内存,有结果的指令被降级的内存 2025-07-29 14:34:16 +08:00
4a329eeaf2 [midend]修复return指令exp为空的判断条件错误 2025-07-29 12:16:46 +08:00
3dc4b28c92 [midend-mem2reg]dom增加访问支配树子节点求解和访问方法,修复block打印,phi指令命名,TODO:reg2membug待修复 2025-07-29 03:25:56 +08:00
202e6d7cd8 [midend-mem2reg]增加遍打印方法,修复reg2mem构造函数错误 2025-07-29 02:11:10 +08:00
3e4cac089e [midend-reg2mem]增加reg2mem遍,应用未定义值,增加inst迭代器查找方法,通过编译且脚本运行通过率不变 2025-07-29 02:01:48 +08:00
76d7b14b2e [backend]更新了测试脚本,现在的测试更准确 2025-07-29 01:04:43 +08:00
9ba08126fb Merge branch 'peephole' into backend 2025-07-28 23:46:34 +08:00
875100ec01 [backend]为单次运行脚本添加了clean参数 2025-07-28 23:41:36 +08:00
b0cecca081 Merge branch 'backend-rec' into backend 2025-07-28 23:40:58 +08:00
434bcea98e [PostRA_Scheduler]修复了超大测例卡死的bug 2025-07-28 23:17:26 +08:00
da5c2bb41d [PostRA_Scheduler]完成寄存器分配后的指令调度优化 2025-07-28 22:35:29 +08:00
fcc3806342 Merge branch 'backend-bss' into backend 2025-07-28 17:31:47 +08:00
792dc9c1f6 Merge branch 'backend-bss' into backend-rec 2025-07-28 17:31:23 +08:00
429e477776 [backend]引入了对.bss和.data段的区分 2025-07-28 17:29:18 +08:00
535a935bf1 [midend-mem2reg]暂存文件,思路留存 2025-07-28 14:57:15 +08:00
efe74cba6c [midend-mem2reg]mem2reg遍基本写完,编译不报错,待reg2mem写完统一测试 2025-07-28 14:28:46 +08:00
634a84f29c [peephole]Pass架构重构优化 2025-07-27 11:03:26 +08:00
2e8b564d8f [backend]修复了递归函数的调用问题,引入了新的bug? 2025-07-27 01:07:08 +08:00
2dd6a17fca [backend]saving1 2025-07-27 00:34:45 +08:00
78dee0d72a [peephole]添加7项窥孔优化规则初步测试生效成功,有待进一步检查,TODO: 指令调度优化 2025-07-26 21:48:14 +08:00
af318b6c0e [backend]尝试在寄存器分配逻辑中区分调用者保存、被调用者保存寄存器 2025-07-26 21:45:01 +08:00
9bea4d5343 [backend]更新todo 2025-07-26 19:04:31 +08:00
540742be0c [backend]添加了一个Pass,将调用者、被调用者寄存器实现转移到其中 2025-07-26 18:38:04 +08:00
8ae7478ef3 Merge branch 'midend' into backend 2025-07-26 17:36:23 +08:00
a616ec085e [midend][backend]补全了符合RV64调用约定的寄存器着色规则 2025-07-26 17:35:08 +08:00
828515bc2f [midend][backend]添加了DAG中的Argument类型,添加了Argument节点的处理逻辑 2025-07-26 16:55:32 +08:00
a231267fc5 [midend]修复函数参数alloca指令创建错误导致的段错误,修复irprint对argument的识别 2025-07-26 13:02:24 +08:00
4b181261ce [midend][backend]同步后端逻辑,修复编译错误 2025-07-26 12:53:21 +08:00
3df9b3bb06 Merge remote-tracking branch 'origin/midend-mem2reg' into midend 2025-07-26 12:41:43 +08:00
e57ac7709d [backend]开始区分调用者保存寄存器与被调用者保存寄存器 2025-07-26 12:39:17 +08:00
2643eb1edd [midend-mem2reg]修改函数参数定义引入argument类,显示为参数创建alloca和store指令 2025-07-26 12:30:03 +08:00
5bfa6d72a2 Merge branch 'midend' into backend 2025-07-25 22:25:45 +08:00
14fb3dbe48 [midend][backend-GEP]解决了一个32/64位宽的错误问题 2025-07-25 22:23:26 +08:00
04c5c6b44d [midend-mem2reg]修复assignstmt对lvalue的错误解析(lvaue会被exp解释为值,而被assign解释为地址) 2025-07-25 20:00:41 +08:00
e2c97fd171 [miden]DCE引入ctx避免重复运行遍导致的状态污染。修复天然活跃判断条件 2025-07-25 16:33:18 +08:00
12f63a0bf5 [midend]解决标签重名问题 2025-07-25 12:35:35 +08:00
d50912ee4c [midend]后端适配GEP 2025-07-25 12:00:47 +08:00
259d71cde5 Merge branch 'midend' of gitee.com:lixuanwang/mysysy into midend 2025-07-25 11:18:12 +08:00
1e6f6ed711 [midend] GEP类型推断函数getIndexedType逻辑修复,增加数组type缓存池避免相同type ==操作返回假,修复实参形参类型转换判断逻辑,starttime stoptime提供支持(待后端测试) 2025-07-25 03:26:10 +08:00
96c6b0ab6e [midend]修复函数参数为数组指针的退化问题,能够正确区分局部变量和函数参数并生成正确的GEP指令 2025-07-25 01:53:49 +08:00
10a533b0cc [backend]添加了库 2025-07-24 21:04:20 +08:00
5f8bf15d4d [midend]添加了库 2025-07-24 21:02:28 +08:00
18dc8dbfee [midend]修改注释 2025-07-24 17:05:56 +08:00
9c56bc1310 [midend]修改GEP指令定义,更靠近llvm ir设计,增加自动推断类型函数,修复generator中错误生成ir的逻辑 2025-07-24 17:02:29 +08:00
c68b031c01 [midend]修复全局数组类型问题 2025-07-24 15:22:38 +08:00
2556ab7315 [midend]修复getanalysisusagee缺失定义,修复数组初始化错误 2025-07-24 15:04:29 +08:00
4b9d067c12 [midend]部分DCE遍实现(传播活跃代码),修改优化遍运行逻辑,TODO:完善优化遍的getAnalysisUsage,删除无用代码 2025-07-24 14:36:33 +08:00
f4d231b989 [midend]添加了后端中对GEP指令的支持 2025-07-24 00:39:11 +08:00
56b376914b Merge branch 'backend' into midend 2025-07-23 19:30:19 +08:00
2157cf6aa6 [midend]修复了一个Pass相关的编译错误 2025-07-23 19:12:04 +08:00
0e492cd6d7 [backend]修复了函数序言的根本性错误 2025-07-23 18:43:40 +08:00
87d38be255 [midend]更新遍静态ID定义方法,
注册遍模板函数重构(针对遍的不同构造方法),
修复phi指令更新引起的旧代码错误,
将CFG优化适配到现有终端框架中,
独立CFG优化方法使得其他优化遍能独立调用,
usedelete方法回调取消删除功能。
IRGenerator代码风格修改。
2025-07-23 17:19:11 +08:00
2040670f8c [backend]添加了DAG图打印函数;为分支指令引入了延迟物化;添加了函数参数溢出到栈的处理逻辑 2025-07-22 22:50:25 +08:00
3df3d7a097 [midend]通过编译,TODO:验证正确性 2025-07-22 22:38:47 +08:00
b20bda2f52 [backend]引入了栈上的20字节安全区 2025-07-22 21:36:22 +08:00
f61b51b2fa [midend]优化中端框架,移除无用旧代码,ignore格式文件 2025-07-22 21:25:07 +08:00
20a5c5cbfb [backend]增加了一个在虚拟机内部单文件调试的脚本 2025-07-22 02:25:30 +08:00
cf88ca77cb [backend]修复了一个全局数组地址的计算问题 2025-07-22 00:16:37 +08:00
fd6fe22020 [backend]增加了对全局数组的访存地址展开 2025-07-22 00:11:42 +08:00
e8fe710c26 [backend]更新了测试脚本,限制最大打印行数,避免糟蹋终端输出 2025-07-22 00:09:41 +08:00
9c87cb397b [backend]解决了非零数组初始化不正确的问题 2025-07-22 00:07:54 +08:00
c45938d41d Merge branch 'backend' of gitee.com:lixuanwang/mysysy into backend 2025-07-21 17:49:09 +08:00
3baccbc03a [backend]解决了测试程序可能的挂起问题,引入了用于单个用例测试的新脚本 2025-07-21 17:49:06 +08:00
24d8e730f1 [backend]更新了测试脚本,减少测试进程卡死情况 2025-07-21 17:36:22 +08:00
bbfbf96b5e [backend]解决了重构后数组初始化不正确的问题 2025-07-21 16:27:47 +08:00
a72fc541fb [midend]活跃变量分析,CFG优化遍重写。还未跑通,暂存 2025-07-21 15:20:46 +08:00
550f4017be [midend]重构中端,建立遍管理器,注册器等,初步构建支配树分析遍,增加基本块方法 2025-07-21 15:19:38 +08:00
f7e811b756 [backend]解决了标签打印问题 2025-07-21 14:44:48 +08:00
88604c1f94 [IR]消除Falltrhough现象
[IR]优化生成Ret指令逻辑
[README]添加TODO表
2025-07-20 18:23:48 +08:00
de696b2b53 [IR]重构数组地址相关指令
增加GEP指令以及相关方法
新增数组Array Type
删除无用指令(GetSubArray,LA)
删除冗余类定义(Lval)
修复中间代码生成逻辑
测试通过所以test目录下的文件
TODO:后端展开数组计算地址仅需要针对GEP指令展开
2025-07-20 15:33:58 +08:00
18e7cbd413 Merge branch 'backend' into SCCP 2025-07-20 13:00:15 +08:00
20cd16bf52 暂存2 2025-07-20 12:54:19 +08:00
80dee78f04 [backend]引入后端pass管理器 2025-07-20 12:45:52 +08:00
8f1e477e73 暂存 2025-07-19 14:23:57 +08:00
10b011a1de [fix]修复部分常量构建,[Pass]建立Pass基类和管理器,预重构优化遍结构 2025-07-18 21:28:36 +08:00
34b5a93aaf [Mem2Reg]重构SSA提升 2025-07-18 18:17:45 +08:00
a5d97185e1 [IR]修复IR报错,调整结构。 2025-07-18 18:17:22 +08:00
fdc946c1b5 [IR]重构常量定义,引入undefvalue定义,修改常量方法使用尽量适配旧版 2025-07-18 16:40:16 +08:00
725da2858d [IR]指令构造器更新 2025-07-17 21:34:19 +08:00
631ef80de2 [IR]phi指令重构,将block信息加入并提供新方法,后续需更改phi相关指令构建逻辑 2025-07-17 19:01:02 +08:00
77fae4d662 [CFG]增加分支优化,为SCCP调用做铺垫,预备修改phi定义 2025-07-17 16:50:09 +08:00
009f54863e [CFG]CFG优化方法转换为静态方法,方便其他优化遍调用,TODO:简化条件分支 2025-07-17 15:54:37 +08:00
f7e318e623 [SCCP]初步构建SCCP,.cpp仍不完善暂不commit 2025-07-16 22:01:37 +08:00
00348c1931 修改CFG优化的文件名,修改phidel标签 2025-07-16 22:01:37 +08:00
5a6cfbee1e [SysYIROptUtils]增加通用优化工具类,修改相关代码 2025-07-16 22:01:37 +08:00
319 changed files with 639597 additions and 8748 deletions

5
.gitignore vendored
View File

@ -23,7 +23,6 @@
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
@ -37,6 +36,7 @@ doxygen
!/testdata/functional/*.out
!/testdata/h_functional/*.out
!/testdata/performance/*.out
build/
.antlr
.vscode/
@ -53,4 +53,5 @@ __init__.py
.DS_*
antlr/
antlr/
.clang-format

429
Pass_ID_List.md Normal file
View File

@ -0,0 +1,429 @@
# 记录中端遍的开发进度
| 名称 | 优化级别 | 开发进度 |
| ------------ | ------------ | ---------- |
| CFG优化 | 函数级 | 已完成 |
| DCE | 函数级 | 待正确性测试 |
| Mem2Reg | 函数级 | 待正确性测试 |
| Reg2Mem | 函数级 | 待正确性测试 |
# 部分优化遍的说明
## Mem2Reg
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位范围时及时发现
智能回退:使用已验证的标准值保证正确性
保持通用性:对于没有预设值的除数仍然可以工作
## 死归纳变量消除
整体架构和工作流程
当前的归纳变量消除优化分为三个清晰的阶段:
识别阶段:找出所有潜在的死归纳变量
安全性分析阶段:验证每个变量消除的安全性
消除执行阶段:实际删除安全的死归纳变量
逃逸点检测 (已修复的关键安全机制)
数组索引检测GEP指令被正确识别为逃逸点
循环退出条件:用于比较和条件分支的归纳变量不会被消除
控制流指令condBr、br、return等被特殊处理为逃逸点
内存操作store/load指令经过别名分析检查
# 后续优化可能涉及的改动
## 1将所有的alloca集中到entryblock中已实现
好处优化友好性方便mem2reg提升
目前没有实现这个机制,如果想要实现首先解决同一函数不同域的同名变量命名区分
需要保证符号表能正确维护域中的局部变量
# 关于中端优化提升编译器性能的TODO
## usedelete_withinstdelte方法
这个方法删除了use关系并移除了指令逻辑是根据Instruction* inst去find对应的迭代器并erase
有些情况下外部持有迭代器和inst,可以省略find过程

View File

@ -37,4 +37,38 @@ mysysy/ $ bash setup.sh
```
### 配套脚本
TODO: 需要完善)
TODO: 需要完善)
### TODO_list:
除开注释中的TODO后续时间充足可以考虑的TODO:
- store load指令由于gep指令的引入, 维度信息的记录是非必须的, 考虑删除
- use def关系经过mem2reg和phi函数明确转换为ssa形式, 以及函数参数通过value数组明确定义, 使得基本块的args参数信息记录非必须, 考虑删除
---
## 编译器后端 TODO 列表
### 1. `CALL` 指令处理不完善 (高优先级)
* **问题描述**:当前 `RISCv64RegAlloc::getInstrUseDef()` 方法中,对 `CALL` 指令的 `use`/`def` 分析不完整。它正确识别了返回值为 `def` 和参数为 `use`,但**没有将所有调用者保存 (Caller-saved) 的物理寄存器(`T0-T6`, `A0-A7`)标记为隐式 `def` (即 `CALL` 会破坏它们)**。
* **潜在后果**
* **活跃性分析错误**:寄存器分配器可能会错误地认为某个跨函数调用活跃的虚拟寄存器是安全的,并将其分配给 `T` 或 `A` 寄存器。
* **值被破坏**:在 `CALL` 指令执行后,这些 `T` 或 `A` 寄存器中本应保留的值会被被调用的函数破坏,导致程序行为异常。
* **参考文件**`RISCv64RegAlloc.cpp` (在 `getInstrUseDef` 函数中对 `RVOpcodes::CALL` 的处理)。
### 2. `T6` 寄存器作为溢出寄存器的问题 (中等优先级)
* **问题描述**`RISCv64RegAlloc::rewriteFunction()` 方法中,所有未能成功着色并被溢出 (spilled) 的虚拟寄存器,都被统一替换为物理寄存器 `T6`。
* **问题 2.1`T6` 是调用者保存寄存器,但未被调用者保存**
* `T6` 属于调用者保存寄存器 (`T0-T6` 范围)。
* 标准 ABI 要求,如果一个调用者保存寄存器在函数调用前后都活跃(例如,它存储了一个被溢出的变量,而这个变量在 `CALL` 指令之后还需要用到),那么**调用者**有责任在 `CALL` 前保存该寄存器,并在 `CALL` 后恢复它。
* 目前的 `rewriteFunction` 没有为 `T6` 插入这种保存/恢复逻辑。
* **潜在后果**:如果一个溢出变量被分配到 `T6`,并且它跨函数调用活跃,那么 `putint` 或其他任何被调用的函数可能会随意使用 `T6`,从而破坏该溢出变量的值。
* **问题 2.2:所有溢出变量共用一个 `T6`**
* 将所有溢出变量映射到同一个物理寄存器 `T6` 是一种简化的溢出策略。
* **潜在后果**:这意味着,每当需要使用一个溢出变量时,其值必须从栈中加载到 `T6`;每当一个溢出变量被定义时,其值必须从 `T6` 存储回栈。这会引入大量的 `load`/`store` 指令,并导致 `T6` 本身成为一个高度冲突的寄存器,严重降低代码效率。
* **参考文件**`RISCv64RegAlloc.cpp` (在 `rewriteFunction` 函数中处理 `spilled_vregs` 的部分)。

BIN
lib/libsysy_arm.a Normal file

Binary file not shown.

BIN
lib/libsysy_riscv.a Normal file

Binary file not shown.

View File

@ -0,0 +1,255 @@
#!/bin/bash
# runit-riscv64-single.sh - 用于在 RISC-V 虚拟机内部测试单个或少量 .s 文件的脚本
# 模仿 runit-riscv64.sh 的功能,但以具体文件路径作为输入。
# --- 配置区 ---
# 假设此脚本位于项目根目录 (例如 /home/ubuntu/debug)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
LIB_DIR="${SCRIPT_DIR}/lib"
TMP_DIR="${SCRIPT_DIR}/tmp" # 临时可执行文件将存放在这里
TESTDATA_DIR="${SCRIPT_DIR}/testdata" # 用于查找 .in/.out 文件
# 定义编译器
GCC_NATIVE="gcc" # VM 内部的原生 gcc
# --- 初始化变量 ---
CLEAN_MODE=false
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
EXEC_TIMEOUT=5 # 程序自动化执行超时 (秒)
MAX_OUTPUT_LINES=50 # 对比失败时显示的最大行数
S_FILES=() # 存储用户提供的 .s 文件列表
PASSED_CASES=0
FAILED_CASES_LIST=""
# --- 函数定义 ---
show_help() {
echo "用法: $0 [文件1.s] [文件2.s] ... [选项]"
echo "在 VM 内部编译并测试指定的 .s 文件。"
echo ""
echo "如果找到对应的 .in/.out 文件,则进行自动化测试。否则,进入交互模式。"
echo ""
echo "选项:"
echo " -c, --clean 清理 tmp 临时目录下的所有文件。"
echo " -ct N 设置 gcc 编译超时为 N 秒 (默认: 10)。"
echo " -t N 设置程序自动化执行超时为 N 秒 (默认: 5)。"
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 50)。"
echo " -h, --help 显示此帮助信息并退出。"
}
# 显示文件内容并根据行数截断的函数
display_file_content() {
local file_path="$1"
local title="$2"
local max_lines="$3"
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"
else
cat "$file_path"
fi
}
# --- 新增功能: 清理临时文件的函数 ---
clean_tmp() {
echo "正在清理临时目录: ${TMP_DIR}"
if [ -d "${TMP_DIR}" ]; then
rm -rf "${TMP_DIR}"/* 2>/dev/null
echo "清理完成。"
else
echo "临时目录 ${TMP_DIR} 不存在,无需清理。"
fi
}
# --- 参数解析 ---
# 从参数中分离出 .s 文件和选项
for arg in "$@"; do
case "$arg" in
-c|--clean)
CLEAN_MODE=true
;;
-ct|-t|-ml|--max-lines)
# 选项和其值将在下一个循环中处理
;;
-h|--help)
show_help
exit 0
;;
-*)
# 检查是否是带值的选项
if ! [[ ${args_processed+x} ]]; then
args_processed=true # 标记已处理过参数
while [[ "$#" -gt 0 ]]; do
case "$1" in
-c|--clean) ;; # 已在外部处理
-ct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift; else echo "错误: -ct 需要一个正整数参数。" >&2; exit 1; fi ;;
-t) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift; else echo "错误: -t 需要一个正整数参数。" >&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 ;;
*.s) S_FILES+=("$1") ;;
*) if ! [[ "$1" =~ ^[0-9]+$ ]]; then echo "未知选项或无效文件: $1"; show_help; exit 1; fi ;;
esac
shift
done
fi
;;
*.s)
if [[ -f "$arg" ]]; then
S_FILES+=("$arg")
else
echo "警告: 文件不存在,已忽略: $arg"
fi
;;
esac
done
# --- 主逻辑开始 ---
if ${CLEAN_MODE}; then
clean_tmp
# 如果只提供了 -c 选项,则退出
if [ ${#S_FILES[@]} -eq 0 ]; then
exit 0
fi
fi
if [ ${#S_FILES[@]} -eq 0 ]; then
echo "错误: 未提供任何 .s 文件作为输入。"
show_help
exit 1
fi
mkdir -p "${TMP_DIR}"
TOTAL_CASES=${#S_FILES[@]}
echo "SysY VM 内单例测试运行器启动..."
echo "超时设置: gcc=${GCC_TIMEOUT}s, 运行=${EXEC_TIMEOUT}s"
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
echo ""
for s_file in "${S_FILES[@]}"; do
is_passed=1
# 从 .s 文件名反向推导原始测试用例路径
base_name_from_s_file=$(basename "$s_file" .s)
original_test_name_underscored=$(echo "$base_name_from_s_file" | sed 's/_sysyc_riscv64$//')
category=$(echo "$original_test_name_underscored" | cut -d'_' -f1)
test_file_base=$(echo "$original_test_name_underscored" | cut -d'_' -f2-)
original_relative_path="${category}/${test_file_base}"
executable_file="${TMP_DIR}/${base_name_from_s_file}"
input_file="${TESTDATA_DIR}/${original_relative_path}.in"
output_reference_file="${TESTDATA_DIR}/${original_relative_path}.out"
output_actual_file="${TMP_DIR}/${base_name_from_s_file}.actual_out"
echo "======================================================================"
echo "正在处理: ${s_file}"
echo " (关联测试用例: ${original_relative_path}.sy)"
# 步骤 1: GCC 编译
echo " 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
timeout -s KILL ${GCC_TIMEOUT} "${GCC_NATIVE}" "${s_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static -g
if [ $? -ne 0 ]; then
echo -e "\e[31m错误: GCC 编译失败或超时。\e[0m"
is_passed=0
fi
# 步骤 2: 执行与测试
if [ "$is_passed" -eq 1 ]; then
# 检查是自动化测试还是交互模式
if [ -f "${input_file}" ] || [ -f "${output_reference_file}" ]; then
# --- 自动化测试模式 ---
echo " 检测到 .in/.out 文件,进入自动化测试模式..."
echo " 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
exec_cmd="\"${executable_file}\""
[ -f "${input_file}" ] && exec_cmd+=" < \"${input_file}\""
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 执行超时。\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}/${base_name_from_s_file}.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 删除所有空白字符后再比较 ---
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
# --- 本次修改点: 使用 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}"
fi
fi
else
# --- 交互模式 ---
echo -e "\e[33m"
echo " **********************************************************"
echo " ** 未找到 .in 或 .out 文件,进入交互模式。 **"
echo " ** 程序即将运行,你可以直接在终端中输入。 **"
echo " ** 按下 Ctrl+D (EOF) 或以其他方式结束程序以继续。 **"
echo " **********************************************************"
echo -e "\e[0m"
"${executable_file}"
INTERACTIVE_RET_CODE=$?
echo -e "\e[33m\n 交互模式执行完毕,程序返回码: ${INTERACTIVE_RET_CODE}\e[0m"
echo " 注意: 交互模式的结果未经验证。"
fi
fi
if [ "$is_passed" -eq 1 ]; then
echo -e "\e[32m状态: 通过\e[0m"
((PASSED_CASES++))
else
echo -e "\e[31m状态: 失败\e[0m"
FAILED_CASES_LIST+="${original_relative_path}.sy\n"
fi
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

228
script/runit-riscv64.sh Normal file
View File

@ -0,0 +1,228 @@
#!/bin/bash
# runit-riscv64.sh - 用于在 RISC-V 虚拟机内部汇编、链接和测试 SysY 程序的脚本
# 此脚本应位于您的项目根目录 (例如 /home/ubuntu/debug)
# 假设当前运行环境已经是 RISC-V 64 位架构,可以直接执行编译后的程序。
# 定义相对于脚本位置的目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
TMP_DIR="${SCRIPT_DIR}/tmp"
LIB_DIR="${SCRIPT_DIR}/lib"
TESTDATA_DIR="${SCRIPT_DIR}/testdata"
# 定义编译器 (这里假设 gcc 在 VM 内部是可用的)
GCC_NATIVE="gcc" # VM 内部的 gcc
# --- 新增功能: 初始化变量 ---
GCC_TIMEOUT=10 # 默认 gcc 编译超时 (秒)
EXEC_TIMEOUT=5 # 默认运行时超时 (秒)
MAX_OUTPUT_LINES=50 # 对比失败时显示的最大行数
TOTAL_CASES=0
PASSED_CASES=0
FAILED_CASES_LIST="" # 用于存储未通过的测例列表
# 显示帮助信息的函数
show_help() {
echo "用法: $0 [选项]"
echo "此脚本用于在 RISC-V 虚拟机内部,对之前生成的 .s 汇编文件进行汇编、链接和测试。"
echo "测试会按文件名升序进行。"
echo ""
echo "选项:"
echo " -c, --clean 清理 'tmp' 目录下的所有生成文件。"
echo " -ct M 设置 gcc 编译的超时时间为 M 秒 (默认: 10)。"
echo " -t N 设置每个测试用例的运行时超时为 N 秒 (默认: 5)。"
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 50)。"
echo " -h, --help 显示此帮助信息并退出。"
}
# 显示文件内容并根据行数截断的函数
display_file_content() {
local file_path="$1"
local title="$2"
local max_lines="$3"
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"
else
cat "$file_path"
fi
}
# 清理临时文件的函数
clean_tmp() {
echo "正在清理临时目录: ${TMP_DIR}"
rm -rf "${TMP_DIR}"/*
echo "清理完成。"
}
# 如果临时目录不存在,则创建它
mkdir -p "${TMP_DIR}"
# 解析命令行参数
while [[ "$#" -gt 0 ]]; do
case "$1" in
-c|--clean)
clean_tmp
exit 0
;;
-t)
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift; else echo "错误: -t 需要一个正整数参数。" >&2; exit 1; fi
;;
-ct)
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift; else echo "错误: -ct 需要一个正整数参数。" >&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
;;
esac
shift # 移过参数名
done
echo "SysY VM 内部测试运行器启动..."
echo "GCC 编译超时设置为: ${GCC_TIMEOUT}"
echo "运行时超时设置为: ${EXEC_TIMEOUT}"
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
echo "汇编文件目录: ${TMP_DIR}"
echo ""
# 查找 tmp 目录下的所有 .s 汇编文件并排序
s_files=$(find "${TMP_DIR}" -maxdepth 1 -name "*.s" | sort -V)
TOTAL_CASES=$(echo "$s_files" | wc -w)
# 使用 here-string (<<<) 避免子 shell 问题
while IFS= read -r s_file; do
is_passed=1 # 1 表示通过, 0 表示失败
base_name_from_s_file=$(basename "$s_file" .s)
original_test_name_underscored=$(echo "$base_name_from_s_file" | sed 's/_sysyc_riscv64$//')
category=$(echo "$original_test_name_underscored" | cut -d'_' -f1)
test_file_base=$(echo "$original_test_name_underscored" | cut -d'_' -f2-)
original_relative_path="${category}/${test_file_base}"
executable_file="${TMP_DIR}/${base_name_from_s_file}"
input_file="${TESTDATA_DIR}/${original_relative_path}.in"
output_reference_file="${TESTDATA_DIR}/${original_relative_path}.out"
output_actual_file="${TMP_DIR}/${base_name_from_s_file}.actual_out"
echo "正在处理汇编文件: $(basename "$s_file")"
echo " 对应的测试用例路径: ${original_relative_path}"
# 步骤 1: 使用 VM 内部的 gcc 编译 .s 到可执行文件
echo " 使用 gcc 汇编并链接 (超时 ${GCC_TIMEOUT}s)..."
timeout -s KILL ${GCC_TIMEOUT} "${GCC_NATIVE}" "${s_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static -g
GCC_STATUS=$?
if [ $GCC_STATUS -eq 124 ]; then
echo -e "\e[31m错误: GCC 编译/链接 ${s_file} 超时\e[0m"
is_passed=0
elif [ $GCC_STATUS -ne 0 ]; then
echo -e "\e[31m错误: GCC 汇编/链接 ${s_file} 失败,退出码: ${GCC_STATUS}\e[0m"
is_passed=0
fi
# 步骤 2: 只有当编译成功时才执行
if [ "$is_passed" -eq 1 ]; then
echo " 生成的可执行文件: ${executable_file}"
echo " 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
exec_cmd="\"${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 执行超时: ${original_relative_path}.sy 运行超过 ${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}/${base_name_from_s_file}.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}"
fi
fi
fi
if [ "$is_passed" -eq 1 ]; then
((PASSED_CASES++))
else
FAILED_CASES_LIST+="${original_relative_path}.sy\n"
fi
echo ""
done <<< "$s_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

304
script/runit-single.sh Normal file
View File

@ -0,0 +1,304 @@
#!/bin/bash
# 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_BIN_DIR="${SCRIPT_DIR}/../build/bin"
LIB_DIR="${SCRIPT_DIR}/../lib"
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
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 文件。必须提供 -e 或 -eir 之一。"
echo ""
echo "选项:"
echo " -e 通过汇编运行测试 (sysyc -> gcc -> qemu)。"
echo " -eir 通过IR运行测试 (sysyc -> llc -> gcc -> qemu)。"
echo " -c, --clean 清理 tmp 临时目录下的所有文件。"
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 秒 (默认: 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
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"
else
cat "$file_path"
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
# --- 参数解析 ---
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 -rf "${TMP_DIR}"/* 2>/dev/null
echo "清理完成。"
else
echo "临时目录 ${TMP_DIR} 不存在,无需清理。"
fi
if [ ${#SY_FILES[@]} -eq 0 ] && ! ${EXECUTE_MODE} && ! ${IR_EXECUTE_MODE}; then
exit 0
fi
fi
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
exit 1
fi
mkdir -p "${TMP_DIR}"
TOTAL_CASES=${#SY_FILES[@]}
echo "SysY 单例测试运行器启动..."
if [ -n "$OPTIMIZE_FLAG" ]; then echo "优化等级: ${OPTIMIZE_FLAG}"; fi
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, llc=${LLC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
echo ""
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}.ll"
assembly_file="${TMP_DIR}/${base_name}.s"
executable_file="${TMP_DIR}/${base_name}"
input_file="${source_dir}/${base_name}.in"
output_reference_file="${source_dir}/${base_name}.out"
output_actual_file="${TMP_DIR}/${base_name}.actual_out"
echo "======================================================================"
echo "正在处理: ${sy_file}"
# --- 编译阶段 ---
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
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
# --- 执行与测试阶段 (公共逻辑) ---
if [ "$compilation_ok" -eq 1 ]; then
if [ -f "${input_file}" ] || [ -f "${output_reference_file}" ]; then
# --- 自动化测试模式 ---
echo " 检测到 .in/.out 文件,进入自动化测试模式..."
echo " 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
exec_cmd="${QEMU_RISCV64} \"${executable_file}\""
[ -f "${input_file}" ] && exec_cmd+=" < \"${input_file}\""
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 执行超时。\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}/${base_name}.expected_stdout"
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
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"; 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}"
fi
if [ "$ret_ok" -eq 1 ] && [ "$out_ok" -eq 1 ]; then echo -e "\e[32m 返回码与标准输出测试成功。\e[0m"; else is_passed=0; fi
else
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}"
fi
fi
else
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
fi
fi
else
# --- 交互模式 ---
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"
fi
else
is_passed=0
fi
# --- 状态总结 ---
if [ "$is_passed" -eq 1 ]; then
echo -e "\e[32m状态: 通过\e[0m"
((PASSED_CASES++))
else
echo -e "\e[31m状态: 失败\e[0m"
FAILED_CASES_LIST+="${sy_file}\n"
fi
done
# --- 打印最终总结 ---
print_summary

442
script/runit.sh Normal file
View File

@ -0,0 +1,442 @@
#!/bin/bash
# runit.sh - 用于编译和测试 SysY 程序的脚本
# 此脚本应该位于 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"
# 定义编译器和模拟器
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
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=""
INTERRUPTED=false # 新增:用于标记是否被中断
# =================================================================
# --- 函数定义 ---
# =================================================================
# 显示帮助信息的函数
show_help() {
echo "用法: $0 [选项]"
echo "此脚本用于按文件名前缀数字升序编译和测试 .sy 文件。"
echo ""
echo "选项:"
echo " -e, --executable 编译为汇编并运行测试 (sysyc -> gcc -> qemu)。"
echo " -eir 通过IR编译为可执行文件并运行测试 (sysyc -> llc -> gcc -> qemu)。"
echo " -c, --clean 清理 'tmp' 目录下的所有生成文件。"
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 秒 (默认: 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
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"
else
cat "$file_path"
fi
}
# 清理临时文件的函数
clean_tmp() {
echo "正在清理临时目录: ${TMP_DIR}"
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; 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
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 测试运行器启动..."
if [ -n "$OPTIMIZE_FLAG" ]; then echo "优化等级: ${OPTIMIZE_FLAG}"; fi
echo "输入目录: ${SEARCH_PATHS[@]}"
echo "临时目录: ${TMP_DIR}"
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_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)
while IFS= read -r sy_file; do
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_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"
echo "正在处理: $(basename "$sy_file") (路径: ${relative_path_no_ext}.sy)"
# --- 模式 1: IR 执行模式 (-eir) ---
if ${IR_EXECUTE_MODE}; then
step_failed=0
test_logic_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
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"
# --- 修改:调用总结函数 ---
print_summary

View File

@ -1,160 +0,0 @@
#include "AddressCalculationExpansion.h"
#include <iostream>
#include <vector>
#include "IR.h"
#include "IRBuilder.h"
extern int DEBUG;
namespace sysy {
bool AddressCalculationExpansion::run() {
bool changed = false;
for (auto& funcPair : pModule->getFunctions()) {
Function* func = funcPair.second.get();
for (auto& bb_ptr : func->getBasicBlocks()) {
BasicBlock* bb = bb_ptr.get();
for (auto it = bb->getInstructions().begin(); it != bb->getInstructions().end(); ) {
Instruction* inst = it->get();
Value* basePointer = nullptr;
Value* valueToStore = nullptr;
size_t firstIndexOperandIdx = 0;
size_t numBaseOperands = 0;
if (inst->isLoad()) {
numBaseOperands = 1;
basePointer = inst->getOperand(0);
firstIndexOperandIdx = 1;
} else if (inst->isStore()) {
numBaseOperands = 2;
valueToStore = inst->getOperand(0);
basePointer = inst->getOperand(1);
firstIndexOperandIdx = 2;
} else {
++it;
continue;
}
if (inst->getNumOperands() <= numBaseOperands) {
++it;
continue;
}
std::vector<int> dims;
if (AllocaInst* allocaInst = dynamic_cast<AllocaInst*>(basePointer)) {
for (const auto& use_ptr : allocaInst->getDims()) {
Value* dimValue = use_ptr->getValue();
if (ConstantValue* constVal = dynamic_cast<ConstantValue*>(dimValue)) {
dims.push_back(constVal->getInt());
} else {
std::cerr << "Warning: AllocaInst dimension is not a constant integer. Skipping GEP expansion for: ";
SysYPrinter::printValue(allocaInst);
std::cerr << "\n";
dims.clear();
break;
}
}
} else if (GlobalValue* globalValue = dynamic_cast<GlobalValue*>(basePointer)) {
std::cerr << "Warning: GlobalValue dimension handling needs explicit implementation for GEP expansion. Skipping GEP for: ";
SysYPrinter::printValue(globalValue);
std::cerr << "\n";
++it;
continue;
} else {
std::cerr << "Warning: Base pointer is not AllocaInst/GlobalValue or its array dimensions cannot be determined for GEP expansion. Skipping GEP for: ";
SysYPrinter::printValue(basePointer);
std::cerr << " in instruction ";
SysYPrinter::printInst(inst);
std::cerr << "\n";
++it;
continue;
}
if (dims.empty() && (inst->getNumOperands() > numBaseOperands)) {
if (DEBUG) {
std::cerr << "ACE Warning: Could not get valid array dimensions for ";
SysYPrinter::printValue(basePointer);
std::cerr << " in instruction ";
SysYPrinter::printInst(inst);
std::cerr << " (expected dimensions for indices, but got none).\n";
}
++it;
continue;
}
std::vector<Value*> indexOperands;
for (size_t i = firstIndexOperandIdx; i < inst->getNumOperands(); ++i) {
indexOperands.push_back(inst->getOperand(i));
}
if (AllocaInst* allocaInst = dynamic_cast<AllocaInst*>(basePointer)) {
if (allocaInst->getNumDims() != indexOperands.size()) {
if (DEBUG) {
std::cerr << "ACE Warning: Index count (" << indexOperands.size() << ") does not match AllocaInst dimensions (" << allocaInst->getNumDims() << ") for instruction ";
SysYPrinter::printInst(inst);
std::cerr << "\n";
}
++it;
continue;
}
}
Value* totalOffset = ConstantInteger::get(0);
pBuilder->setPosition(bb, it);
for (size_t i = 0; i < indexOperands.size(); ++i) {
Value* index = indexOperands[i];
int stride = calculateStride(dims, i);
Value* strideConst = ConstantInteger::get(stride);
Type* intType = Type::getIntType();
BinaryInst* currentDimOffsetInst = pBuilder->createBinaryInst(Instruction::kMul, intType, index, strideConst);
BinaryInst* newTotalOffsetInst = pBuilder->createBinaryInst(Instruction::kAdd, intType, totalOffset, currentDimOffsetInst);
totalOffset = newTotalOffsetInst;
}
// 计算有效地址effective_address = basePointer + totalOffset
Value* effective_address = pBuilder->createBinaryInst(Instruction::kAdd, basePointer->getType(), basePointer, totalOffset);
// 创建新的 LoadInst 或 StoreInstindices 为空
Instruction* newInst = nullptr;
if (inst->isLoad()) {
newInst = pBuilder->createLoadInst(effective_address, {});
inst->replaceAllUsesWith(newInst);
} else { // StoreInst
newInst = pBuilder->createStoreInst(valueToStore, effective_address, {});
}
Instruction* oldInst = it->get();
++it;
for (size_t i = 0; i < oldInst->getNumOperands(); ++i) {
Value* operandValue = oldInst->getOperand(i);
if (operandValue) {
for (auto use_it = operandValue->getUses().begin(); use_it != operandValue->getUses().end(); ++use_it) {
if ((*use_it)->getUser() == oldInst && (*use_it)->getIndex() == i) {
operandValue->removeUse(*use_it);
break;
}
}
}
}
bb->getInstructions().erase(std::prev(it));
changed = true;
if (DEBUG) {
std::cerr << "ACE: Computed effective address:\n";
SysYPrinter::printInst(dynamic_cast<Instruction*>(effective_address));
std::cerr << "ACE: New Load/Store instruction:\n";
SysYPrinter::printInst(newInst);
std::cerr << "--------------------------------\n";
}
}
}
}
return changed;
}
} // namespace sysy

View File

@ -1,51 +1,24 @@
# 移除 ANTLR 代码生成相关配置
# list(APPEND CMAKE_MODULE_PATH "${ANTLR_RUNTIME}/cmake")
# include(FindANTLR)
# antlr_target(SysYGen SysY.g4
# LEXER PARSER
# OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
# VISITOR
# )
# src/CMakeLists.txt
# add_subdirectory 命令会负责遍历子目录并查找其内部的 CMakeLists.txt 文件
add_subdirectory(frontend)
add_subdirectory(midend)
add_subdirectory(backend/RISCv64)
# 移除 SysYParser 库的构建(如果不需要独立库)
# add_library(SysYParser SHARED ${ANTLR_SysYGen_CXX_OUTPUTS})
# target_include_directories(SysYParser PUBLIC ${ANTLR_RUNTIME}/runtime/src)
# target_link_libraries(SysYParser PUBLIC antlr4_shared)
# 构建 sysyc 可执行文件,使用手动提供的 SysYLexer.cpp、SysYParser.cpp 等文件
# 构建 sysyc 可执行文件,链接各个模块的库
add_executable(sysyc
sysyc.cpp
SysYLexer.cpp # 手动提供的文件
SysYParser.cpp # 手动提供的文件
SysYVisitor.cpp # 手动提供的文件
IR.cpp
SysYIRGenerator.cpp
SysYIRPrinter.cpp
SysYIROptPre.cpp
SysYIRAnalyser.cpp
# DeadCodeElimination.cpp
AddressCalculationExpansion.cpp
# Mem2Reg.cpp
# Reg2Mem.cpp
RISCv64Backend.cpp
RISCv64ISel.cpp
RISCv64RegAlloc.cpp
RISCv64AsmPrinter.cpp
sysyc.cpp
)
# 设置 include 路径,包含 ANTLR 运行时库和项目头文件
# 链接各个模块的库
target_link_libraries(sysyc PRIVATE
frontend_lib
midend_lib
riscv64_backend_lib
antlr4_shared
)
# 设置 include 路径,包含项目顶层 include 目录
target_include_directories(sysyc PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include # 项目头文件目录
${ANTLR_RUNTIME}/runtime/src # ANTLR 运行时库头文件
)
# 保留 ANTLR 运行时库的链接
target_link_libraries(sysyc PRIVATE antlr4_shared)
# 保留其他编译选项
target_compile_options(sysyc PRIVATE -frtti)
# 可选:线程支持(如果需要,取消注释)
# set(THREADS_PREFER_PTHREAD_FLAG ON)
# find_package(Threads REQUIRED)
# target_link_libraries(sysyc PRIVATE Threads::Threads)
${CMAKE_CURRENT_SOURCE_DIR}/include # 项目头文件目录
${ANTLR_RUNTIME}/runtime/src # ANTLR运行时库头文件
)

View File

@ -1,276 +0,0 @@
#include "DeadCodeElimination.h"
#include <iostream>
extern int DEBUG;
namespace sysy {
void DeadCodeElimination::runDCEPipeline() {
const auto& functions = pModule->getFunctions();
for (const auto& function : functions) {
const auto& func = function.second;
bool changed = true;
while (changed) {
changed = false;
eliminateDeadStores(func.get(), changed);
eliminateDeadLoads(func.get(), changed);
eliminateDeadAllocas(func.get(), changed);
eliminateDeadRedundantLoadStore(func.get(), changed);
eliminateDeadGlobals(changed);
}
}
}
// 消除无用存储 消除条件:
// 存储的目标指针pointer不是全局变量!isGlobal(pointer))。
// 存储的目标指针不是数组参数(!isArr(pointer) 或不在函数参数列表里)。
// 该指针的所有使用者uses仅限 alloca 或 store即没有 load 或其他指令使用它)。
void DeadCodeElimination::eliminateDeadStores(Function* func, bool& changed) {
for (const auto& block : func->getBasicBlocks()) {
auto& instrs = block->getInstructions();
for (auto iter = instrs.begin(); iter != instrs.end();) {
auto inst = iter->get();
if (!inst->isStore()) {
++iter;
continue;
}
auto storeInst = dynamic_cast<StoreInst*>(inst);
auto pointer = storeInst->getPointer();
// 如果是全局变量或者是函数的数组参数
if (isGlobal(pointer) || (isArr(pointer) &&
std::find(func->getEntryBlock()->getArguments().begin(),
func->getEntryBlock()->getArguments().end(),
pointer) != func->getEntryBlock()->getArguments().end())) {
++iter;
continue;
}
bool changetag = true;
for (auto& use : pointer->getUses()) {
// 依次判断store的指针是否被其他指令使用
auto user = use->getUser();
auto userInst = dynamic_cast<Instruction*>(user);
// 如果使用store的指针的指令不是Alloca或Store则不删除
if (userInst != nullptr && !userInst->isAlloca() && !userInst->isStore()) {
changetag = false;
break;
}
}
if (changetag) {
changed = true;
if(DEBUG){
std::cout << "=== Dead Store Found ===\n";
SysYPrinter::printInst(storeInst);
}
usedelete(storeInst);
iter = instrs.erase(iter);
} else {
++iter;
}
}
}
}
// 消除无用加载 消除条件:
// 该指令的结果未被使用inst->getUses().empty())。
void DeadCodeElimination::eliminateDeadLoads(Function* func, bool& changed) {
for (const auto& block : func->getBasicBlocks()) {
auto& instrs = block->getInstructions();
for (auto iter = instrs.begin(); iter != instrs.end();) {
auto inst = iter->get();
if (inst->isBinary() || inst->isUnary() || inst->isLoad()) {
if (inst->getUses().empty()) {
changed = true;
if(DEBUG){
std::cout << "=== Dead Load Binary Unary Found ===\n";
SysYPrinter::printInst(inst);
}
usedelete(inst);
iter = instrs.erase(iter);
continue;
}
}
++iter;
}
}
}
// 消除无用加载 消除条件:
// 该 alloca 未被任何指令使用allocaInst->getUses().empty())。
// 该 alloca 不是函数的参数(不在 entry 块的参数列表里)。
void DeadCodeElimination::eliminateDeadAllocas(Function* func, bool& changed) {
for (const auto& block : func->getBasicBlocks()) {
auto& instrs = block->getInstructions();
for (auto iter = instrs.begin(); iter != instrs.end();) {
auto inst = iter->get();
if (inst->isAlloca()) {
auto allocaInst = dynamic_cast<AllocaInst*>(inst);
if (allocaInst->getUses().empty() &&
std::find(func->getEntryBlock()->getArguments().begin(),
func->getEntryBlock()->getArguments().end(),
allocaInst) == func->getEntryBlock()->getArguments().end()) {
changed = true;
if(DEBUG){
std::cout << "=== Dead Alloca Found ===\n";
SysYPrinter::printInst(inst);
}
usedelete(inst);
iter = instrs.erase(iter);
continue;
}
}
++iter;
}
}
}
void DeadCodeElimination::eliminateDeadIndirectiveAllocas(Function* func, bool& changed) {
// 删除mem2reg时引入的且现在已经没有value使用了的隐式alloca
FunctionAnalysisInfo* funcInfo = pCFA->getFunctionAnalysisInfo(func);
for (auto it = funcInfo->getIndirectAllocas().begin(); it != funcInfo->getIndirectAllocas().end();) {
auto &allocaInst = *it;
if (allocaInst->getUses().empty()) {
changed = true;
if(DEBUG){
std::cout << "=== Dead Indirect Alloca Found ===\n";
SysYPrinter::printInst(allocaInst.get());
}
it = funcInfo->getIndirectAllocas().erase(it);
} else {
++it;
}
}
}
// 该全局变量未被任何指令使用global->getUses().empty())。
void DeadCodeElimination::eliminateDeadGlobals(bool& changed) {
auto& globals = pModule->getGlobals();
for (auto it = globals.begin(); it != globals.end();) {
auto& global = *it;
if (global->getUses().empty()) {
changed = true;
if(DEBUG){
std::cout << "=== Dead Global Found ===\n";
SysYPrinter::printValue(global.get());
}
it = globals.erase(it);
} else {
++it;
}
}
}
// 消除冗余加载和存储 消除条件:
// phi 指令的目标指针仅被该 phi 使用(无其他 store/load 使用)。
// memset 指令的目标指针未被使用pointer->getUses().empty()
// store -> load -> store 模式
void DeadCodeElimination::eliminateDeadRedundantLoadStore(Function* func, bool& changed) {
for (const auto& block : func->getBasicBlocks()) {
auto& instrs = block->getInstructions();
for (auto iter = instrs.begin(); iter != instrs.end();) {
auto inst = iter->get();
if (inst->isPhi()) {
auto phiInst = dynamic_cast<PhiInst*>(inst);
auto pointer = phiInst->getPointer();
bool tag = true;
for (const auto& use : pointer->getUses()) {
auto user = use->getUser();
if (user != inst) {
tag = false;
break;
}
}
/// 如果 pointer 仅被该 phi 使用,可以删除 ph
if (tag) {
changed = true;
usedelete(inst);
iter = instrs.erase(iter);
continue;
}
// 数组指令还不完善不保证memset优化效果
} else if (inst->isMemset()) {
auto memsetInst = dynamic_cast<MemsetInst*>(inst);
auto pointer = memsetInst->getPointer();
if (pointer->getUses().empty()) {
changed = true;
usedelete(inst);
iter = instrs.erase(iter);
continue;
}
}else if(inst->isLoad()) {
if (iter != instrs.begin()) {
auto loadInst = dynamic_cast<LoadInst*>(inst);
auto loadPointer = loadInst->getPointer();
// TODO:store -> load -> store 模式
auto prevIter = std::prev(iter);
auto prevInst = prevIter->get();
if (prevInst->isStore()) {
auto prevStore = dynamic_cast<StoreInst*>(prevInst);
auto prevStorePointer = prevStore->getPointer();
auto prevStoreValue = prevStore->getOperand(0);
// 确保前一个 store 不是数组操作
if (prevStore->getIndices().empty()) {
// 检查后一条指令是否是 store 同一个值
auto nextIter = std::next(iter);
if (nextIter != instrs.end()) {
auto nextInst = nextIter->get();
if (nextInst->isStore()) {
auto nextStore = dynamic_cast<StoreInst*>(nextInst);
auto nextStorePointer = nextStore->getPointer();
auto nextStoreValue = nextStore->getOperand(0);
// 确保后一个 store 不是数组操作
if (nextStore->getIndices().empty()) {
// 判断优化条件:
// 1. prevStore 的指针操作数 == load 的指针操作数
// 2. nextStore 的值操作数 == load 指令本身
if (prevStorePointer == loadPointer &&
nextStoreValue == loadInst) {
// 可以优化直接把prevStorePointer的值存到nextStorePointer
changed = true;
nextStore->setOperand(0, prevStoreValue);
if(DEBUG){
std::cout << "=== Dead Store Load Store Found(now only del Load) ===\n";
SysYPrinter::printInst(prevStore);
SysYPrinter::printInst(loadInst);
SysYPrinter::printInst(nextStore);
}
usedelete(loadInst);
iter = instrs.erase(iter);
// 删除 prevStore 这里是不是可以留给删除无用store处理
// if (prevStore->getUses().empty()) {
// usedelete(prevStore);
// instrs.erase(prevIter); // 删除 prevStore
// }
continue; // 跳过 ++iter因为已经移动迭代器
}
}
}
}
}
}
}
}
++iter;
}
}
}
bool DeadCodeElimination::isGlobal(Value *val){
auto gval = dynamic_cast<GlobalValue *>(val);
return gval != nullptr;
}
bool DeadCodeElimination::isArr(Value *val){
auto aval = dynamic_cast<AllocaInst *>(val);
return aval != nullptr && aval->getNumDims() != 0;
}
void DeadCodeElimination::usedelete(Instruction *instr){
for (auto &use1 : instr->getOperands()) {
auto val1 = use1->getValue();
val1->removeUse(use1);
}
}
} // namespace sysy

View File

@ -1,750 +0,0 @@
#include "IR.h"
#include <algorithm>
#include <cassert>
#include <memory>
#include <queue>
#include <set>
#include <sstream>
#include <vector>
#include "IRBuilder.h"
/**
* @file IR.cpp
*
* @brief 定义IR相关类型与操作的源文件
*/
namespace sysy {
//===----------------------------------------------------------------------===//
// Types
//===----------------------------------------------------------------------===//
auto Type::getIntType() -> Type * {
static Type intType(kInt);
return &intType;
}
auto Type::getFloatType() -> Type * {
static Type floatType(kFloat);
return &floatType;
}
auto Type::getVoidType() -> Type * {
static Type voidType(kVoid);
return &voidType;
}
auto Type::getLabelType() -> Type * {
static Type labelType(kLabel);
return &labelType;
}
auto Type::getPointerType(Type *baseType) -> Type * {
// forward to PointerType
return PointerType::get(baseType);
}
auto Type::getFunctionType(Type *returnType, const std::vector<Type *> &paramTypes) -> Type * {
// forward to FunctionType
return FunctionType::get(returnType, paramTypes);
}
auto Type::getSize() const -> unsigned {
switch (kind) {
case kInt:
case kFloat:
return 4;
case kLabel:
case kPointer:
case kFunction:
return 8;
case kVoid:
return 0;
}
return 0;
}
PointerType* PointerType::get(Type *baseType) {
static std::map<Type *, std::unique_ptr<PointerType>> pointerTypes;
auto iter = pointerTypes.find(baseType);
if (iter != pointerTypes.end()) {
return iter->second.get();
}
auto type = new PointerType(baseType);
assert(type);
auto result = pointerTypes.emplace(baseType, type);
return result.first->second.get();
}
FunctionType*FunctionType::get(Type *returnType, const std::vector<Type *> &paramTypes) {
static std::set<std::unique_ptr<FunctionType>> functionTypes;
auto iter =
std::find_if(functionTypes.begin(), functionTypes.end(), [&](const std::unique_ptr<FunctionType> &type) -> bool {
if (returnType != type->getReturnType() ||
paramTypes.size() != static_cast<size_t>(type->getParamTypes().size())) {
return false;
}
return std::equal(paramTypes.begin(), paramTypes.end(), type->getParamTypes().begin());
});
if (iter != functionTypes.end()) {
return iter->get();
}
auto type = new FunctionType(returnType, paramTypes);
assert(type);
auto result = functionTypes.emplace(type);
return result.first->get();
}
void Value::replaceAllUsesWith(Value *value) {
for (auto &use : uses) {
use->getUser()->setOperand(use->getIndex(), value);
}
uses.clear();
}
// Implementations for static members
std::unordered_map<ConstantValueKey, ConstantValue*, ConstantValueHash, ConstantValueEqual> ConstantValue::mConstantPool;
std::unordered_map<Type*, UndefinedValue*> UndefinedValue::UndefValues;
ConstantValue* ConstantValue::get(Type* type, ConstantValVariant val) {
ConstantValueKey key = {type, val};
auto it = mConstantPool.find(key);
if (it != mConstantPool.end()) {
return it->second;
}
ConstantValue* newConstant = nullptr;
if (std::holds_alternative<int>(val)) {
newConstant = new ConstantInteger(type, std::get<int>(val));
} else if (std::holds_alternative<float>(val)) {
newConstant = new ConstantFloating(type, std::get<float>(val));
} else {
assert(false && "Unsupported ConstantValVariant type");
}
mConstantPool[key] = newConstant;
return newConstant;
}
ConstantInteger* ConstantInteger::get(Type* type, int val) {
return dynamic_cast<ConstantInteger*>(ConstantValue::get(type, val));
}
ConstantFloating* ConstantFloating::get(Type* type, float val) {
return dynamic_cast<ConstantFloating*>(ConstantValue::get(type, val));
}
UndefinedValue* UndefinedValue::get(Type* type) {
assert(!type->isVoid() && "Cannot get UndefinedValue of void type!");
auto it = UndefValues.find(type);
if (it != UndefValues.end()) {
return it->second;
}
UndefinedValue* newUndef = new UndefinedValue(type);
UndefValues[type] = newUndef;
return newUndef;
}
auto Function::getCalleesWithNoExternalAndSelf() -> std::set<Function *> {
std::set<Function *> result;
for (auto callee : callees) {
if (parent->getExternalFunctions().count(callee->getName()) == 0U && callee != this) {
result.insert(callee);
}
}
return result;
}
// 函数克隆,后续函数级优化(内联等)需要用到
Function * Function::clone(const std::string &suffix) const {
std::stringstream ss;
std::map<BasicBlock *, BasicBlock *> oldNewBlockMap;
IRBuilder builder;
auto newFunction = new Function(parent, type, name);
newFunction->getEntryBlock()->setName(blocks.front()->getName());
oldNewBlockMap.emplace(blocks.front().get(), newFunction->getEntryBlock());
auto oldBlockListIter = std::next(blocks.begin());
while (oldBlockListIter != blocks.end()) {
auto newBlock = newFunction->addBasicBlock(oldBlockListIter->get()->getName());
oldNewBlockMap.emplace(oldBlockListIter->get(), newBlock);
oldBlockListIter++;
}
for (const auto &oldNewBlockItem : oldNewBlockMap) {
auto oldBlock = oldNewBlockItem.first;
auto newBlock = oldNewBlockItem.second;
for (const auto &oldPred : oldBlock->getPredecessors()) {
newBlock->addPredecessor(oldNewBlockMap.at(oldPred));
}
for (const auto &oldSucc : oldBlock->getSuccessors()) {
newBlock->addSuccessor(oldNewBlockMap.at(oldSucc));
}
}
std::map<Value *, Value *> oldNewValueMap;
std::map<Value *, bool> isAddedToCreate;
std::map<Value *, bool> isCreated;
std::queue<Value *> toCreate;
for (const auto &oldBlock : blocks) {
for (const auto &inst : oldBlock->getInstructions()) {
isAddedToCreate.emplace(inst.get(), false);
isCreated.emplace(inst.get(), false);
}
}
for (const auto &oldBlock : blocks) {
for (const auto &inst : oldBlock->getInstructions()) {
for (const auto &valueUse : inst->getOperands()) {
auto value = valueUse->getValue();
if (oldNewValueMap.find(value) == oldNewValueMap.end()) {
auto oldAllocInst = dynamic_cast<AllocaInst *>(value);
if (oldAllocInst != nullptr) {
std::vector<Value *> dims;
for (const auto &dim : oldAllocInst->getDims()) {
dims.emplace_back(dim->getValue());
}
ss << oldAllocInst->getName() << suffix;
auto newAllocInst =
new AllocaInst(oldAllocInst->getType(), dims, oldNewBlockMap.at(oldAllocInst->getParent()), ss.str());
ss.str("");
oldNewValueMap.emplace(oldAllocInst, newAllocInst);
if (isAddedToCreate.find(oldAllocInst) == isAddedToCreate.end()) {
isAddedToCreate.emplace(oldAllocInst, true);
} else {
isAddedToCreate.at(oldAllocInst) = true;
}
if (isCreated.find(oldAllocInst) == isCreated.end()) {
isCreated.emplace(oldAllocInst, true);
} else {
isCreated.at(oldAllocInst) = true;
}
}
}
}
if (inst->getKind() == Instruction::kAlloca) {
if (oldNewValueMap.find(inst.get()) == oldNewValueMap.end()) {
auto oldAllocInst = dynamic_cast<AllocaInst *>(inst.get());
std::vector<Value *> dims;
for (const auto &dim : oldAllocInst->getDims()) {
dims.emplace_back(dim->getValue());
}
ss << oldAllocInst->getName() << suffix;
auto newAllocInst =
new AllocaInst(oldAllocInst->getType(), dims, oldNewBlockMap.at(oldAllocInst->getParent()), ss.str());
ss.str("");
oldNewValueMap.emplace(oldAllocInst, newAllocInst);
if (isAddedToCreate.find(oldAllocInst) == isAddedToCreate.end()) {
isAddedToCreate.emplace(oldAllocInst, true);
} else {
isAddedToCreate.at(oldAllocInst) = true;
}
if (isCreated.find(oldAllocInst) == isCreated.end()) {
isCreated.emplace(oldAllocInst, true);
} else {
isCreated.at(oldAllocInst) = true;
}
}
}
}
}
for (const auto &oldBlock : blocks) {
for (const auto &inst : oldBlock->getInstructions()) {
for (const auto &valueUse : inst->getOperands()) {
auto value = valueUse->getValue();
if (oldNewValueMap.find(value) == oldNewValueMap.end()) {
auto globalValue = dynamic_cast<GlobalValue *>(value);
auto constVariable = dynamic_cast<ConstantVariable *>(value);
auto constantValue = dynamic_cast<ConstantValue *>(value);
auto functionValue = dynamic_cast<Function *>(value);
if (globalValue != nullptr || constantValue != nullptr || constVariable != nullptr ||
functionValue != nullptr) {
if (functionValue == this) {
oldNewValueMap.emplace(value, newFunction);
} else {
oldNewValueMap.emplace(value, value);
}
isCreated.emplace(value, true);
isAddedToCreate.emplace(value, true);
}
}
}
}
}
for (const auto &oldBlock : blocks) {
for (const auto &inst : oldBlock->getInstructions()) {
if (inst->getKind() != Instruction::kAlloca) {
bool isReady = true;
for (const auto &use : inst->getOperands()) {
auto value = use->getValue();
if (dynamic_cast<BasicBlock *>(value) == nullptr && !isCreated.at(value)) {
isReady = false;
break;
}
}
if (isReady) {
toCreate.push(inst.get());
isAddedToCreate.at(inst.get()) = true;
}
}
}
}
while (!toCreate.empty()) {
auto inst = dynamic_cast<Instruction *>(toCreate.front());
toCreate.pop();
bool isReady = true;
for (const auto &valueUse : inst->getOperands()) {
auto value = dynamic_cast<Instruction *>(valueUse->getValue());
if (value != nullptr && !isCreated.at(value)) {
isReady = false;
break;
}
}
if (!isReady) {
toCreate.push(inst);
continue;
}
isCreated.at(inst) = true;
switch (inst->getKind()) {
case Instruction::kAdd:
case Instruction::kSub:
case Instruction::kMul:
case Instruction::kDiv:
case Instruction::kRem:
case Instruction::kICmpEQ:
case Instruction::kICmpNE:
case Instruction::kICmpLT:
case Instruction::kICmpGT:
case Instruction::kICmpLE:
case Instruction::kICmpGE:
case Instruction::kAnd:
case Instruction::kOr:
case Instruction::kFAdd:
case Instruction::kFSub:
case Instruction::kFMul:
case Instruction::kFDiv:
case Instruction::kFCmpEQ:
case Instruction::kFCmpNE:
case Instruction::kFCmpLT:
case Instruction::kFCmpGT:
case Instruction::kFCmpLE:
case Instruction::kFCmpGE: {
auto oldBinaryInst = dynamic_cast<BinaryInst *>(inst);
auto lhs = oldBinaryInst->getLhs();
auto rhs = oldBinaryInst->getRhs();
Value *newLhs;
Value *newRhs;
newLhs = oldNewValueMap[lhs];
newRhs = oldNewValueMap[rhs];
ss << oldBinaryInst->getName() << suffix;
auto newBinaryInst = new BinaryInst(oldBinaryInst->getKind(), oldBinaryInst->getType(), newLhs, newRhs,
oldNewBlockMap.at(oldBinaryInst->getParent()), ss.str());
ss.str("");
oldNewValueMap.emplace(oldBinaryInst, newBinaryInst);
break;
}
case Instruction::kNeg:
case Instruction::kNot:
case Instruction::kFNeg:
case Instruction::kFNot:
case Instruction::kItoF:
case Instruction::kFtoI: {
auto oldUnaryInst = dynamic_cast<UnaryInst *>(inst);
auto hs = oldUnaryInst->getOperand();
Value *newHs;
newHs = oldNewValueMap.at(hs);
ss << oldUnaryInst->getName() << suffix;
auto newUnaryInst = new UnaryInst(oldUnaryInst->getKind(), oldUnaryInst->getType(), newHs,
oldNewBlockMap.at(oldUnaryInst->getParent()), ss.str());
ss.str("");
oldNewValueMap.emplace(oldUnaryInst, newUnaryInst);
break;
}
case Instruction::kCall: {
auto oldCallInst = dynamic_cast<CallInst *>(inst);
std::vector<Value *> newArgumnts;
for (const auto &arg : oldCallInst->getArguments()) {
newArgumnts.emplace_back(oldNewValueMap.at(arg->getValue()));
}
ss << oldCallInst->getName() << suffix;
CallInst *newCallInst;
newCallInst =
new CallInst(oldCallInst->getCallee(), newArgumnts, oldNewBlockMap.at(oldCallInst->getParent()), ss.str());
ss.str("");
// if (oldCallInst->getCallee() != this) {
// newCallInst = new CallInst(oldCallInst->getCallee(), newArgumnts,
// oldNewBlockMap.at(oldCallInst->getParent()),
// oldCallInst->getName());
// } else {
// newCallInst = new CallInst(newFunction, newArgumnts, oldNewBlockMap.at(oldCallInst->getParent()),
// oldCallInst->getName());
// }
oldNewValueMap.emplace(oldCallInst, newCallInst);
break;
}
case Instruction::kCondBr: {
auto oldCondBrInst = dynamic_cast<CondBrInst *>(inst);
auto oldCond = oldCondBrInst->getCondition();
Value *newCond;
newCond = oldNewValueMap.at(oldCond);
auto newCondBrInst = new CondBrInst(newCond, oldNewBlockMap.at(oldCondBrInst->getThenBlock()),
oldNewBlockMap.at(oldCondBrInst->getElseBlock()), {}, {},
oldNewBlockMap.at(oldCondBrInst->getParent()));
oldNewValueMap.emplace(oldCondBrInst, newCondBrInst);
break;
}
case Instruction::kBr: {
auto oldBrInst = dynamic_cast<UncondBrInst *>(inst);
auto newBrInst =
new UncondBrInst(oldNewBlockMap.at(oldBrInst->getBlock()), {}, oldNewBlockMap.at(oldBrInst->getParent()));
oldNewValueMap.emplace(oldBrInst, newBrInst);
break;
}
case Instruction::kReturn: {
auto oldReturnInst = dynamic_cast<ReturnInst *>(inst);
auto oldRval = oldReturnInst->getReturnValue();
Value *newRval = nullptr;
if (oldRval != nullptr) {
newRval = oldNewValueMap.at(oldRval);
}
auto newReturnInst =
new ReturnInst(newRval, oldNewBlockMap.at(oldReturnInst->getParent()), oldReturnInst->getName());
oldNewValueMap.emplace(oldReturnInst, newReturnInst);
break;
}
case Instruction::kAlloca: {
assert(false);
}
case Instruction::kLoad: {
auto oldLoadInst = dynamic_cast<LoadInst *>(inst);
auto oldPointer = oldLoadInst->getPointer();
Value *newPointer;
newPointer = oldNewValueMap.at(oldPointer);
std::vector<Value *> newIndices;
for (const auto &index : oldLoadInst->getIndices()) {
newIndices.emplace_back(oldNewValueMap.at(index->getValue()));
}
ss << oldLoadInst->getName() << suffix;
auto newLoadInst = new LoadInst(newPointer, newIndices, oldNewBlockMap.at(oldLoadInst->getParent()), ss.str());
ss.str("");
oldNewValueMap.emplace(oldLoadInst, newLoadInst);
break;
}
case Instruction::kStore: {
auto oldStoreInst = dynamic_cast<StoreInst *>(inst);
auto oldPointer = oldStoreInst->getPointer();
auto oldValue = oldStoreInst->getValue();
Value *newPointer;
Value *newValue;
std::vector<Value *> newIndices;
newPointer = oldNewValueMap.at(oldPointer);
newValue = oldNewValueMap.at(oldValue);
for (const auto &index : oldStoreInst->getIndices()) {
newIndices.emplace_back(oldNewValueMap.at(index->getValue()));
}
auto newStoreInst = new StoreInst(newValue, newPointer, newIndices,
oldNewBlockMap.at(oldStoreInst->getParent()), oldStoreInst->getName());
oldNewValueMap.emplace(oldStoreInst, newStoreInst);
break;
}
case Instruction::kLa: {
auto oldLaInst = dynamic_cast<LaInst *>(inst);
auto oldPointer = oldLaInst->getPointer();
Value *newPointer;
std::vector<Value *> newIndices;
newPointer = oldNewValueMap.at(oldPointer);
for (const auto &index : oldLaInst->getIndices()) {
newIndices.emplace_back(oldNewValueMap.at(index->getValue()));
}
ss << oldLaInst->getName() << suffix;
auto newLaInst = new LaInst(newPointer, newIndices, oldNewBlockMap.at(oldLaInst->getParent()), ss.str());
ss.str("");
oldNewValueMap.emplace(oldLaInst, newLaInst);
break;
}
case Instruction::kGetSubArray: {
auto oldGetSubArrayInst = dynamic_cast<GetSubArrayInst *>(inst);
auto oldFather = oldGetSubArrayInst->getFatherArray();
auto oldChild = oldGetSubArrayInst->getChildArray();
Value *newFather;
Value *newChild;
std::vector<Value *> newIndices;
newFather = oldNewValueMap.at(oldFather);
newChild = oldNewValueMap.at(oldChild);
for (const auto &index : oldGetSubArrayInst->getIndices()) {
newIndices.emplace_back(oldNewValueMap.at(index->getValue()));
}
ss << oldGetSubArrayInst->getName() << suffix;
auto newGetSubArrayInst =
new GetSubArrayInst(dynamic_cast<LVal *>(newFather), dynamic_cast<LVal *>(newChild), newIndices,
oldNewBlockMap.at(oldGetSubArrayInst->getParent()), ss.str());
ss.str("");
oldNewValueMap.emplace(oldGetSubArrayInst, newGetSubArrayInst);
break;
}
case Instruction::kMemset: {
auto oldMemsetInst = dynamic_cast<MemsetInst *>(inst);
auto oldPointer = oldMemsetInst->getPointer();
auto oldValue = oldMemsetInst->getValue();
Value *newPointer;
Value *newValue;
newPointer = oldNewValueMap.at(oldPointer);
newValue = oldNewValueMap.at(oldValue);
auto newMemsetInst = new MemsetInst(newPointer, oldMemsetInst->getBegin(), oldMemsetInst->getSize(), newValue,
oldNewBlockMap.at(oldMemsetInst->getParent()), oldMemsetInst->getName());
oldNewValueMap.emplace(oldMemsetInst, newMemsetInst);
break;
}
case Instruction::kInvalid:
case Instruction::kPhi: {
break;
}
default:
assert(false);
}
for (const auto &userUse : inst->getUses()) {
auto user = userUse->getUser();
if (!isAddedToCreate.at(user)) {
toCreate.push(user);
isAddedToCreate.at(user) = true;
}
}
}
for (const auto &oldBlock : blocks) {
auto newBlock = oldNewBlockMap.at(oldBlock.get());
builder.setPosition(newBlock, newBlock->end());
for (const auto &inst : oldBlock->getInstructions()) {
builder.insertInst(dynamic_cast<Instruction *>(oldNewValueMap.at(inst.get())));
}
}
for (const auto &param : blocks.front()->getArguments()) {
newFunction->getEntryBlock()->insertArgument(dynamic_cast<AllocaInst *>(oldNewValueMap.at(param)));
}
return newFunction;
}
/**
* 设置操作数
*/
void User::setOperand(unsigned index, Value *value) {
assert(index < getNumOperands());
operands[index]->setValue(value);
value->addUse(operands[index]);
}
/**
* 替换操作数
*/
void User::replaceOperand(unsigned index, Value *value) {
assert(index < getNumOperands());
auto &use = operands[index];
use->getValue()->removeUse(use);
use->setValue(value);
value->addUse(use);
}
/**
* phi相关函数
*/
Value* PhiInst::getvalfromBlk(BasicBlock* blk){
refreshB2VMap();
if( blk2val.find(blk) != blk2val.end()) {
return blk2val.at(blk);
}
return nullptr;
}
BasicBlock* PhiInst::getBlkfromVal(Value* val){
// 返回第一个值对应的基本块
for(unsigned i = 0; i < vsize; i++) {
if(getValue(i) == val) {
return getBlock(i);
}
}
return nullptr;
}
void PhiInst::delValue(Value* val){
//根据value删除对应的基本块和值
unsigned i = 0;
BasicBlock* blk = getBlkfromVal(val);
for(i = 0; i < vsize; i++) {
if(getValue(i) == val) {
break;
}
}
removeOperand(2 * i + 1); // 删除blk
removeOperand(2 * i); // 删除val
vsize--;
blk2val.erase(blk); // 删除blk2val映射
}
void PhiInst::delBlk(BasicBlock* blk){
//根据Blk删除对应的基本块和值
unsigned i = 0;
Value* val = getvalfromBlk(blk);
for(i = 0; i < vsize; i++) {
if(getBlock(i) == blk) {
break;
}
}
removeOperand(2 * i + 1); // 删除blk
removeOperand(2 * i); // 删除val
vsize--;
blk2val.erase(blk); // 删除blk2val映射
}
void PhiInst::replaceBlk(BasicBlock* newBlk, unsigned k){
refreshB2VMap();
Value* val = blk2val.at(getBlock(k));
// 替换基本块
setOperand(2 * k + 1, newBlk);
// 替换blk2val映射
blk2val.erase(getBlock(k));
blk2val.emplace(newBlk, val);
}
void PhiInst::replaceold2new(BasicBlock* oldBlk, BasicBlock* newBlk){
refreshB2VMap();
Value* val = blk2val.at(oldBlk);
// 替换基本块
delBlk(oldBlk);
addIncoming(val, newBlk);
}
void PhiInst::refreshB2VMap(){
blk2val.clear();
for(unsigned i = 0; i < vsize; i++) {
blk2val.emplace(getBlock(i), getValue(i));
}
}
CallInst::CallInst(Function *callee, const std::vector<Value *> &args, BasicBlock *parent, const std::string &name)
: Instruction(kCall, callee->getReturnType(), parent, name) {
addOperand(callee);
for (auto arg : args) {
addOperand(arg);
}
}
/**
* 获取被调用函数的指针
*/
Function * CallInst::getCallee() const { return dynamic_cast<Function *>(getOperand(0)); }
/**
* 获取变量指针
*/
auto SymbolTable::getVariable(const std::string &name) const -> User * {
auto node = curNode;
while (node != nullptr) {
auto iter = node->varList.find(name);
if (iter != node->varList.end()) {
return iter->second;
}
node = node->pNode;
}
return nullptr;
}
/**
* 添加变量到符号表
*/
auto SymbolTable::addVariable(const std::string &name, User *variable) -> User * {
User *result = nullptr;
if (curNode != nullptr) {
std::stringstream ss;
auto iter = variableIndex.find(name);
if (iter != variableIndex.end()) {
ss << name << iter->second ;
iter->second += 1;
} else {
variableIndex.emplace(name, 1);
ss << name << 0 ;
}
variable->setName(ss.str());
curNode->varList.emplace(name, variable);
auto global = dynamic_cast<GlobalValue *>(variable);
auto constvar = dynamic_cast<ConstantVariable *>(variable);
if (global != nullptr) {
globals.emplace_back(global);
} else if (constvar != nullptr) {
consts.emplace_back(constvar);
}
result = variable;
}
return result;
}
/**
* 获取全局变量
*/
auto SymbolTable::getGlobals() -> std::vector<std::unique_ptr<GlobalValue>> & { return globals; }
/**
* 获取常量
*/
auto SymbolTable::getConsts() const -> const std::vector<std::unique_ptr<ConstantVariable>> & { return consts; }
/**
* 进入新的作用域
*/
void SymbolTable::enterNewScope() {
auto newNode = new SymbolTableNode;
nodeList.emplace_back(newNode);
if (curNode != nullptr) {
curNode->children.emplace_back(newNode);
}
newNode->pNode = curNode;
curNode = newNode;
}
/**
* 进入全局作用域
*/
void SymbolTable::enterGlobalScope() { curNode = nodeList.front().get(); }
/**
* 离开作用域
*/
void SymbolTable::leaveScope() { curNode = curNode->pNode; }
/**
* 是否位于全局作用域
*/
auto SymbolTable::isInGlobalScope() const -> bool { return curNode->pNode == nullptr; }
/**
*移动指令
*/
auto BasicBlock::moveInst(iterator sourcePos, iterator targetPos, BasicBlock *block) -> iterator {
auto inst = sourcePos->release();
inst->setParent(block);
block->instructions.emplace(targetPos, inst);
return instructions.erase(sourcePos);
}
} // namespace sysy

View File

@ -1,801 +0,0 @@
#include "Mem2Reg.h"
#include <algorithm>
#include <cassert>
#include <iterator>
#include <memory>
#include <queue>
#include <stack>
#include <string>
#include <unordered_map>
#include <utility>
#include "IR.h"
#include "SysYIRAnalyser.h"
#include "SysYIRPrinter.h"
namespace sysy {
// 计算给定变量的定义块集合的迭代支配边界
// TODO优化Semi-Naive IDF
std::unordered_set<BasicBlock *> Mem2Reg::computeIterDf(const std::unordered_set<BasicBlock *> &blocks) {
std::unordered_set<BasicBlock *> workList;
std::unordered_set<BasicBlock *> ret_list;
workList.insert(blocks.begin(), blocks.end());
while (!workList.empty()) {
auto n = workList.begin();
BlockAnalysisInfo* blockInfo = controlFlowAnalysis->getBlockAnalysisInfo(*n);
auto DFs = blockInfo->getDomFrontiers();
for (auto c : DFs) {
// 如果c不在ret_list中则将其加入ret_list和workList
// 这里的c是n的支配边界
// 也就是n的支配边界中的块
// 需要注意的是,支配边界是一个集合,所以可能会有重复
if (ret_list.count(c) == 0U) {
ret_list.emplace(c);
workList.emplace(c);
}
}
workList.erase(n);
}
return ret_list;
}
/**
* 计算value2Blocks的映射包括value2AllocBlocks、value2DefBlocks以及value2UseBlocks
* 其中value2DefBlocks可用于计算迭代支配边界来插入相应变量的phi结点
* 这里的value2AllocBlocks、value2DefBlocks和value2UseBlocks改变了函数级别的分析信息
*/
auto Mem2Reg::computeValue2Blocks() -> void {
SysYPrinter printer(pModule); // 初始化打印机
// std::cout << "===== Start computeValue2Blocks =====" << std::endl;
auto &functions = pModule->getFunctions();
for (const auto &function : functions) {
auto func = function.second.get();
// std::cout << "\nProcessing function: " << func->getName() << std::endl;
FunctionAnalysisInfo* funcInfo = controlFlowAnalysis->getFunctionAnalysisInfo(func);
if (!funcInfo) {
std::cerr << "ERROR: No analysis info for function " << func->getName() << std::endl;
continue;
}
auto basicBlocks = func->getBasicBlocks();
// std::cout << "BasicBlocks count: " << basicBlocks.size() << std::endl;
for (auto &it : basicBlocks) {
auto basicBlock = it.get();
// std::cout << "\nProcessing BB: " << basicBlock->getName() << std::endl;
// printer.printBlock(basicBlock); // 打印基本块内容
auto &instrs = basicBlock->getInstructions();
for (auto &instr : instrs) {
// std::cout << " Analyzing instruction: ";
// printer.printInst(instr.get());
// std::cout << std::endl;
if (instr->isAlloca()) {
if (!(isArr(instr.get()) || isGlobal(instr.get()))) {
// std::cout << " Found alloca: ";
// printer.printInst(instr.get());
// std::cout << " -> Adding to allocBlocks" << std::endl;
funcInfo->addValue2AllocBlocks(instr.get(), basicBlock);
} else {
// std::cout << " Skip array/global alloca: ";
// printer.printInst(instr.get());
// std::cout << std::endl;
}
}
else if (instr->isStore()) {
auto val = instr->getOperand(1);
// std::cout << " Store target: ";
// printer.printInst(dynamic_cast<Instruction *>(val));
if (!(isArr(val) || isGlobal(val))) {
// std::cout << " Adding store to defBlocks for value: ";
// printer.printInst(dynamic_cast<Instruction *>(instr.get()));
// std::cout << std::endl;
// 将store的目标值添加到defBlocks中
funcInfo->addValue2DefBlocks(val, basicBlock);
} else {
// std::cout << " Skip array/global store" << std::endl;
}
}
else if (instr->isLoad()) {
auto val = instr->getOperand(0);
// std::cout << " Load source: ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// std::cout << std::endl;
if (!(isArr(val) || isGlobal(val))) {
// std::cout << " Adding load to useBlocks for value: ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// std::cout << std::endl;
funcInfo->addValue2UseBlocks(val, basicBlock);
} else {
// std::cout << " Skip array/global load" << std::endl;
}
}
}
}
// 打印分析结果
// std::cout << "\nAnalysis results for function " << func->getName() << ":" << std::endl;
// auto &allocMap = funcInfo->getValue2AllocBlocks();
// std::cout << "AllocBlocks (" << allocMap.size() << "):" << std::endl;
// for (auto &[val, bb] : allocMap) {
// std::cout << " ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// std::cout << " in BB: " << bb->getName() << std::endl;
// }
// auto &defMap = funcInfo->getValue2DefBlocks();
// std::cout << "DefBlocks (" << defMap.size() << "):" << std::endl;
// for (auto &[val, bbs] : defMap) {
// std::cout << " ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// for (const auto &[bb, count] : bbs) {
// std::cout << " in BB: " << bb->getName() << " (count: " << count << ")";
// }
// }
// auto &useMap = funcInfo->getValue2UseBlocks();
// std::cout << "UseBlocks (" << useMap.size() << "):" << std::endl;
// for (auto &[val, bbs] : useMap) {
// std::cout << " ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// for (const auto &[bb, count] : bbs) {
// std::cout << " in BB: " << bb->getName() << " (count: " << count << ")";
// }
// }
}
// std::cout << "===== End computeValue2Blocks =====" << std::endl;
}
/**
* @brief 级联关系的顺带消除用于llvm mem2reg类预优化1
*
* 采用队列进行模拟从某种程度上来看其实可以看作是UD链的反向操作
*
* @param [in] instr store指令使用的指令
* @param [in] changed 不动点法的判断标准,地址传递
* @param [in] func 指令所在函数
* @param [in] block 指令所在基本块
* @param [in] instrs 基本块所在指令集合,地址传递
* @return 无返回值,但满足条件的情况下会对指令进行删除
*/
auto Mem2Reg::cascade(Instruction *instr, bool &changed, Function *func, BasicBlock *block,
std::list<std::unique_ptr<Instruction>> &instrs) -> void {
if (instr != nullptr) {
if (instr->isUnary() || instr->isBinary() || instr->isLoad()) {
std::queue<Instruction *> toRemove;
toRemove.push(instr);
while (!toRemove.empty()) {
auto top = toRemove.front();
toRemove.pop();
auto operands = top->getOperands();
for (const auto &operand : operands) {
auto elem = dynamic_cast<Instruction *>(operand->getValue());
if (elem != nullptr) {
if ((elem->isUnary() || elem->isBinary() || elem->isLoad()) && elem->getUses().size() == 1 &&
elem->getUses().front()->getUser() == top) {
toRemove.push(elem);
} else if (elem->isAlloca()) {
// value2UseBlock中该block对应次数-1如果该变量的该useblock中count减为0了则意味着
// 该block其他地方也没用到该alloc了故从value2UseBlock中删除
FunctionAnalysisInfo* funcInfo = controlFlowAnalysis->getFunctionAnalysisInfo(func);
auto res = funcInfo->removeValue2UseBlock(elem, block);
// 只要有一次返回了true就说明有变化
if (res) {
changed = true;
}
}
}
}
auto tofind =
std::find_if(instrs.begin(), instrs.end(), [&top](const auto &instr) { return instr.get() == top; });
assert(tofind != instrs.end());
usedelete(tofind->get());
instrs.erase(tofind);
}
}
}
}
/**
* llvm mem2reg预优化1: 删除不含load的alloc和store
*
* 1. 删除不含load的alloc和store
* 2. 删除store指令之前的用于作store指令第0个操作数的那些级联指令就冗余了也要删除
* 3. 删除之后可能有些变量的load使用恰好又没有了因此再次从第一步开始循环这里使用不动点法
*
* 由于删除了级联关系,所以这里的方法有点儿激进;
* 同时也考虑了级联关系时如果调用了函数可能会有side effect所以没有删除调用函数的级联关系
* 而且关于函数参数的alloca不会在指令中删除也不会在value2Alloca中删除;
* 同样地我们不考虑数组和global不过这里的代码是基于value2blocks的在value2blocks中已经考虑了所以不用显式指明
*=
*/
auto Mem2Reg::preOptimize1() -> void {
SysYPrinter printer(pModule); // 初始化打印机
auto &functions = pModule->getFunctions();
// std::cout << "===== Start preOptimize1 =====" << std::endl;
for (const auto &function : functions) {
auto func = function.second.get();
// std::cout << "\nProcessing function: " << func->getName() << std::endl;
FunctionAnalysisInfo* funcInfo = controlFlowAnalysis->getFunctionAnalysisInfo(func);
if (!funcInfo) {
// std::cerr << "ERROR: No analysis info for function " << func->getName() << std::endl;
continue;
}
auto &vToDefB = funcInfo->getValue2DefBlocks();
auto &vToUseB = funcInfo->getValue2UseBlocks();
auto &vToAllocB = funcInfo->getValue2AllocBlocks();
// 打印初始状态
// std::cout << "Initial allocas: " << vToAllocB.size() << std::endl;
// for (auto &[val, bb] : vToAllocB) {
// std::cout << " Alloca: ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// std::cout << " in BB: " << bb->getName() << std::endl;
// }
// 阶段1删除无store的alloca
// std::cout << "\nPhase 1: Remove unused allocas" << std::endl;
for (auto iter = vToAllocB.begin(); iter != vToAllocB.end();) {
auto val = iter->first;
auto bb = iter->second;
// std::cout << "Checking alloca: ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// std::cout << " in BB: " << bb->getName() << std::endl;
// 如果该alloca没有对应的store指令且不在函数参数中
// 这里的vToDefB是value2DefBlocksvToUseB是value2UseBlocks
// 打印vToDefB
// std::cout << "DefBlocks (" << vToDefB.size() << "):" << std::endl;
// for (auto &[val, bbs] : vToDefB) {
// std::cout << " ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// for (const auto &[bb, count] : bbs) {
// std::cout << " in BB: " << bb->getName() << " (count: " << count << ")" << std::endl;
// }
// }
// std::cout << vToDefB.count(val) << std::endl;
if (vToDefB.count(val) == 0U &&
std::find(func->getEntryBlock()->getArguments().begin(),
func->getEntryBlock()->getArguments().end(),
val) == func->getEntryBlock()->getArguments().end()) {
// std::cout << " Removing unused alloca: ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// std::cout << std::endl;
auto tofind = std::find_if(bb->getInstructions().begin(),
bb->getInstructions().end(),
[val](const auto &instr) {
return instr.get() == val;
});
if (tofind == bb->getInstructions().end()) {
// std::cerr << "ERROR: Alloca not found in BB!" << std::endl;
++iter;
continue;
}
usedelete(tofind->get());
bb->getInstructions().erase(tofind);
iter = vToAllocB.erase(iter);
} else {
++iter;
}
}
// 阶段2删除无load的store
// std::cout << "\nPhase 2: Remove dead stores" << std::endl;
bool changed = true;
int iteration = 0;
while (changed) {
changed = false;
iteration++;
// std::cout << "\nIteration " << iteration << std::endl;
for (auto iter = vToDefB.begin(); iter != vToDefB.end();) {
auto val = iter->first;
// std::cout << "Checking value: ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// std::cout << std::endl;
if (vToUseB.count(val) == 0U) {
// std::cout << " Found dead store for value: ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// std::cout << std::endl;
auto blocks = funcInfo->getDefBlocksByValue(val);
for (auto block : blocks) {
// std::cout << " Processing BB: " << block->getName() << std::endl;
// printer.printBlock(block); // 打印基本块内容
auto &instrs = block->getInstructions();
for (auto it = instrs.begin(); it != instrs.end();) {
if ((*it)->isStore() && (*it)->getOperand(1) == val) {
// std::cout << " Removing store: ";
// printer.printInst(it->get());
std::cout << std::endl;
auto valUsedByStore = dynamic_cast<Instruction *>((*it)->getOperand(0));
usedelete(it->get());
if (valUsedByStore != nullptr &&
valUsedByStore->getUses().size() == 1 &&
valUsedByStore->getUses().front()->getUser() == (*it).get()) {
// std::cout << " Cascade deleting: ";
// printer.printInst(valUsedByStore);
// std::cout << std::endl;
cascade(valUsedByStore, changed, func, block, instrs);
}
it = instrs.erase(it);
changed = true;
} else {
++it;
}
}
}
// 删除对应的alloca
if (std::find(func->getEntryBlock()->getArguments().begin(),
func->getEntryBlock()->getArguments().end(),
val) == func->getEntryBlock()->getArguments().end()) {
auto bb = funcInfo->getAllocBlockByValue(val);
if (bb != nullptr) {
// std::cout << " Removing alloca: ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// std::cout << " in BB: " << bb->getName() << std::endl;
funcInfo->removeValue2AllocBlock(val);
auto tofind = std::find_if(bb->getInstructions().begin(),
bb->getInstructions().end(),
[val](const auto &instr) {
return instr.get() == val;
});
if (tofind != bb->getInstructions().end()) {
usedelete(tofind->get());
bb->getInstructions().erase(tofind);
} else {
std::cerr << "ERROR: Alloca not found in BB!" << std::endl;
}
}
}
iter = vToDefB.erase(iter);
} else {
++iter;
}
}
}
}
// std::cout << "===== End preOptimize1 =====" << std::endl;
}
/**
* llvm mem2reg预优化2: 针对某个变量的Defblocks只有一个块的情况
*
* 1. 该基本块最后一次对该变量的store指令后的所有对该变量的load指令都可以替换为该基本块最后一次store指令的第0个操作数
* 2. 以该基本块为必经结点的结点集合中的对该变量的load指令都可以替换为该基本块最后一次对该变量的store指令的第0个操作数
* 3.
* 如果对该变量的所有load均替换掉了删除该基本块中最后一次store指令如果这个store指令是唯一的define那么再删除alloca指令不删除参数的alloca
* 4.
* 如果对该value的所有load都替换掉了对于该变量剩下还有store的话就转换成了preOptimize1的情况再调用preOptimize1进行删除
*
* 同样不考虑数组和全局变量因为这些变量不会被mem2reg优化在value2blocks中已经考虑了所以不用显式指明
* 替换的操作采用了UD链进行简化和效率的提升
*
*/
auto Mem2Reg::preOptimize2() -> void {
auto &functions = pModule->getFunctions();
for (const auto &function : functions) {
auto func = function.second.get();
FunctionAnalysisInfo* funcInfo = controlFlowAnalysis->getFunctionAnalysisInfo(func);
auto values = funcInfo->getValuesOfDefBlock();
for (auto val : values) {
auto blocks = funcInfo->getDefBlocksByValue(val);
// 该val只有一个defining block
if (blocks.size() == 1) {
auto block = *blocks.begin();
auto &instrs = block->getInstructions();
auto rit = std::find_if(instrs.rbegin(), instrs.rend(),
[val](const auto &instr) { return instr->isStore() && instr->getOperand(1) == val; });
// 注意reverse_iterator求base后是指向下一个指令因此要减一才是原来的指令
assert(rit != instrs.rend());
auto it = --rit.base();
auto propogationVal = (*it)->getOperand(0);
// 其实该块中it后对该val的load指令也可以替换掉了
for (auto curit = std::next(it); curit != instrs.end();) {
if ((*curit)->isLoad() && (*curit)->getOperand(0) == val) {
curit->get()->replaceAllUsesWith(propogationVal);
usedelete(curit->get());
curit = instrs.erase(curit);
funcInfo->removeValue2UseBlock(val, block);
} else {
++curit;
}
}
// 在支配树后继结点中替换load指令的操作数
BlockAnalysisInfo* blockInfo = controlFlowAnalysis->getBlockAnalysisInfo(block);
std::vector<BasicBlock *> blkchildren;
// 获取该块的支配树后继结点
std::queue<BasicBlock *> q;
auto sdoms = blockInfo->getSdoms();
for (auto sdom : sdoms) {
q.push(sdom);
blkchildren.push_back(sdom);
}
while (!q.empty()) {
auto blk = q.front();
q.pop();
BlockAnalysisInfo* blkInfo = controlFlowAnalysis->getBlockAnalysisInfo(blk);
for (auto sdom : blkInfo->getSdoms()) {
q.push(sdom);
blkchildren.push_back(sdom);
}
}
for (auto child : blkchildren) {
auto &childInstrs = child->getInstructions();
for (auto childIter = childInstrs.begin(); childIter != childInstrs.end();) {
if ((*childIter)->isLoad() && (*childIter)->getOperand(0) == val) {
childIter->get()->replaceAllUsesWith(propogationVal);
usedelete(childIter->get());
childIter = childInstrs.erase(childIter);
funcInfo->removeValue2UseBlock(val, child);
} else {
++childIter;
}
}
}
// 如果对该val的所有load均替换掉了那么对于该val的defining block中的最后一个define也可以删除了
// 同时该块中前面对于该val的define也变成死代码了可调用preOptimize1进行删除
if (funcInfo->getUseBlocksByValue(val).empty()) {
usedelete(it->get());
instrs.erase(it);
auto change = funcInfo->removeValue2DefBlock(val, block);
if (change) {
// 如果define是唯一的且不是函数参数的alloca直接删alloca
if (std::find(func->getEntryBlock()->getArguments().begin(), func->getEntryBlock()->getArguments().end(),
val) == func->getEntryBlock()->getArguments().end()) {
auto bb = funcInfo->getAllocBlockByValue(val);
assert(bb != nullptr);
auto tofind = std::find_if(bb->getInstructions().begin(), bb->getInstructions().end(),
[val](const auto &instr) { return instr.get() == val; });
usedelete(tofind->get());
bb->getInstructions().erase(tofind);
funcInfo->removeValue2AllocBlock(val);
}
} else {
// 如果该变量还有其他的define那么前面的define也变成死代码了
assert(!funcInfo->getDefBlocksByValue(val).empty());
assert(funcInfo->getUseBlocksByValue(val).empty());
preOptimize1();
}
}
}
}
}
}
/**
* @brief llvm mem2reg类预优化3针对某个变量的所有读写都在同一个块中的情况
*
* 1. 将每一个load替换成前一个store的值并删除该load
* 2. 如果在load前没有对该变量的store则不删除该load
* 3. 如果一个store后没有任何对改变量的load则删除该store
*
* @note 额外说明第二点不用显式处理因为我们的方法是从找到第一个store开始
* 第三点其实可以更激进一步地理解即每次替换了load之后它对应地那个store也可以删除了同时注意这里不要使用preoptimize1进行处理因为他们的级联关系是有用的即用来求load的替换值
* 同样地我们这里不考虑数组和全局变量因为这些变量不会被mem2reg优化不过这里在计算value2DefBlocks时已经跳过了所以不需要再显式处理了
* 替换的操作采用了UD链进行简化和效率的提升
*
* @param [in] void
* @return 无返回值,但满足条件的情况下会对指令的操作数进行替换以及对指令进行删除
*/
auto Mem2Reg::preOptimize3() -> void {
auto &functions = pModule->getFunctions();
for (const auto &function : functions) {
auto func = function.second.get();
FunctionAnalysisInfo* funcInfo = controlFlowAnalysis->getFunctionAnalysisInfo(func);
auto values = funcInfo->getValuesOfDefBlock();
for (auto val : values) {
auto sblocks = funcInfo->getDefBlocksByValue(val);
auto lblocks = funcInfo->getUseBlocksByValue(val);
if (sblocks.size() == 1 && lblocks.size() == 1 && *sblocks.begin() == *lblocks.begin()) {
auto block = *sblocks.begin();
auto &instrs = block->getInstructions();
auto it = std::find_if(instrs.begin(), instrs.end(),
[val](const auto &instr) { return instr->isStore() && instr->getOperand(1) == val; });
while (it != instrs.end()) {
auto propogationVal = (*it)->getOperand(0);
auto last = std::find_if(std::next(it), instrs.end(), [val](const auto &instr) {
return instr->isStore() && instr->getOperand(1) == val;
});
for (auto curit = std::next(it); curit != last;) {
if ((*curit)->isLoad() && (*curit)->getOperand(0) == val) {
curit->get()->replaceAllUsesWith(propogationVal);
usedelete(curit->get());
curit = instrs.erase(curit);
funcInfo->removeValue2UseBlock(val, block);
} else {
++curit;
}
}
// 替换了load之后它对应地那个store也可以删除了
if (!(std::find_if(func->getEntryBlock()->getArguments().begin(), func->getEntryBlock()->getArguments().end(),
[val](const auto &instr) { return instr == val; }) !=
func->getEntryBlock()->getArguments().end()) &&
last == instrs.end()) {
usedelete(it->get());
it = instrs.erase(it);
if (funcInfo->removeValue2DefBlock(val, block)) {
auto bb = funcInfo->getAllocBlockByValue(val);
if (bb != nullptr) {
auto tofind = std::find_if(bb->getInstructions().begin(), bb->getInstructions().end(),
[val](const auto &instr) { return instr.get() == val; });
usedelete(tofind->get());
bb->getInstructions().erase(tofind);
funcInfo->removeValue2AllocBlock(val);
}
}
}
it = last;
}
}
}
}
}
/**
* 为所有变量的定义块集合的迭代支配边界插入phi结点
*
* insertPhi是mem2reg的核心之一这里是对所有变量的迭代支配边界的phi结点插入无参数也无返回值
* 同样跳过对数组和全局变量的处理因为这些变量不会被mem2reg优化刚好这里在计算value2DefBlocks时已经跳过了所以不需要再显式处理了
* 同时我们进行了剪枝处理只有在基本块入口活跃的变量才插入phi函数
*
*/
auto Mem2Reg::insertPhi() -> void {
auto &functions = pModule->getFunctions();
for (const auto &function : functions) {
auto func = function.second.get();
FunctionAnalysisInfo* funcInfo = controlFlowAnalysis->getFunctionAnalysisInfo(func);
const auto &vToDefB = funcInfo->getValue2DefBlocks();
for (const auto &map_pair : vToDefB) {
// 首先为每个变量找到迭代支配边界
auto val = map_pair.first;
auto blocks = funcInfo->getDefBlocksByValue(val);
auto itDFs = computeIterDf(blocks);
// 然后在每个变量相应的迭代支配边界上插入phi结点
for (auto basicBlock : itDFs) {
const auto &actiTable = activeVarAnalysis->getActiveTable();
auto dval = dynamic_cast<User *>(val);
// 只有在基本块入口活跃的变量才插入phi函数
if (actiTable.at(basicBlock).front().count(dval) != 0U) {
pBuilder->createPhiInst(val->getType(), val, basicBlock);
}
}
}
}
}
/**
* 重命名
*
* 重命名是mem2reg的核心之二这里是对单个块的重命名递归实现
* 同样跳过对数组和全局变量的处理因为这些变量不会被mem2reg优化
*
*/
auto Mem2Reg::rename(BasicBlock *block, std::unordered_map<Value *, int> &count,
std::unordered_map<Value *, std::stack<Instruction *>> &stacks) -> void {
auto &instrs = block->getInstructions();
std::unordered_map<Value *, int> valPop;
// 第一大步:对块中的所有指令遍历处理
for (auto iter = instrs.begin(); iter != instrs.end();) {
auto instr = iter->get();
// 对于load指令变量用最新的那个
if (instr->isLoad()) {
auto val = instr->getOperand(0);
if (!(isArr(val) || isGlobal(val))) {
if (!stacks[val].empty()) {
instr->replaceOperand(0, stacks[val].top());
}
}
}
// 然后对于define的情况看alloca、store和phi指令
if (instr->isDefine()) {
if (instr->isAlloca()) {
// alloca指令名字不改了命名就按xx_1x_2...来就行
auto val = instr;
if (!(isArr(val) || isGlobal(val))) {
++valPop[val];
stacks[val].push(val);
++count[val];
}
} else if (instr->isPhi()) {
// Phi指令也是一条特殊的define指令
auto val = dynamic_cast<PhiInst *>(instr)->getMapVal();
if (!(isArr(val) || isGlobal(val))) {
auto i = count[val];
if (i == 0) {
// 对还未alloca就有phi的指令的处理直接删除
usedelete(iter->get());
iter = instrs.erase(iter);
continue;
}
auto newname = dynamic_cast<Instruction *>(val)->getName() + "_" + std::to_string(i);
auto newalloca = pBuilder->createAllocaInstWithoutInsert(val->getType(), {}, block, newname);
FunctionAnalysisInfo* ParentfuncInfo = controlFlowAnalysis->getFunctionAnalysisInfo(block->getParent());
ParentfuncInfo->addIndirectAlloca(newalloca);
instr->replaceOperand(0, newalloca);
++valPop[val];
stacks[val].push(newalloca);
++count[val];
}
} else {
// store指令看operand的名字我们的实现是规定变量在operand的第二位用一个新的alloca x_i代替
auto val = instr->getOperand(1);
if (!(isArr(val) || isGlobal(val))) {
auto i = count[val];
auto newname = dynamic_cast<Instruction *>(val)->getName() + "_" + std::to_string(i);
auto newalloca = pBuilder->createAllocaInstWithoutInsert(val->getType(), {}, block, newname);
FunctionAnalysisInfo* ParentfuncInfo = controlFlowAnalysis->getFunctionAnalysisInfo(block->getParent());
ParentfuncInfo->addIndirectAlloca(newalloca);
// block->getParent()->addIndirectAlloca(newalloca);
instr->replaceOperand(1, newalloca);
++valPop[val];
stacks[val].push(newalloca);
++count[val];
}
}
}
++iter;
}
// 第二大步把所有CFG中的该块的successor的phi指令的相应operand确定
for (auto succ : block->getSuccessors()) {
auto position = getPredIndex(block, succ);
for (auto &instr : succ->getInstructions()) {
if (instr->isPhi()) {
auto val = dynamic_cast<PhiInst *>(instr.get())->getMapVal();
if (!stacks[val].empty()) {
instr->replaceOperand(position + 1, stacks[val].top());
}
} else {
// phi指令是添加在块的最前面的因此过了之后就不会有phi了直接break
break;
}
}
}
// 第三大步递归支配树的后继支配树才能表示define-use关系
BlockAnalysisInfo* blockInfo = controlFlowAnalysis->getBlockAnalysisInfo(block);
for (auto sdom : blockInfo->getSdoms()) {
rename(sdom, count, stacks);
}
// 第四大步遍历块中的所有指令如果涉及到define就弹栈这一步是必要的可以从递归的整体性来思考原因
// 注意这里count没清理因为平级之间计数仍然是一直增加的但是stack要清理因为define-use关系来自直接
// 支配结点而不是平级之间,不清理栈会被污染
// 提前优化知道变量对应的要弹栈的次数就可以了没必要遍历所有instr.
for (auto val_pair : valPop) {
auto val = val_pair.first;
for (int i = 0; i < val_pair.second; ++i) {
stacks[val].pop();
}
}
}
/**
* 重命名所有块
*
* 调用rename自上而下实现所有rename
*
*/
auto Mem2Reg::renameAll() -> void {
auto &functions = pModule->getFunctions();
for (const auto &function : functions) {
auto func = function.second.get();
// 对于每个function都要SSA化所以count和stacks定义在这并初始化
std::unordered_map<Value *, int> count;
std::unordered_map<Value *, std::stack<Instruction *>> stacks;
FunctionAnalysisInfo* funcInfo = controlFlowAnalysis->getFunctionAnalysisInfo(func);
for (const auto &map_pair : funcInfo->getValue2DefBlocks()) {
auto val = map_pair.first;
count[val] = 0;
}
rename(func->getEntryBlock(), count, stacks);
}
}
/**
* mem2reg对外的接口
*
* 静态单一赋值 + mem2reg等pass的逻辑组合
*
*/
auto Mem2Reg::mem2regPipeline() -> void {
// 首先进行mem2reg的前置分析
controlFlowAnalysis->clear();
controlFlowAnalysis->runControlFlowAnalysis();
// 活跃变量分析
activeVarAnalysis->clear();
dataFlowAnalysisUtils.addBackwardAnalyzer(activeVarAnalysis);
dataFlowAnalysisUtils.backwardAnalyze(pModule);
// 计算所有valueToBlocks的定义映射
computeValue2Blocks();
// SysYPrinter printer(pModule);
// 参考llvm的mem2reg遍在插入phi结点之前先做些优化
preOptimize1();
// printer.printIR();
preOptimize2();
// printer.printIR();
// 优化三 可能会针对局部变量优化而删除整个块的alloca/store
preOptimize3();
//再进行活跃变量分析
// 报错?
// printer.printIR();
dataFlowAnalysisUtils.backwardAnalyze(pModule);
// 为所有变量插入phi结点
insertPhi();
// 重命名
renameAll();
}
/**
* 计算块n是块s的第几个前驱
*
* helperfunction没有返回值但是会将dom和other的交集赋值给dom
*
*/
auto Mem2Reg::getPredIndex(BasicBlock *n, BasicBlock *s) -> int {
int index = 0;
for (auto elem : s->getPredecessors()) {
if (elem == n) {
break;
}
++index;
}
assert(index < static_cast<int>(s->getPredecessors().size()) && "n is not a predecessor of s.");
return index;
}
/**
* 判断一个value是不是全局变量
*/
auto Mem2Reg::isGlobal(Value *val) -> bool {
auto gval = dynamic_cast<GlobalValue *>(val);
return gval != nullptr;
}
/**
* 判断一个value是不是数组
*/
auto Mem2Reg::isArr(Value *val) -> bool {
auto aval = dynamic_cast<AllocaInst *>(val);
return aval != nullptr && aval->getNumDims() != 0;
}
/**
* 删除一个指令的operand对应的value的该条use
*/
auto Mem2Reg::usedelete(Instruction *instr) -> void {
for (auto &use : instr->getOperands()) {
auto val = use->getValue();
val->removeUse(use);
}
}
} // namespace sysy

View File

@ -1,73 +0,0 @@
#include "RISCv64Backend.h"
#include "RISCv64ISel.h"
#include "RISCv64RegAlloc.h"
#include "RISCv64AsmPrinter.h"
#include <sstream>
namespace sysy {
// 顶层入口
std::string RISCv64CodeGen::code_gen() {
return module_gen();
}
// 模块级代码生成 (移植自原文件,处理.data段和驱动函数生成)
std::string RISCv64CodeGen::module_gen() {
std::stringstream ss;
// 1. 处理全局变量 (.data段)
if (!module->getGlobals().empty()) {
ss << ".data\n";
for (const auto& global : module->getGlobals()) {
ss << ".globl " << global->getName() << "\n";
ss << global->getName() << ":\n";
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";
}
}
}
}
}
}
// 2. 处理函数 (.text段)
if (!module->getFunctions().empty()) {
ss << ".text\n";
for (const auto& func_pair : module->getFunctions()) {
if (func_pair.second.get()) {
ss << function_gen(func_pair.second.get());
}
}
}
return ss.str();
}
// function_gen 现在是新的、模块化的处理流水线
std::string RISCv64CodeGen::function_gen(Function* func) {
// 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers)
RISCv64ISel isel;
std::unique_ptr<MachineFunction> mfunc = isel.runOnFunction(func);
// 阶段 2: 寄存器分配 (包含栈帧布局, 活跃性分析, 图着色, spill/rewrite)
RISCv64RegAlloc reg_alloc(mfunc.get());
reg_alloc.run();
// 阶段 3: 代码发射 (LLIR with physical regs -> Assembly Text)
std::stringstream ss;
RISCv64AsmPrinter printer(mfunc.get());
printer.run(ss);
return ss.str();
}
} // namespace sysy

View File

@ -1,635 +0,0 @@
#include "RISCv64ISel.h"
#include <stdexcept>
#include <set>
#include <functional>
#include <cmath> // For std::fabs
#include <limits> // For std::numeric_limits
namespace sysy {
// DAG节点定义 (内部实现)
struct RISCv64ISel::DAGNode {
enum NodeKind { CONSTANT, LOAD, STORE, BINARY, CALL, RETURN, BRANCH, ALLOCA_ADDR, UNARY, MEMSET };
NodeKind kind;
Value* value = nullptr;
std::vector<DAGNode*> operands;
std::vector<DAGNode*> users;
DAGNode(NodeKind k) : kind(k) {}
};
RISCv64ISel::RISCv64ISel() : vreg_counter(0), local_label_counter(0) {}
// 为一个IR Value获取或分配一个新的虚拟寄存器
unsigned RISCv64ISel::getVReg(Value* val) {
if (!val) {
throw std::runtime_error("Cannot get vreg for a null Value.");
}
if (vreg_map.find(val) == vreg_map.end()) {
if (vreg_counter == 0) {
vreg_counter = 1; // vreg 0 保留
}
vreg_map[val] = vreg_counter++;
}
return vreg_map.at(val);
}
// 主入口函数
std::unique_ptr<MachineFunction> RISCv64ISel::runOnFunction(Function* func) {
F = func;
if (!F) return nullptr;
MFunc = std::make_unique<MachineFunction>(F, this);
vreg_map.clear();
bb_map.clear();
vreg_counter = 0;
local_label_counter = 0;
select();
return std::move(MFunc);
}
// 指令选择主流程
void RISCv64ISel::select() {
for (const auto& bb_ptr : F->getBasicBlocks()) {
auto mbb = std::make_unique<MachineBasicBlock>(bb_ptr->getName(), MFunc.get());
bb_map[bb_ptr.get()] = mbb.get();
MFunc->addBlock(std::move(mbb));
}
if (F->getEntryBlock()) {
for (auto* arg_alloca : F->getEntryBlock()->getArguments()) {
getVReg(arg_alloca);
}
}
for (const auto& bb_ptr : F->getBasicBlocks()) {
selectBasicBlock(bb_ptr.get());
}
for (const auto& bb_ptr : F->getBasicBlocks()) {
CurMBB = bb_map.at(bb_ptr.get());
for (auto succ : bb_ptr->getSuccessors()) {
CurMBB->successors.push_back(bb_map.at(succ));
}
for (auto pred : bb_ptr->getPredecessors()) {
CurMBB->predecessors.push_back(bb_map.at(pred));
}
}
}
// 处理单个基本块
void RISCv64ISel::selectBasicBlock(BasicBlock* bb) {
CurMBB = bb_map.at(bb);
auto dag = build_dag(bb);
std::map<Value*, DAGNode*> value_to_node;
for(const auto& node : dag) {
if (node->value) {
value_to_node[node->value] = node.get();
}
}
std::set<DAGNode*> selected_nodes;
std::function<void(DAGNode*)> select_recursive =
[&](DAGNode* node) {
if (!node || selected_nodes.count(node)) return;
for (auto operand : node->operands) {
select_recursive(operand);
}
selectNode(node);
selected_nodes.insert(node);
};
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());
} else {
for(const auto& node : dag) {
if(node->value == inst_ptr.get()) {
node_to_select = node.get();
break;
}
}
}
if(node_to_select) {
select_recursive(node_to_select);
}
}
}
// 核心函数为DAG节点选择并生成MachineInstr (忠实移植版)
void RISCv64ISel::selectNode(DAGNode* node) {
switch (node->kind) {
case DAGNode::CONSTANT:
case DAGNode::ALLOCA_ADDR:
if (node->value) getVReg(node->value);
break;
case DAGNode::LOAD: {
auto dest_vreg = getVReg(node->value);
Value* ptr_val = node->operands[0]->value;
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_LOAD);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(getVReg(alloca)));
CurMBB->addInstruction(std::move(instr));
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_val)) {
auto addr_vreg = getNewVReg();
auto la = std::make_unique<MachineInstr>(RVOpcodes::LA);
la->addOperand(std::make_unique<RegOperand>(addr_vreg));
la->addOperand(std::make_unique<LabelOperand>(global->getName()));
CurMBB->addInstruction(std::move(la));
auto lw = std::make_unique<MachineInstr>(RVOpcodes::LW);
lw->addOperand(std::make_unique<RegOperand>(dest_vreg));
lw->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(addr_vreg),
std::make_unique<ImmOperand>(0)
));
CurMBB->addInstruction(std::move(lw));
} else {
auto ptr_vreg = getVReg(ptr_val);
auto lw = std::make_unique<MachineInstr>(RVOpcodes::LW);
lw->addOperand(std::make_unique<RegOperand>(dest_vreg));
lw->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(ptr_vreg),
std::make_unique<ImmOperand>(0)
));
CurMBB->addInstruction(std::move(lw));
}
break;
}
case DAGNode::STORE: {
Value* val_to_store = node->operands[0]->value;
Value* ptr_val = node->operands[1]->value;
if (auto val_const = dynamic_cast<ConstantValue*>(val_to_store)) {
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(getVReg(val_const)));
li->addOperand(std::make_unique<ImmOperand>(val_const->getInt()));
CurMBB->addInstruction(std::move(li));
}
auto val_vreg = getVReg(val_to_store);
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_STORE);
instr->addOperand(std::make_unique<RegOperand>(val_vreg));
instr->addOperand(std::make_unique<RegOperand>(getVReg(alloca)));
CurMBB->addInstruction(std::move(instr));
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_val)) {
auto addr_vreg = getNewVReg();
auto la = std::make_unique<MachineInstr>(RVOpcodes::LA);
la->addOperand(std::make_unique<RegOperand>(addr_vreg));
la->addOperand(std::make_unique<LabelOperand>(global->getName()));
CurMBB->addInstruction(std::move(la));
auto sw = std::make_unique<MachineInstr>(RVOpcodes::SW);
sw->addOperand(std::make_unique<RegOperand>(val_vreg));
sw->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(addr_vreg),
std::make_unique<ImmOperand>(0)
));
CurMBB->addInstruction(std::move(sw));
} else {
auto ptr_vreg = getVReg(ptr_val);
auto sw = std::make_unique<MachineInstr>(RVOpcodes::SW);
sw->addOperand(std::make_unique<RegOperand>(val_vreg));
sw->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(ptr_vreg),
std::make_unique<ImmOperand>(0)
));
CurMBB->addInstruction(std::move(sw));
}
break;
}
case DAGNode::BINARY: {
auto bin = dynamic_cast<BinaryInst*>(node->value);
Value* lhs = bin->getLhs();
Value* rhs = bin->getRhs();
auto load_val_if_const = [&](Value* val) {
if (auto c = dynamic_cast<ConstantValue*>(val)) {
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(getVReg(c)));
li->addOperand(std::make_unique<ImmOperand>(c->getInt()));
CurMBB->addInstruction(std::move(li));
}
};
load_val_if_const(lhs);
load_val_if_const(rhs);
auto dest_vreg = getVReg(bin);
auto lhs_vreg = getVReg(lhs);
auto rhs_vreg = getVReg(rhs);
if (bin->getKind() == BinaryInst::kAdd) {
if (auto rhs_const = dynamic_cast<ConstantValue*>(rhs)) {
if (rhs_const->getInt() >= -2048 && rhs_const->getInt() < 2048) {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::ADDIW);
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));
return;
}
}
}
switch (bin->getKind()) {
case BinaryInst::kAdd: {
RVOpcodes opcode = (lhs->getType()->isPointer() || rhs->getType()->isPointer()) ? RVOpcodes::ADD : RVOpcodes::ADDW;
auto instr = std::make_unique<MachineInstr>(opcode);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
case BinaryInst::kSub: {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
case BinaryInst::kMul: {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::MULW);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
case Instruction::kDiv: {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::DIVW);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
case Instruction::kRem: {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::REMW);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
case BinaryInst::kICmpEQ: {
auto sub = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
sub->addOperand(std::make_unique<RegOperand>(dest_vreg));
sub->addOperand(std::make_unique<RegOperand>(lhs_vreg));
sub->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(sub));
auto seqz = std::make_unique<MachineInstr>(RVOpcodes::SEQZ);
seqz->addOperand(std::make_unique<RegOperand>(dest_vreg));
seqz->addOperand(std::make_unique<RegOperand>(dest_vreg));
CurMBB->addInstruction(std::move(seqz));
break;
}
case BinaryInst::kICmpNE: {
auto sub = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
sub->addOperand(std::make_unique<RegOperand>(dest_vreg));
sub->addOperand(std::make_unique<RegOperand>(lhs_vreg));
sub->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(sub));
auto snez = std::make_unique<MachineInstr>(RVOpcodes::SNEZ);
snez->addOperand(std::make_unique<RegOperand>(dest_vreg));
snez->addOperand(std::make_unique<RegOperand>(dest_vreg));
CurMBB->addInstruction(std::move(snez));
break;
}
case BinaryInst::kICmpLT: {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SLT);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
case BinaryInst::kICmpGT: {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SLT);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
case BinaryInst::kICmpLE: {
auto slt = std::make_unique<MachineInstr>(RVOpcodes::SLT);
slt->addOperand(std::make_unique<RegOperand>(dest_vreg));
slt->addOperand(std::make_unique<RegOperand>(rhs_vreg));
slt->addOperand(std::make_unique<RegOperand>(lhs_vreg));
CurMBB->addInstruction(std::move(slt));
auto xori = std::make_unique<MachineInstr>(RVOpcodes::XORI);
xori->addOperand(std::make_unique<RegOperand>(dest_vreg));
xori->addOperand(std::make_unique<RegOperand>(dest_vreg));
xori->addOperand(std::make_unique<ImmOperand>(1));
CurMBB->addInstruction(std::move(xori));
break;
}
case BinaryInst::kICmpGE: {
auto slt = std::make_unique<MachineInstr>(RVOpcodes::SLT);
slt->addOperand(std::make_unique<RegOperand>(dest_vreg));
slt->addOperand(std::make_unique<RegOperand>(lhs_vreg));
slt->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(slt));
auto xori = std::make_unique<MachineInstr>(RVOpcodes::XORI);
xori->addOperand(std::make_unique<RegOperand>(dest_vreg));
xori->addOperand(std::make_unique<RegOperand>(dest_vreg));
xori->addOperand(std::make_unique<ImmOperand>(1));
CurMBB->addInstruction(std::move(xori));
break;
}
default:
throw std::runtime_error("Unsupported binary instruction in ISel");
}
break;
}
case DAGNode::UNARY: {
auto unary = dynamic_cast<UnaryInst*>(node->value);
auto dest_vreg = getVReg(unary);
auto src_vreg = getVReg(unary->getOperand());
switch (unary->getKind()) {
case UnaryInst::kNeg: {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
instr->addOperand(std::make_unique<RegOperand>(src_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
case UnaryInst::kNot: {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SEQZ);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(src_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
default:
throw std::runtime_error("Unsupported unary instruction in ISel");
}
break;
}
case DAGNode::CALL: {
auto call = dynamic_cast<CallInst*>(node->value);
for (size_t i = 0; i < node->operands.size() && i < 8; ++i) {
DAGNode* arg_node = node->operands[i];
auto arg_preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + i);
if (arg_node->kind == DAGNode::CONSTANT) {
if (auto const_val = dynamic_cast<ConstantValue*>(arg_node->value)) {
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(arg_preg));
li->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
CurMBB->addInstruction(std::move(li));
}
} else {
auto src_vreg = getVReg(arg_node->value);
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
mv->addOperand(std::make_unique<RegOperand>(arg_preg));
mv->addOperand(std::make_unique<RegOperand>(src_vreg));
CurMBB->addInstruction(std::move(mv));
}
}
auto call_instr = std::make_unique<MachineInstr>(RVOpcodes::CALL);
call_instr->addOperand(std::make_unique<LabelOperand>(call->getCallee()->getName()));
CurMBB->addInstruction(std::move(call_instr));
if (!call->getType()->isVoid()) {
auto mv_instr = std::make_unique<MachineInstr>(RVOpcodes::MV);
mv_instr->addOperand(std::make_unique<RegOperand>(getVReg(call)));
mv_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
CurMBB->addInstruction(std::move(mv_instr));
}
break;
}
case DAGNode::RETURN: {
auto ret_inst_ir = dynamic_cast<ReturnInst*>(node->value);
if (ret_inst_ir && ret_inst_ir->hasReturnValue()) {
Value* ret_val = ret_inst_ir->getReturnValue();
if (auto const_val = dynamic_cast<ConstantValue*>(ret_val)) {
auto li_instr = std::make_unique<MachineInstr>(RVOpcodes::LI);
li_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
li_instr->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
CurMBB->addInstruction(std::move(li_instr));
} else {
auto mv_instr = std::make_unique<MachineInstr>(RVOpcodes::MV);
mv_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
mv_instr->addOperand(std::make_unique<RegOperand>(getVReg(ret_val)));
CurMBB->addInstruction(std::move(mv_instr));
}
}
auto ret_mi = std::make_unique<MachineInstr>(RVOpcodes::RET);
CurMBB->addInstruction(std::move(ret_mi));
break;
}
case DAGNode::BRANCH: {
if (auto cond_br = dynamic_cast<CondBrInst*>(node->value)) {
auto br_instr = std::make_unique<MachineInstr>(RVOpcodes::BNE);
br_instr->addOperand(std::make_unique<RegOperand>(getVReg(cond_br->getCondition())));
br_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
br_instr->addOperand(std::make_unique<LabelOperand>(cond_br->getThenBlock()->getName()));
CurMBB->addInstruction(std::move(br_instr));
} else if (auto uncond_br = dynamic_cast<UncondBrInst*>(node->value)) {
auto j_instr = std::make_unique<MachineInstr>(RVOpcodes::J);
j_instr->addOperand(std::make_unique<LabelOperand>(uncond_br->getBlock()->getName()));
CurMBB->addInstruction(std::move(j_instr));
}
break;
}
case DAGNode::MEMSET: {
auto memset = dynamic_cast<MemsetInst*>(node->value);
auto r_dest_addr = getVReg(memset->getPointer());
auto r_num_bytes = getVReg(memset->getSize());
auto r_value_byte = getVReg(memset->getValue());
auto r_counter = getNewVReg();
auto r_end_addr = getNewVReg();
auto r_current_addr = getNewVReg();
auto r_temp_val = getNewVReg();
auto add_instr = [&](RVOpcodes op, unsigned rd, unsigned rs1, unsigned rs2) {
auto i = std::make_unique<MachineInstr>(op);
i->addOperand(std::make_unique<RegOperand>(rd));
i->addOperand(std::make_unique<RegOperand>(rs1));
i->addOperand(std::make_unique<RegOperand>(rs2));
CurMBB->addInstruction(std::move(i));
};
auto addi_instr = [&](RVOpcodes op, unsigned rd, unsigned rs1, int64_t imm) {
auto i = std::make_unique<MachineInstr>(op);
i->addOperand(std::make_unique<RegOperand>(rd));
i->addOperand(std::make_unique<RegOperand>(rs1));
i->addOperand(std::make_unique<ImmOperand>(imm));
CurMBB->addInstruction(std::move(i));
};
auto store_instr = [&](RVOpcodes op, unsigned src, unsigned base, int64_t off) {
auto i = std::make_unique<MachineInstr>(op);
i->addOperand(std::make_unique<RegOperand>(src));
i->addOperand(std::make_unique<MemOperand>(std::make_unique<RegOperand>(base), std::make_unique<ImmOperand>(off)));
CurMBB->addInstruction(std::move(i));
};
auto branch_instr = [&](RVOpcodes op, unsigned rs1, unsigned rs2, const std::string& label) {
auto i = std::make_unique<MachineInstr>(op);
i->addOperand(std::make_unique<RegOperand>(rs1));
i->addOperand(std::make_unique<RegOperand>(rs2));
i->addOperand(std::make_unique<LabelOperand>(label));
CurMBB->addInstruction(std::move(i));
};
auto jump_instr = [&](const std::string& label) {
auto i = std::make_unique<MachineInstr>(RVOpcodes::J);
i->addOperand(std::make_unique<LabelOperand>(label));
CurMBB->addInstruction(std::move(i));
};
auto label_instr = [&](const std::string& name) {
auto i = std::make_unique<MachineInstr>(RVOpcodes::LABEL);
i->addOperand(std::make_unique<LabelOperand>(name));
CurMBB->addInstruction(std::move(i));
};
int unique_id = this->local_label_counter++;
std::string loop_start_label = MFunc->getName() + "_memset_loop_start_" + std::to_string(unique_id);
std::string loop_end_label = MFunc->getName() + "_memset_loop_end_" + std::to_string(unique_id);
std::string remainder_label = MFunc->getName() + "_memset_remainder_" + std::to_string(unique_id);
std::string done_label = MFunc->getName() + "_memset_done_" + std::to_string(unique_id);
addi_instr(RVOpcodes::ANDI, r_temp_val, r_value_byte, 255);
addi_instr(RVOpcodes::SLLI, r_value_byte, r_temp_val, 8);
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte);
addi_instr(RVOpcodes::SLLI, r_value_byte, r_temp_val, 16);
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte);
addi_instr(RVOpcodes::SLLI, r_value_byte, r_temp_val, 32);
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte);
add_instr(RVOpcodes::ADD, r_end_addr, r_dest_addr, r_num_bytes);
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
mv->addOperand(std::make_unique<RegOperand>(r_current_addr));
mv->addOperand(std::make_unique<RegOperand>(r_dest_addr));
CurMBB->addInstruction(std::move(mv));
addi_instr(RVOpcodes::ANDI, r_counter, r_num_bytes, -8);
add_instr(RVOpcodes::ADD, r_counter, r_dest_addr, r_counter);
label_instr(loop_start_label);
branch_instr(RVOpcodes::BGEU, r_current_addr, r_counter, loop_end_label);
store_instr(RVOpcodes::SD, r_temp_val, r_current_addr, 0);
addi_instr(RVOpcodes::ADDI, r_current_addr, r_current_addr, 8);
jump_instr(loop_start_label);
label_instr(loop_end_label);
label_instr(remainder_label);
branch_instr(RVOpcodes::BGEU, r_current_addr, r_end_addr, done_label);
store_instr(RVOpcodes::SB, r_temp_val, r_current_addr, 0);
addi_instr(RVOpcodes::ADDI, r_current_addr, r_current_addr, 1);
jump_instr(remainder_label);
label_instr(done_label);
break;
}
default:
throw std::runtime_error("Unsupported DAGNode kind in ISel");
}
}
// 以下是忠实移植的DAG构建函数
RISCv64ISel::DAGNode* RISCv64ISel::create_node(int kind_int, Value* val, std::map<Value*, DAGNode*>& value_to_node, std::vector<std::unique_ptr<DAGNode>>& nodes_storage) {
auto kind = static_cast<DAGNode::NodeKind>(kind_int);
if (val && value_to_node.count(val) && kind != DAGNode::STORE && kind != DAGNode::RETURN && kind != DAGNode::BRANCH && kind != DAGNode::MEMSET) {
return value_to_node[val];
}
auto node = std::make_unique<DAGNode>(kind);
node->value = val;
DAGNode* raw_node_ptr = node.get();
nodes_storage.push_back(std::move(node));
if (val && !val->getType()->isVoid() && (dynamic_cast<Instruction*>(val) || dynamic_cast<GlobalValue*>(val))) {
value_to_node[val] = raw_node_ptr;
}
return raw_node_ptr;
}
RISCv64ISel::DAGNode* RISCv64ISel::get_operand_node(Value* val_ir, std::map<Value*, DAGNode*>& value_to_node, std::vector<std::unique_ptr<DAGNode>>& nodes_storage) {
if (value_to_node.count(val_ir)) {
return value_to_node[val_ir];
} else if (dynamic_cast<ConstantValue*>(val_ir)) {
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
} else if (dynamic_cast<GlobalValue*>(val_ir)) {
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
} else if (dynamic_cast<AllocaInst*>(val_ir)) {
return create_node(DAGNode::ALLOCA_ADDR, val_ir, value_to_node, nodes_storage);
}
return create_node(DAGNode::LOAD, val_ir, value_to_node, nodes_storage);
}
std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicBlock* bb) {
std::vector<std::unique_ptr<DAGNode>> nodes_storage;
std::map<Value*, DAGNode*> value_to_node;
for (const auto& inst_ptr : bb->getInstructions()) {
Instruction* inst = inst_ptr.get();
if (auto alloca = dynamic_cast<AllocaInst*>(inst)) {
create_node(DAGNode::ALLOCA_ADDR, alloca, value_to_node, nodes_storage);
} else if (auto store = dynamic_cast<StoreInst*>(inst)) {
auto store_node = create_node(DAGNode::STORE, store, value_to_node, nodes_storage);
store_node->operands.push_back(get_operand_node(store->getValue(), value_to_node, nodes_storage));
store_node->operands.push_back(get_operand_node(store->getPointer(), value_to_node, nodes_storage));
} else if (auto memset = dynamic_cast<MemsetInst*>(inst)) {
auto memset_node = create_node(DAGNode::MEMSET, memset, value_to_node, nodes_storage);
memset_node->operands.push_back(get_operand_node(memset->getPointer(), value_to_node, nodes_storage));
memset_node->operands.push_back(get_operand_node(memset->getBegin(), value_to_node, nodes_storage));
memset_node->operands.push_back(get_operand_node(memset->getSize(), value_to_node, nodes_storage));
memset_node->operands.push_back(get_operand_node(memset->getValue(), value_to_node, nodes_storage));
} else if (auto load = dynamic_cast<LoadInst*>(inst)) {
auto load_node = create_node(DAGNode::LOAD, load, value_to_node, nodes_storage);
load_node->operands.push_back(get_operand_node(load->getPointer(), value_to_node, nodes_storage));
} else if (auto bin = dynamic_cast<BinaryInst*>(inst)) {
if(value_to_node.count(bin)) continue;
if (bin->getKind() == BinaryInst::kSub) {
if (auto const_lhs = dynamic_cast<ConstantValue*>(bin->getLhs())) {
if (const_lhs->getInt() == 0) {
auto unary_node = create_node(DAGNode::UNARY, bin, value_to_node, nodes_storage);
unary_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
continue;
}
}
}
auto bin_node = create_node(DAGNode::BINARY, bin, value_to_node, nodes_storage);
bin_node->operands.push_back(get_operand_node(bin->getLhs(), value_to_node, nodes_storage));
bin_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
} else if (auto un = dynamic_cast<UnaryInst*>(inst)) {
if(value_to_node.count(un)) continue;
auto unary_node = create_node(DAGNode::UNARY, un, value_to_node, nodes_storage);
unary_node->operands.push_back(get_operand_node(un->getOperand(), value_to_node, nodes_storage));
} else if (auto call = dynamic_cast<CallInst*>(inst)) {
if(value_to_node.count(call)) continue;
auto call_node = create_node(DAGNode::CALL, call, value_to_node, nodes_storage);
for (auto arg : call->getArguments()) {
call_node->operands.push_back(get_operand_node(arg->getValue(), value_to_node, nodes_storage));
}
} else if (auto ret = dynamic_cast<ReturnInst*>(inst)) {
auto ret_node = create_node(DAGNode::RETURN, ret, value_to_node, nodes_storage);
if (ret->hasReturnValue()) {
ret_node->operands.push_back(get_operand_node(ret->getReturnValue(), value_to_node, nodes_storage));
}
} else if (auto cond_br = dynamic_cast<CondBrInst*>(inst)) {
auto br_node = create_node(DAGNode::BRANCH, cond_br, value_to_node, nodes_storage);
br_node->operands.push_back(get_operand_node(cond_br->getCondition(), value_to_node, nodes_storage));
} else if (auto uncond_br = dynamic_cast<UncondBrInst*>(inst)) {
create_node(DAGNode::BRANCH, uncond_br, value_to_node, nodes_storage);
}
}
return nodes_storage;
}
} // namespace sysy

View File

@ -1,8 +0,0 @@
// RISCv64Passes.cpp
#include "RISCv64Passes.h"
namespace sysy {
// 此处为未来优化Pass的实现
} // namespace sysy

View File

@ -1,322 +0,0 @@
#include "RISCv64RegAlloc.h"
#include "RISCv64ISel.h"
#include <algorithm>
#include <vector>
namespace sysy {
RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) : MFunc(mfunc) {
allocable_int_regs = {
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3,
PhysicalReg::T4, PhysicalReg::T5, PhysicalReg::T6,
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3,
PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7,
PhysicalReg::S0, PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3,
PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
};
}
void RISCv64RegAlloc::run() {
eliminateFrameIndices();
analyzeLiveness();
buildInterferenceGraph();
colorGraph();
rewriteFunction();
}
void RISCv64RegAlloc::eliminateFrameIndices() {
StackFrameInfo& frame_info = MFunc->getFrameInfo();
int current_offset = 0;
Function* F = MFunc->getFunc();
RISCv64ISel* isel = MFunc->getISel();
for (auto& bb : F->getBasicBlocks()) {
for (auto& inst : bb->getInstructions()) {
if (auto alloca = dynamic_cast<AllocaInst*>(inst.get())) {
int size = 4;
if (!alloca->getDims().empty()) {
int num_elements = 1;
for (const auto& dim_use : alloca->getDims()) {
if (auto const_dim = dynamic_cast<ConstantValue*>(dim_use->getValue())) {
num_elements *= const_dim->getInt();
}
}
size *= num_elements;
}
current_offset += size;
unsigned alloca_vreg = isel->getVReg(alloca);
frame_info.alloca_offsets[alloca_vreg] = -current_offset;
}
}
}
frame_info.locals_size = current_offset;
for (auto& mbb : MFunc->getBlocks()) {
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
for (auto& instr_ptr : mbb->getInstructions()) {
if (instr_ptr->getOpcode() == RVOpcodes::FRAME_LOAD) {
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();
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));
auto lw = std::make_unique<MachineInstr>(RVOpcodes::LW);
lw->addOperand(std::make_unique<RegOperand>(dest_vreg));
lw->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(addr_vreg),
std::make_unique<ImmOperand>(0)));
new_instructions.push_back(std::move(lw));
} else if (instr_ptr->getOpcode() == RVOpcodes::FRAME_STORE) {
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();
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));
auto sw = std::make_unique<MachineInstr>(RVOpcodes::SW);
sw->addOperand(std::make_unique<RegOperand>(src_vreg));
sw->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(addr_vreg),
std::make_unique<ImmOperand>(0)));
new_instructions.push_back(std::move(sw));
} else {
new_instructions.push_back(std::move(instr_ptr));
}
}
mbb->getInstructions() = std::move(new_instructions);
}
}
void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def) {
bool is_def = true;
auto opcode = instr->getOpcode();
// 预定义def和use规则
if (opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
opcode == RVOpcodes::RET || opcode == RVOpcodes::J) {
is_def = false;
}
if (opcode == RVOpcodes::CALL) {
// CALL会杀死所有调用者保存寄存器这是一个简化处理
// 同时也使用了传入a0-a7的参数
}
for (const auto& op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(op.get());
if (reg_op->isVirtual()) {
if (is_def) {
def.insert(reg_op->getVRegNum());
is_def = false;
} else {
use.insert(reg_op->getVRegNum());
}
}
} else if (op->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand*>(op.get());
if (mem_op->getBase()->isVirtual()) {
use.insert(mem_op->getBase()->getVRegNum());
}
}
}
}
void RISCv64RegAlloc::analyzeLiveness() {
bool changed = true;
while (changed) {
changed = false;
for (auto it = MFunc->getBlocks().rbegin(); it != MFunc->getBlocks().rend(); ++it) {
auto& mbb = *it;
LiveSet live_out;
for (auto succ : mbb->successors) {
if (!succ->getInstructions().empty()) {
auto first_instr = succ->getInstructions().front().get();
if (live_in_map.count(first_instr)) {
live_out.insert(live_in_map.at(first_instr).begin(), live_in_map.at(first_instr).end());
}
}
}
for (auto instr_it = mbb->getInstructions().rbegin(); instr_it != mbb->getInstructions().rend(); ++instr_it) {
MachineInstr* instr = instr_it->get();
LiveSet old_live_in = live_in_map[instr];
live_out_map[instr] = live_out;
LiveSet use, def;
getInstrUseDef(instr, use, def);
LiveSet live_in = use;
LiveSet diff = live_out;
for (auto vreg : def) {
diff.erase(vreg);
}
live_in.insert(diff.begin(), diff.end());
live_in_map[instr] = live_in;
live_out = live_in;
if (live_in_map[instr] != old_live_in) {
changed = true;
}
}
}
}
}
void RISCv64RegAlloc::buildInterferenceGraph() {
std::set<unsigned> all_vregs;
for (auto& mbb : MFunc->getBlocks()) {
for(auto& instr : mbb->getInstructions()) {
LiveSet use, def;
getInstrUseDef(instr.get(), use, def);
for(auto u : use) all_vregs.insert(u);
for(auto d : def) all_vregs.insert(d);
}
}
for (auto vreg : all_vregs) { interference_graph[vreg] = {}; }
for (auto& mbb : MFunc->getBlocks()) {
for (auto& instr : mbb->getInstructions()) {
LiveSet def, use;
getInstrUseDef(instr.get(), use, def);
const LiveSet& live_out = live_out_map.at(instr.get());
for (unsigned d : def) {
for (unsigned l : live_out) {
if (d != l) {
interference_graph[d].insert(l);
interference_graph[l].insert(d);
}
}
}
}
}
}
void RISCv64RegAlloc::colorGraph() {
std::vector<unsigned> sorted_vregs;
for (auto const& [vreg, neighbors] : interference_graph) {
sorted_vregs.push_back(vreg);
}
std::sort(sorted_vregs.begin(), sorted_vregs.end(), [&](unsigned a, unsigned b) {
return interference_graph[a].size() > interference_graph[b].size();
});
for (unsigned vreg : sorted_vregs) {
std::set<PhysicalReg> used_colors;
for (unsigned neighbor : interference_graph.at(vreg)) {
if (color_map.count(neighbor)) {
used_colors.insert(color_map.at(neighbor));
}
}
bool colored = false;
for (PhysicalReg preg : allocable_int_regs) {
if (used_colors.find(preg) == used_colors.end()) {
color_map[vreg] = preg;
colored = true;
break;
}
}
if (!colored) {
spilled_vregs.insert(vreg);
}
}
}
void RISCv64RegAlloc::rewriteFunction() {
StackFrameInfo& frame_info = MFunc->getFrameInfo();
int current_offset = frame_info.locals_size;
for (unsigned vreg : spilled_vregs) {
current_offset += 4;
frame_info.spill_offsets[vreg] = -current_offset;
}
frame_info.spill_size = current_offset - frame_info.locals_size;
for (auto& mbb : MFunc->getBlocks()) {
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
for (auto& instr_ptr : mbb->getInstructions()) {
LiveSet use, def;
getInstrUseDef(instr_ptr.get(), use, def);
for (unsigned vreg : use) {
if (spilled_vregs.count(vreg)) {
int offset = frame_info.spill_offsets.at(vreg);
auto load = std::make_unique<MachineInstr>(RVOpcodes::LW);
load->addOperand(std::make_unique<RegOperand>(vreg));
load->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(offset)
));
new_instructions.push_back(std::move(load));
}
}
new_instructions.push_back(std::move(instr_ptr));
for (unsigned vreg : def) {
if (spilled_vregs.count(vreg)) {
int offset = frame_info.spill_offsets.at(vreg);
auto store = std::make_unique<MachineInstr>(RVOpcodes::SW);
store->addOperand(std::make_unique<RegOperand>(vreg));
store->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(offset)
));
new_instructions.push_back(std::move(store));
}
}
}
mbb->getInstructions() = std::move(new_instructions);
}
for (auto& mbb : MFunc->getBlocks()) {
for (auto& instr_ptr : mbb->getInstructions()) {
for (auto& op_ptr : instr_ptr->getOperands()) {
if(op_ptr->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(op_ptr.get());
if (reg_op->isVirtual()) {
unsigned vreg = reg_op->getVRegNum();
if (color_map.count(vreg)) {
reg_op->setPReg(color_map.at(vreg));
} else if (spilled_vregs.count(vreg)) {
reg_op->setPReg(PhysicalReg::T6); // 溢出统一用t6
}
}
} else if (op_ptr->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand*>(op_ptr.get());
auto base_reg_op = mem_op->getBase();
if(base_reg_op->isVirtual()){
unsigned vreg = base_reg_op->getVRegNum();
if(color_map.count(vreg)) {
base_reg_op->setPReg(color_map.at(vreg));
} else if (spilled_vregs.count(vreg)) {
base_reg_op->setPReg(PhysicalReg::T6);
}
}
}
}
}
}
}
} // namespace sysy

View File

@ -1,129 +0,0 @@
#include "Reg2Mem.h"
#include <cstddef>
#include <iostream>
#include <list>
#include <memory>
namespace sysy {
/**
* 删除phi节点
* 删除phi节点后可能会生成冗余存储代码
*/
void Reg2Mem::DeletePhiInst(){
auto &functions = pModule->getFunctions();
for (auto &function : functions) {
auto basicBlocks = function.second->getBasicBlocks();
for (auto &basicBlock : basicBlocks) {
for (auto iter = basicBlock->begin(); iter != basicBlock->end();) {
auto &instruction = *iter;
if (instruction->isPhi()) {
auto predBlocks = basicBlock->getPredecessors();
// 寻找源和目的
// 目的就是phi指令的第一个操作数
// 源就是phi指令的后续操作数
auto destination = instruction->getOperand(0);
int predBlockindex = 0;
for (auto &predBlock : predBlocks) {
++predBlockindex;
// 判断前驱块儿只有一个后继还是多个后继
// 如果有多个
auto source = instruction->getOperand(predBlockindex);
if (source == destination) {
continue;
}
// std::cout << predBlock->getNumSuccessors() << std::endl;
if (predBlock->getNumSuccessors() > 1) {
// 创建一个basicblock
auto newbasicBlock = function.second->addBasicBlock();
std::stringstream ss;
ss << " phidel.L" << pBuilder->getLabelIndex();
newbasicBlock->setName(ss.str());
ss.str("");
// // 修改前驱后继关系
basicBlock->replacePredecessor(predBlock, newbasicBlock);
// predBlock = newbasicBlock;
newbasicBlock->addPredecessor(predBlock);
newbasicBlock->addSuccessor(basicBlock.get());
predBlock->removeSuccessor(basicBlock.get());
predBlock->addSuccessor(newbasicBlock);
// std::cout << "the block name is " << basicBlock->getName() << std::endl;
// for (auto pb : basicBlock->getPredecessors()) {
// // newbasicBlock->addPredecessor(pb);
// std::cout << pb->getName() << std::endl;
// }
// sysy::BasicBlock::conectBlocks(newbasicBlock, static_cast<BasicBlock *>(basicBlock.get()));
// 若后为跳转指令,应该修改跳转指令所到达的位置
auto thelastinst = predBlock->end();
(--thelastinst);
if (thelastinst->get()->isConditional() || thelastinst->get()->isUnconditional()) { // 如果是跳转指令
auto opnum = thelastinst->get()->getNumOperands();
for (size_t i = 0; i < opnum; i++) {
if (thelastinst->get()->getOperand(i) == basicBlock.get()) {
thelastinst->get()->replaceOperand(i, newbasicBlock);
}
}
}
// 在新块中插入store指令
pBuilder->setPosition(newbasicBlock, newbasicBlock->end());
// pBuilder->createStoreInst(source, destination);
if (source->isInt() || source->isFloat()) {
pBuilder->createStoreInst(source, destination);
} else {
auto loadInst = pBuilder->createLoadInst(source);
pBuilder->createStoreInst(loadInst, destination);
}
// pBuilder->createMoveInst(Instruction::kMove, destination->getType(), destination, source,
// newbasicBlock);
pBuilder->setPosition(newbasicBlock, newbasicBlock->end());
pBuilder->createUncondBrInst(basicBlock.get(), {});
} else {
// 如果前驱块只有一个后继
auto thelastinst = predBlock->end();
(--thelastinst);
// std::cout << predBlock->getName() << std::endl;
// std::cout << thelastinst->get() << std::endl;
// std::cout << "First point 11 " << std::endl;
if (thelastinst->get()->isConditional() || thelastinst->get()->isUnconditional()) {
// 在跳转语句前insert st指令
pBuilder->setPosition(predBlock, thelastinst);
} else {
pBuilder->setPosition(predBlock, predBlock->end());
}
if (source->isInt() || source->isFloat()) {
pBuilder->createStoreInst(source, destination);
} else {
auto loadInst = pBuilder->createLoadInst(source);
pBuilder->createStoreInst(loadInst, destination);
}
}
}
// 删除phi指令
auto &instructions = basicBlock->getInstructions();
usedelete(iter->get());
iter = instructions.erase(iter);
if (basicBlock->getNumInstructions() == 0) {
if (basicBlock->getNumSuccessors() == 1) {
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
pBuilder->createUncondBrInst(basicBlock->getSuccessors()[0], {});
}
}
} else {
break;
}
}
}
}
}
void Reg2Mem::usedelete(Instruction *instr) {
for (auto &use : instr->getOperands()) {
auto val = use->getValue();
val->removeUse(use);
}
}
} // namespace sysy

View File

@ -1,532 +0,0 @@
#include "SysYIRAnalyser.h"
#include <iostream>
namespace sysy {
void ControlFlowAnalysis::init() {
// 初始化分析器
auto &functions = pModule->getFunctions();
for (const auto &function : functions) {
auto func = function.second.get();
auto basicBlocks = func->getBasicBlocks();
for (auto &basicBlock : basicBlocks) {
blockAnalysisInfo[basicBlock.get()] = new BlockAnalysisInfo();
blockAnalysisInfo[basicBlock.get()]->clear();
}
functionAnalysisInfo[func] = new FunctionAnalysisInfo();
functionAnalysisInfo[func]->clear();
}
}
void ControlFlowAnalysis::runControlFlowAnalysis() {
// 运行控制流分析
clear(); // 清空之前的分析结果
init(); // 初始化分析器
computeDomNode();
computeDomTree();
computeDomFrontierAllBlk();
}
void ControlFlowAnalysis::intersectOP4Dom(std::unordered_set<BasicBlock *> &dom, const std::unordered_set<BasicBlock *> &other) {
// 计算交集
for (auto it = dom.begin(); it != dom.end();) {
if (other.find(*it) == other.end()) {
// 如果other中没有这个基本块则从dom中删除
it = dom.erase(it);
} else {
++it;
}
}
}
auto ControlFlowAnalysis::findCommonDominator(BasicBlock *a, BasicBlock *b) -> BasicBlock * {
// 查找两个基本块的共同支配结点
while (a != b) {
BlockAnalysisInfo* infoA = blockAnalysisInfo[a];
BlockAnalysisInfo* infoB = blockAnalysisInfo[b];
// 如果深度不同,则向上移动到直接支配结点
// TODO空间换时间倍增优化优先级较低
while (infoA->getDomDepth() > infoB->getDomDepth()) {
a = const_cast<BasicBlock*>(infoA->getIdom());
infoA = blockAnalysisInfo[a];
}
while (infoB->getDomDepth() > infoA->getDomDepth()) {
b = const_cast<BasicBlock*>(infoB->getIdom());
infoB = blockAnalysisInfo[b];
}
if (a == b) break;
a = const_cast<BasicBlock*>(infoA->getIdom());
b = const_cast<BasicBlock*>(infoB->getIdom());
}
return a;
}
void ControlFlowAnalysis::computeDomNode(){
auto &functions = pModule->getFunctions();
// 分析每个函数内的基本块
for (const auto &function : functions) {
auto func = function.second.get();
auto basicBlocks = func->getBasicBlocks();
std::unordered_set<BasicBlock *> domSetTmp;
// 一开始把domSetTmp置为所有block
auto entry_block = func->getEntryBlock();
entry_block->setName("Entry");
blockAnalysisInfo[entry_block]->addDominants(entry_block);
for (auto &basicBlock : basicBlocks) {
domSetTmp.emplace(basicBlock.get());
}
// 初始化
for (auto &basicBlock : basicBlocks) {
if (basicBlock.get() != entry_block) {
blockAnalysisInfo[basicBlock.get()]->setDominants(domSetTmp);
// 先把所有block的必经结点都设为N
}
}
// 支配节点计算公式
//DOM[B]={B} {⋂P∈pred(B) DOM[P]}
// 其中pred(B)是B的所有前驱结点
// 迭代计算支配结点,直到不再变化
// 这里使用迭代法,直到支配结点不再变化
// TODOLengauer-Tarjan 算法可以更高效地计算支配结点
// 或者按照CFG拓扑序遍历效率更高
bool changed = true;
while (changed) {
changed = false;
// 循环非start结点
for (auto &basicBlock : basicBlocks) {
if (basicBlock.get() != entry_block) {
auto olddom =
blockAnalysisInfo[basicBlock.get()]->getDominants();
std::unordered_set<BasicBlock *> dom =
blockAnalysisInfo[basicBlock->getPredecessors().front()]->getDominants();
// 对于每个基本块,计算其支配结点
// 取其前驱结点的支配结点的交集和自己
for (auto pred : basicBlock->getPredecessors()) {
intersectOP4Dom(dom, blockAnalysisInfo[pred]->getDominants());
}
dom.emplace(basicBlock.get());
blockAnalysisInfo[basicBlock.get()]->setDominants(dom);
if (dom != olddom) {
changed = true;
}
}
}
}
}
}
// TODO SEMI-NCA算法改进
void ControlFlowAnalysis::computeDomTree() {
// 构造支配树
auto &functions = pModule->getFunctions();
for (const auto &function : functions) {
auto func = function.second.get();
auto basicBlocks = func->getBasicBlocks();
auto entry_block = func->getEntryBlock();
blockAnalysisInfo[entry_block]->setIdom(entry_block);
blockAnalysisInfo[entry_block]->setDomDepth(0); // 入口块深度为0
bool changed = true;
while (changed) {
changed = false;
for (auto &basicBlock : basicBlocks) {
if (basicBlock.get() == entry_block) continue;
BasicBlock *new_idom = nullptr;
for (auto pred : basicBlock->getPredecessors()) {
// 跳过未处理的前驱
if (blockAnalysisInfo[pred]->getIdom() == nullptr) continue;
// new_idom = (new_idom == nullptr) ? pred : findCommonDominator(new_idom, pred);
if (new_idom == nullptr)
new_idom = pred;
else
new_idom = findCommonDominator(new_idom, pred);
}
// 更新直接支配节点
if (new_idom && new_idom != blockAnalysisInfo[basicBlock.get()]->getIdom()) {
// 移除旧的支配关系
if (blockAnalysisInfo[basicBlock.get()]->getIdom()) {
blockAnalysisInfo[const_cast<BasicBlock*>(blockAnalysisInfo[basicBlock.get()]->getIdom())]->removeSdoms(basicBlock.get());
}
// 设置新的支配关系
// std::cout << "Block: " << basicBlock->getName()
// << " New Idom: " << new_idom->getName() << std::endl;
blockAnalysisInfo[basicBlock.get()]->setIdom(new_idom);
blockAnalysisInfo[new_idom]->addSdoms(basicBlock.get());
// 更新深度 = 直接支配节点深度 + 1
blockAnalysisInfo[basicBlock.get()]->setDomDepth(
blockAnalysisInfo[new_idom]->getDomDepth() + 1);
changed = true;
}
}
}
}
// for (auto &basicBlock : basicBlocks) {
// if (basicBlock.get() != func->getEntryBlock()) {
// auto dominats =
// blockAnalysisInfo[basicBlock.get()]->getDominants();
// bool found = false;
// // 从前驱结点开始寻找直接支配结点
// std::queue<BasicBlock *> q;
// for (auto pred : basicBlock->getPredecessors()) {
// q.push(pred);
// }
// // BFS遍历前驱结点直到找到直接支配结点
// while (!found && !q.empty()) {
// auto curr = q.front();
// q.pop();
// if (curr == basicBlock.get())
// continue;
// if (dominats.count(curr) != 0U) {
// blockAnalysisInfo[basicBlock.get()]->setIdom(curr);
// blockAnalysisInfo[curr]->addSdoms(basicBlock.get());
// found = true;
// } else {
// for (auto pred : curr->getPredecessors()) {
// q.push(pred);
// }
// }
// }
// }
// }
}
// std::unordered_set<BasicBlock *> ControlFlowAnalysis::computeDomFrontier(BasicBlock *block) {
// std::unordered_set<BasicBlock *> ret_list;
// // 计算 localDF
// for (auto local_successor : block->getSuccessors()) {
// if (local_successor->getIdom() != block) {
// ret_list.emplace(local_successor);
// }
// }
// // 计算 upDF
// for (auto up_successor : block->getSdoms()) {
// auto childrenDF = computeDF(up_successor);
// for (auto w : childrenDF) {
// if (block != w->getIdom() || block == w) {
// ret_list.emplace(w);
// }
// }
// }
// return ret_list;
// }
void ControlFlowAnalysis::computeDomFrontierAllBlk() {
auto &functions = pModule->getFunctions();
for (const auto &function : functions) {
auto func = function.second.get();
auto basicBlocks = func->getBasicBlocks();
// 按支配树深度排序(从深到浅)
std::vector<BasicBlock *> orderedBlocks;
for (auto &bb : basicBlocks) {
orderedBlocks.push_back(bb.get());
}
std::sort(orderedBlocks.begin(), orderedBlocks.end(),
[this](BasicBlock *a, BasicBlock *b) {
return blockAnalysisInfo[a]->getDomDepth() > blockAnalysisInfo[b]->getDomDepth();
});
// 计算支配边界
for (auto block : orderedBlocks) {
std::unordered_set<BasicBlock *> df;
// Local DF: 直接后继中不被当前块支配的
for (auto succ : block->getSuccessors()) {
// 当前块不支配该后继(即不是其直接支配节点)
if (blockAnalysisInfo[succ]->getIdom() != block) {
df.insert(succ);
}
}
// Up DF: 从支配子树中继承
for (auto child : blockAnalysisInfo[block]->getSdoms()) {
for (auto w : blockAnalysisInfo[child]->getDomFrontiers()) {
// 如果w不被当前块支配
if (block != blockAnalysisInfo[w]->getIdom()) {
df.insert(w);
}
}
}
blockAnalysisInfo[block]->setDomFrontiers(df);
}
}
}
// ==========================
// dataflow analysis utils
// ==========================
// 先引用学长的代码
// TODO: Worklist 增加逆后序遍历机制
void DataFlowAnalysisUtils::forwardAnalyze(Module *pModule){
std::map<DataFlowAnalysis *, bool> workAnalysis;
for (auto &dataflow : forwardAnalysisList) {
dataflow->init(pModule);
}
for (const auto &function : pModule->getFunctions()) {
for (auto &dataflow : forwardAnalysisList) {
workAnalysis.emplace(dataflow, false);
}
while (!workAnalysis.empty()) {
for (const auto &block : function.second->getBasicBlocks()) {
for (auto &elem : workAnalysis) {
if (elem.first->analyze(pModule, block.get())) {
elem.second = true;
}
}
}
std::map<DataFlowAnalysis *, bool> tmp;
std::remove_copy_if(workAnalysis.begin(), workAnalysis.end(), std::inserter(tmp, tmp.end()),
[](const std::pair<DataFlowAnalysis *, bool> &elem) -> bool { return !elem.second; });
workAnalysis.swap(tmp);
for (auto &elem : workAnalysis) {
elem.second = false;
}
}
}
}
void DataFlowAnalysisUtils::backwardAnalyze(Module *pModule) {
std::map<DataFlowAnalysis *, bool> workAnalysis;
for (auto &dataflow : backwardAnalysisList) {
dataflow->init(pModule);
}
for (const auto &function : pModule->getFunctions()) {
for (auto &dataflow : backwardAnalysisList) {
workAnalysis.emplace(dataflow, false);
}
while (!workAnalysis.empty()) {
for (const auto &block : function.second->getBasicBlocks()) {
for (auto &elem : workAnalysis) {
if (elem.first->analyze(pModule, block.get())) {
elem.second = true;
}
}
}
std::map<DataFlowAnalysis *, bool> tmp;
std::remove_copy_if(workAnalysis.begin(), workAnalysis.end(), std::inserter(tmp, tmp.end()),
[](const std::pair<DataFlowAnalysis *, bool> &elem) -> bool { return !elem.second; });
workAnalysis.swap(tmp);
for (auto &elem : workAnalysis) {
elem.second = false;
}
}
}
}
std::set<User *> ActiveVarAnalysis::getUsedSet(Instruction *inst) {
using Kind = Instruction::Kind;
std::vector<User *> operands;
for (const auto &operand : inst->getOperands()) {
operands.emplace_back(dynamic_cast<User *>(operand->getValue()));
}
std::set<User *> result;
switch (inst->getKind()) {
// phi op
case Kind::kPhi:
case Kind::kCall:
result.insert(std::next(operands.begin()), operands.end());
break;
case Kind::kCondBr:
result.insert(operands[0]);
break;
case Kind::kBr:
case Kind::kAlloca:
break;
// mem op
case Kind::kStore:
// StoreInst 的第一个操作数是被存储的值,第二个操作数是存储的变量
// 后续的是可能的数组维度
result.insert(operands[0]);
result.insert(operands.begin() + 2, operands.end());
break;
case Kind::kLoad:
case Kind::kLa: {
auto variable = dynamic_cast<AllocaInst *>(operands[0]);
auto global = dynamic_cast<GlobalValue *>(operands[0]);
auto constArray = dynamic_cast<ConstantVariable *>(operands[0]);
if ((variable != nullptr && variable->getNumDims() == 0) || (global != nullptr && global->getNumDims() == 0) ||
(constArray != nullptr && constArray->getNumDims() == 0)) {
result.insert(operands[0]);
}
result.insert(std::next(operands.begin()), operands.end());
break;
}
case Kind::kGetSubArray: {
for (unsigned i = 2; i < operands.size(); i++) {
// 数组的维度信息
result.insert(operands[i]);
}
break;
}
case Kind::kMemset: {
result.insert(std::next(operands.begin()), operands.end());
break;
}
case Kind::kInvalid:
// Binary
case Kind::kAdd:
case Kind::kSub:
case Kind::kMul:
case Kind::kDiv:
case Kind::kRem:
case Kind::kICmpEQ:
case Kind::kICmpNE:
case Kind::kICmpLT:
case Kind::kICmpLE:
case Kind::kICmpGT:
case Kind::kICmpGE:
case Kind::kFAdd:
case Kind::kFSub:
case Kind::kFMul:
case Kind::kFDiv:
case Kind::kFCmpEQ:
case Kind::kFCmpNE:
case Kind::kFCmpLT:
case Kind::kFCmpLE:
case Kind::kFCmpGT:
case Kind::kFCmpGE:
case Kind::kAnd:
case Kind::kOr:
// Unary
case Kind::kNeg:
case Kind::kNot:
case Kind::kFNot:
case Kind::kFNeg:
case Kind::kFtoI:
case Kind::kItoF:
// terminator
case Kind::kReturn:
result.insert(operands.begin(), operands.end());
break;
default:
assert(false);
break;
}
result.erase(nullptr);
return result;
}
User * ActiveVarAnalysis::getDefine(Instruction *inst) {
User *result = nullptr;
if (inst->isStore()) {
StoreInst* store = dynamic_cast<StoreInst *>(inst);
auto operand = store->getPointer();
AllocaInst* variable = dynamic_cast<AllocaInst *>(operand);
GlobalValue* global = dynamic_cast<GlobalValue *>(operand);
if ((variable != nullptr && variable->getNumDims() != 0) || (global != nullptr && global->getNumDims() != 0)) {
// 如果是数组变量或者全局变量,则不返回定义
// TODO兼容数组变量
result = nullptr;
} else {
result = dynamic_cast<User *>(operand);
}
} else if (inst->isPhi()) {
result = dynamic_cast<User *>(inst->getOperand(0));
} else if (inst->isBinary() || inst->isUnary() || inst->isCall() ||
inst->isLoad() || inst->isLa()) {
result = dynamic_cast<User *>(inst);
}
return result;
}
void ActiveVarAnalysis::init(Module *pModule) {
for (const auto &function : pModule->getFunctions()) {
for (const auto &block : function.second->getBasicBlocks()) {
activeTable.emplace(block.get(), std::vector<std::set<User *>>{});
for (unsigned i = 0; i < block->getNumInstructions() + 1; i++)
activeTable.at(block.get()).emplace_back();
}
}
}
// 活跃变量分析公式 每个块内的分析动作供分析器调用
bool ActiveVarAnalysis::analyze(Module *pModule, BasicBlock *block) {
bool changed = false; // 标记数据流结果是否有变化
std::set<User *> activeSet{}; // 当前计算的活跃变量集合
// 步骤1: 计算基本块出口的活跃变量集 (OUT[B])
// 公式: OUT[B] = _{S ∈ succ(B)} IN[S]
for (const auto &succ : block->getSuccessors()) {
// 获取后继块入口的活跃变量集 (IN[S])
auto succActiveSet = activeTable.at(succ).front();
// 合并所有后继块的入口活跃变量
activeSet.insert(succActiveSet.begin(), succActiveSet.end());
}
// 步骤2: 处理基本块出口处的活跃变量集
const auto &instructions = block->getInstructions();
const auto numInstructions = instructions.size();
// 获取旧的出口活跃变量集 (block出口对应索引numInstructions)
const auto &oldEndActiveSet = activeTable.at(block)[numInstructions];
// 检查出口活跃变量集是否有变化
if (!std::equal(activeSet.begin(), activeSet.end(),
oldEndActiveSet.begin(), oldEndActiveSet.end()))
{
changed = true; // 标记变化
activeTable.at(block)[numInstructions] = activeSet; // 更新出口活跃变量集
}
// 步骤3: 逆序遍历基本块中的指令
// 从最后一条指令开始向前计算每个程序点的活跃变量
auto instructionIter = instructions.end();
instructionIter--; // 指向最后一条指令
// 从出口向入口遍历 (索引从numInstructions递减到1)
for (unsigned i = numInstructions; i > 0; i--) {
auto inst = instructionIter->get(); // 当前指令
auto used = getUsedSet(inst);
User *defined = getDefine(inst);
// 步骤3.3: 计算指令入口的活跃变量 (IN[i])
// 公式: IN[i] = use_i (OUT[i] - def_i)
activeSet.erase(defined); // 移除被定义的变量 (OUT[i] - def_i)
activeSet.insert(used.begin(), used.end()); // 添加使用的变量
// 获取旧的入口活跃变量集 (位置i-1对应当前指令的入口)
const auto &oldActiveSet = activeTable.at(block)[i - 1];
// 检查活跃变量集是否有变化
if (!std::equal(activeSet.begin(), activeSet.end(),
oldActiveSet.begin(), oldActiveSet.end()))
{
changed = true; // 标记变化
activeTable.at(block)[i - 1] = activeSet; // 更新入口活跃变量集
}
instructionIter--; // 移动到前一条指令
}
return changed; // 返回数据流结果是否变化
}
auto ActiveVarAnalysis::getActiveTable() const -> const std::map<BasicBlock *, std::vector<std::set<User *>>> & {
return activeTable;
}
} // namespace sysy

File diff suppressed because it is too large Load Diff

View File

@ -1,484 +0,0 @@
#include "SysYIROptPre.h"
#include <cassert>
#include <list>
#include <map>
#include <memory>
#include <string>
#include <iostream>
#include "IR.h"
#include "IRBuilder.h"
namespace sysy {
/**
* use删除operand,以免扰乱后续分析
* instr: 要删除的指令
*/
void SysYOptPre::usedelete(Instruction *instr) {
for (auto &use : instr->getOperands()) {
Value* val = use->getValue();
// std::cout << delete << val->getName() << std::endl;
val->removeUse(use);
}
}
// 删除br后的无用指令
void SysYOptPre::SysYDelInstAfterBr() {
auto &functions = pModule->getFunctions();
for (auto &function : functions) {
auto basicBlocks = function.second->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 (Branch)
usedelete(iter->get());
else if ((*iter)->isTerminator()){
Branch = true;
Branchiter = iter;
}
}
if (Branchiter != instructions.end()) ++Branchiter;
while (Branchiter != instructions.end())
Branchiter = instructions.erase(Branchiter);
if (Branch) { // 更新前驱后继关系
auto thelastinstinst = basicBlock->getInstructions().end();
--thelastinstinst;
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));
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));
basicBlock->addSuccessor(thenBlock);
basicBlock->addSuccessor(elseBlock);
thenBlock->addPredecessor(basicBlock.get());
elseBlock->addPredecessor(basicBlock.get());
}
}
}
}
}
void SysYOptPre::SysYBlockMerge() {
auto &functions = pModule->getFunctions(); //std::map<std::string, std::unique_ptr<Function>>
for (auto &function : functions) {
// auto basicBlocks = function.second->getBasicBlocks();
auto &func = function.second;
for (auto blockiter = func->getBasicBlocks().begin();
blockiter != func->getBasicBlocks().end();) {
if (blockiter->get()->getNumSuccessors() == 1) {
// 如果当前块只有一个后继块
// 且后继块只有一个前驱块
// 则将当前块和后继块合并
if (((blockiter->get())->getSuccessors()[0])->getNumPredecessors() == 1) {
// std::cout << "merge block: " << blockiter->get()->getName() << std::endl;
BasicBlock* block = blockiter->get();
BasicBlock* nextBlock = blockiter->get()->getSuccessors()[0];
auto nextarguments = nextBlock->getArguments();
// 删除br指令
if (block->getNumInstructions() != 0) {
auto thelastinstinst = block->end();
(--thelastinstinst);
if (thelastinstinst->get()->isUnconditional()) {
usedelete(thelastinstinst->get());
block->getInstructions().erase(thelastinstinst);
} else if (thelastinstinst->get()->isConditional()) {
// 如果是条件分支,判断条件是否相同,主要优化相同布尔表达式
if (thelastinstinst->get()->getOperand(1)->getName() == thelastinstinst->get()->getOperand(1)->getName()) {
usedelete(thelastinstinst->get());
block->getInstructions().erase(thelastinstinst);
}
}
}
// 将后继块的指令移动到当前块
// 并将后继块的父指针改为当前块
for (auto institer = nextBlock->begin(); institer != nextBlock->end();) {
institer->get()->setParent(block);
block->getInstructions().emplace_back(institer->release());
institer = nextBlock->getInstructions().erase(institer);
}
// 合并参数
// TODO是否需要去重?
for (auto &argm : nextarguments) {
argm->setParent(block);
block->insertArgument(argm);
}
// 更新前驱后继关系,类似树节点操作
block->removeSuccessor(nextBlock);
nextBlock->removePredecessor(block);
std::list<BasicBlock *> succshoulddel;
for (auto &succ : nextBlock->getSuccessors()) {
block->addSuccessor(succ);
succ->replacePredecessor(nextBlock, block);
succshoulddel.push_back(succ);
}
for (auto del : succshoulddel) {
nextBlock->removeSuccessor(del);
}
func->removeBasicBlock(nextBlock);
} else {
blockiter++;
}
} else {
blockiter++;
}
}
}
}
// 删除无前驱块兼容SSA后的处理
void SysYOptPre::SysYDelNoPreBLock() {
auto &functions = pModule->getFunctions(); // std::map<std::string, std::unique_ptr<sysy::Function>>
for (auto &function : functions) {
auto &func = function.second;
for (auto &block : func->getBasicBlocks()) {
block->setreachableFalse();
}
// 对函数基本块做一个拓扑排序,排查不可达基本块
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);
}
}
}
// 删除不可达基本块指令
for (auto blockIter = func->getBasicBlocks().begin(); blockIter != func->getBasicBlocks().end();blockIter++) {
if (!blockIter->get()->getreachable())
for (auto &iterInst : blockIter->get()->getInstructions())
usedelete(iterInst.get());
}
for (auto blockIter = func->getBasicBlocks().begin(); blockIter != func->getBasicBlocks().end();) {
if (!blockIter->get()->getreachable()) {
for (auto succblock : blockIter->get()->getSuccessors()) {
int indexphi = 1;
for (auto pred : succblock->getPredecessors()) {
if (pred == blockIter->get()) {
break;
}
indexphi++;
}
for (auto &phiinst : succblock->getInstructions()) {
if (phiinst->getKind() != Instruction::kPhi) {
break;
}
phiinst->removeOperand(indexphi);
}
}
// 删除不可达基本块,注意迭代器不可达问题
func->removeBasicBlock((blockIter++)->get());
} else {
blockIter++;
}
}
}
}
void SysYOptPre::SysYDelEmptyBlock() {
auto &functions = pModule->getFunctions();
for (auto &function : functions) {
// 收集不可达基本块
// 这里的不可达基本块是指没有实际指令的基本块
// 当一个基本块没有实际指令例如只有phi指令和一个uncondbr指令时也会被视作不可达
auto basicBlocks = function.second->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)
EmptyBlocks[basicBlock.get()] = basicBlock->getSuccessors().front();
}
}
// 更新基本块信息,增加必要指令
for (auto &basicBlock : basicBlocks) {
// 把空块转换成只有跳转指令的不可达块
if (distance(basicBlock->begin(), basicBlock->end()) == 0) {
if (basicBlock->getNumSuccessors() == 0) {
continue;
}
if (basicBlock->getNumSuccessors() > 1) {
assert("");
}
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
pBuilder->createUncondBrInst(basicBlock->getSuccessors()[0], {});
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.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))) !=
EmptyBlocks.end()) {
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
thelastinst->get()->replaceOperand(0, EmptyBlocks[thelastBlockOld]);
}
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());
if (thelastBlockOld != nullptr) {
int indexphi = 0;
for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getPredecessors()) {
if (pred == thelastBlockOld) {
break;
}
indexphi++;
}
// 更新phi指令的操作数
// 移除thelastBlockOld对应的phi操作数
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getInstructions()) {
if (InstInNew->isPhi()) {
dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
} else {
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));
BasicBlock *thelastBlockOld = nullptr;
while (EmptyBlocks.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))) !=
EmptyBlocks.end()) {
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
thelastinst->get()->replaceOperand(
1, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))]);
}
basicBlock->removeSuccessor(OldThenBlock);
OldThenBlock->removePredecessor(basicBlock.get());
// 处理 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));
usedelete(thelastinst->get());
thelastinst = basicBlock->getInstructions().erase(thelastinst);
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
pBuilder->createUncondBrInst(thebrBlock, {});
continue;
}
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)));
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->addPredecessor(basicBlock.get());
// auto indexInNew = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getPredecessors().
if (thelastBlockOld != nullptr) {
int indexphi = 0;
for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->getPredecessors()) {
if (pred == thelastBlockOld) {
break;
}
indexphi++;
}
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->getInstructions()) {
if (InstInNew->isPhi()) {
dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
} else {
break;
}
}
}
thelastBlockOld = nullptr;
while (EmptyBlocks.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) !=
EmptyBlocks.end()) {
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2));
thelastinst->get()->replaceOperand(
2, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))]);
}
basicBlock->removeSuccessor(OldElseBlock);
OldElseBlock->removePredecessor(basicBlock.get());
// 处理 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));
usedelete(thelastinst->get());
thelastinst = basicBlock->getInstructions().erase(thelastinst);
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
pBuilder->createUncondBrInst(thebrBlock, {});
continue;
}
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2)));
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->addPredecessor(basicBlock.get());
if (thelastBlockOld != nullptr) {
int indexphi = 0;
for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->getPredecessors()) {
if (pred == thelastBlockOld) {
break;
}
indexphi++;
}
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->getInstructions()) {
if (InstInNew->isPhi()) {
dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
} else {
break;
}
}
}
} else {
if (basicBlock->getNumSuccessors() == 1) {
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());
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 = function.second->getBasicBlocks().begin(); iter != function.second->getBasicBlocks().end();) {
if (EmptyBlocks.find(iter->get()) != EmptyBlocks.end()) {
// EntryBlock跳过
if (iter->get() == function.second->getEntryBlock()) {
++iter;
continue;
}
for (auto &iterInst : iter->get()->getInstructions())
usedelete(iterInst.get());
// 删除不可达基本块的phi指令的操作数
for (auto &succ : iter->get()->getSuccessors()) {
int index = 0;
for (auto &pred : succ->getPredecessors()) {
if (pred == iter->get()) {
break;
}
index++;
}
for (auto &instinsucc : succ->getInstructions()) {
if (instinsucc->isPhi()) {
dynamic_cast<PhiInst *>(instinsucc.get())->removeOperand(index);
} else {
break;
}
}
}
function.second->removeBasicBlock((iter++)->get());
} else {
++iter;
}
}
}
}
// 如果函数没有返回指令,则添加一个默认返回指令(主要解决void函数没有返回指令的问题)
void SysYOptPre::SysYAddReturn() {
auto &functions = pModule->getFunctions();
for (auto &function : functions) {
auto &func = function.second;
auto basicBlocks = func->getBasicBlocks();
for (auto &block : basicBlocks) {
if (block->getNumSuccessors() == 0) {
// 如果基本块没有后继块,则添加一个返回指令
if (block->getNumInstructions() == 0) {
pBuilder->setPosition(block.get(), block->end());
pBuilder->createReturnInst();
}
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;
pBuilder->setPosition(block.get(), block->end());
// TODO: 如果int float函数缺少返回值是否需要报错
if (func->getReturnType()->isInt()) {
pBuilder->createReturnInst(ConstantInteger::get(0));
} else if (func->getReturnType()->isFloat()) {
pBuilder->createReturnInst(ConstantFloating::get(0.0F));
} else {
pBuilder->createReturnInst();
}
}
}
}
}
}
} // namespace sysy

View File

@ -1,483 +0,0 @@
#include "SysYIRPrinter.h"
#include <cassert>
#include <fstream>
#include <iostream>
#include <string>
#include "IR.h"
namespace sysy {
void SysYPrinter::printIR() {
const auto &functions = pModule->getFunctions();
//TODO: Print target datalayout and triple (minimal required by LLVM)
printGlobalVariable();
for (const auto &iter : functions) {
if (iter.second->getName() == "main") {
printFunction(iter.second.get());
break;
}
}
for (const auto &iter : functions) {
if (iter.second->getName() != "main") {
printFunction(iter.second.get());
}
}
}
std::string SysYPrinter::getTypeString(Type *type) {
if (type->isVoid()) {
return "void";
} else if (type->isInt()) {
return "i32";
} else if (type->isFloat()) {
return "float";
} else if (auto ptrType = dynamic_cast<PointerType*>(type)) {
return getTypeString(ptrType->getBaseType()) + "*";
} else if (auto ptrType = dynamic_cast<FunctionType*>(type)) {
return getTypeString(ptrType->getReturnType());
}
assert(false && "Unsupported type");
return "";
}
std::string SysYPrinter::getValueName(Value *value) {
if (auto global = dynamic_cast<GlobalValue*>(value)) {
return "@" + global->getName();
} else if (auto inst = dynamic_cast<Instruction*>(value)) {
return "%" + inst->getName();
} else if (auto constVal = dynamic_cast<ConstantValue*>(value)) {
if (constVal->isFloat()) {
return std::to_string(constVal->getFloat());
}
return std::to_string(constVal->getInt());
} else if (auto constVar = dynamic_cast<ConstantVariable*>(value)) {
return constVar->getName();
}
assert(false && "Unknown value type");
return "";
}
void SysYPrinter::printType(Type *type) {
std::cout << getTypeString(type);
}
void SysYPrinter::printValue(Value *value) {
std::cout << getValueName(value);
}
void SysYPrinter::printGlobalVariable() {
auto &globals = pModule->getGlobals();
for (const auto &global : globals) {
std::cout << "@" << global->getName() << " = global ";
auto baseType = dynamic_cast<PointerType *>(global->getType())->getBaseType();
printType(baseType);
if (global->getNumDims() > 0) {
// Array type
std::cout << " [";
for (unsigned i = 0; i < global->getNumDims(); i++) {
if (i > 0) std::cout << " x ";
std::cout << getValueName(global->getDim(i));
}
std::cout << "]";
}
std::cout << " ";
if (global->getNumDims() > 0) {
// Array initializer
std::cout << "[";
auto values = global->getInitValues();
auto counterValues = values.getValues();
auto counterNumbers = values.getNumbers();
for (size_t i = 0; i < counterNumbers.size(); i++) {
if (i > 0) std::cout << ", ";
if (baseType->isFloat()) {
std::cout << "float " << dynamic_cast<ConstantValue*>(counterValues[i])->getFloat();
} else {
std::cout << "i32 " << dynamic_cast<ConstantValue*>(counterValues[i])->getInt();
}
}
std::cout << "]";
} else {
// Scalar initializer
if (baseType->isFloat()) {
std::cout << "float " << dynamic_cast<ConstantValue*>(global->getByIndex(0))->getFloat();
} else {
std::cout << "i32 " << dynamic_cast<ConstantValue*>(global->getByIndex(0))->getInt();
}
}
std::cout << ", align 4" << std::endl;
}
}
void SysYPrinter::printFunction(Function *function) {
// Function signature
std::cout << "define ";
printType(function->getReturnType());
std::cout << " @" << function->getName() << "(";
auto entryBlock = function->getEntryBlock();
const auto &args_types = function->getParamTypes();
auto &args = entryBlock->getArguments();
int i = 0;
for (const auto &args_type : args_types) {
if (i > 0) std::cout << ", ";
printType(args_type);
std::cout << " %" << args[i]->getName();
i++;
}
std::cout << ") {" << std::endl;
// Function body
for (const auto &blockIter : function->getBasicBlocks()) {
// Basic block label
BasicBlock* blockPtr = blockIter.get();
if (blockPtr == function->getEntryBlock()) {
std::cout << "entry:" << std::endl;
} else if (!blockPtr->getName().empty()) {
std::cout << blockPtr->getName() << ":" << std::endl;
}
// Instructions
for (const auto &instIter : blockIter->getInstructions()) {
auto inst = instIter.get();
std::cout << " ";
printInst(inst);
}
}
std::cout << "}" << std::endl << std::endl;
}
void SysYPrinter::printInst(Instruction *pInst) {
using Kind = Instruction::Kind;
switch (pInst->getKind()) {
case Kind::kAdd:
case Kind::kSub:
case Kind::kMul:
case Kind::kDiv:
case Kind::kRem:
case Kind::kFAdd:
case Kind::kFSub:
case Kind::kFMul:
case Kind::kFDiv:
case Kind::kICmpEQ:
case Kind::kICmpNE:
case Kind::kICmpLT:
case Kind::kICmpGT:
case Kind::kICmpLE:
case Kind::kICmpGE:
case Kind::kFCmpEQ:
case Kind::kFCmpNE:
case Kind::kFCmpLT:
case Kind::kFCmpGT:
case Kind::kFCmpLE:
case Kind::kFCmpGE:
case Kind::kAnd:
case Kind::kOr: {
auto binInst = dynamic_cast<BinaryInst *>(pInst);
// Print result variable if exists
if (!binInst->getName().empty()) {
std::cout << "%" << binInst->getName() << " = ";
}
// Operation name
switch (pInst->getKind()) {
case Kind::kAdd: std::cout << "add"; break;
case Kind::kSub: std::cout << "sub"; break;
case Kind::kMul: std::cout << "mul"; break;
case Kind::kDiv: std::cout << "sdiv"; break;
case Kind::kRem: std::cout << "srem"; break;
case Kind::kFAdd: std::cout << "fadd"; break;
case Kind::kFSub: std::cout << "fsub"; break;
case Kind::kFMul: std::cout << "fmul"; break;
case Kind::kFDiv: std::cout << "fdiv"; break;
case Kind::kICmpEQ: std::cout << "icmp eq"; break;
case Kind::kICmpNE: std::cout << "icmp ne"; break;
case Kind::kICmpLT: std::cout << "icmp slt"; break;
case Kind::kICmpGT: std::cout << "icmp sgt"; break;
case Kind::kICmpLE: std::cout << "icmp sle"; break;
case Kind::kICmpGE: std::cout << "icmp sge"; break;
case Kind::kFCmpEQ: std::cout << "fcmp oeq"; break;
case Kind::kFCmpNE: std::cout << "fcmp one"; break;
case Kind::kFCmpLT: std::cout << "fcmp olt"; break;
case Kind::kFCmpGT: std::cout << "fcmp ogt"; break;
case Kind::kFCmpLE: std::cout << "fcmp ole"; break;
case Kind::kFCmpGE: std::cout << "fcmp oge"; break;
case Kind::kAnd: std::cout << "and"; break;
case Kind::kOr: std::cout << "or"; break;
default: break;
}
// Types and operands
std::cout << " ";
printType(binInst->getType());
std::cout << " ";
printValue(binInst->getLhs());
std::cout << ", ";
printValue(binInst->getRhs());
std::cout << std::endl;
} break;
case Kind::kNeg:
case Kind::kNot:
case Kind::kFNeg:
case Kind::kFNot:
case Kind::kFtoI:
case Kind::kBitFtoI:
case Kind::kItoF:
case Kind::kBitItoF: {
auto unyInst = dynamic_cast<UnaryInst *>(pInst);
if (!unyInst->getName().empty()) {
std::cout << "%" << unyInst->getName() << " = ";
}
switch (pInst->getKind()) {
case Kind::kNeg: std::cout << "sub "; break;
case Kind::kNot: std::cout << "not "; break;
case Kind::kFNeg: std::cout << "fneg "; break;
case Kind::kFNot: std::cout << "fneg "; break; // FNot not standard, map to fneg
case Kind::kFtoI: std::cout << "fptosi "; break;
case Kind::kBitFtoI: std::cout << "bitcast "; break;
case Kind::kItoF: std::cout << "sitofp "; break;
case Kind::kBitItoF: std::cout << "bitcast "; break;
default: break;
}
printType(unyInst->getType());
std::cout << " ";
// Special handling for negation
if (pInst->getKind() == Kind::kNeg || pInst->getKind() == Kind::kNot) {
std::cout << "i32 0, ";
}
printValue(pInst->getOperand(0));
// For bitcast, need to specify destination type
if (pInst->getKind() == Kind::kBitFtoI || pInst->getKind() == Kind::kBitItoF) {
std::cout << " to ";
printType(unyInst->getType());
}
std::cout << std::endl;
} break;
case Kind::kCall: {
auto callInst = dynamic_cast<CallInst *>(pInst);
auto function = callInst->getCallee();
if (!callInst->getName().empty()) {
std::cout << "%" << callInst->getName() << " = ";
}
std::cout << "call ";
printType(callInst->getType());
std::cout << " @" << function->getName() << "(";
auto params = callInst->getArguments();
bool first = true;
for (auto &param : params) {
if (!first) std::cout << ", ";
first = false;
printType(param->getValue()->getType());
std::cout << " ";
printValue(param->getValue());
}
std::cout << ")" << std::endl;
} break;
case Kind::kCondBr: {
auto condBrInst = dynamic_cast<CondBrInst *>(pInst);
std::cout << "br i1 ";
printValue(condBrInst->getCondition());
std::cout << ", label %" << condBrInst->getThenBlock()->getName();
std::cout << ", label %" << condBrInst->getElseBlock()->getName();
std::cout << std::endl;
} break;
case Kind::kBr: {
auto brInst = dynamic_cast<UncondBrInst *>(pInst);
std::cout << "br label %" << brInst->getBlock()->getName();
std::cout << std::endl;
} break;
case Kind::kReturn: {
auto retInst = dynamic_cast<ReturnInst *>(pInst);
std::cout << "ret ";
if (retInst->getNumOperands() != 0) {
printType(retInst->getOperand(0)->getType());
std::cout << " ";
printValue(retInst->getOperand(0));
} else {
std::cout << "void";
}
std::cout << std::endl;
} break;
case Kind::kAlloca: {
auto allocaInst = dynamic_cast<AllocaInst *>(pInst);
std::cout << "%" << allocaInst->getName() << " = alloca ";
auto baseType = dynamic_cast<PointerType *>(allocaInst->getType())->getBaseType();
printType(baseType);
if (allocaInst->getNumDims() > 0) {
std::cout << ", ";
for (size_t i = 0; i < allocaInst->getNumDims(); i++) {
if (i > 0) std::cout << ", ";
printType(Type::getIntType());
std::cout << " ";
printValue(allocaInst->getDim(i));
}
}
std::cout << ", align 4" << std::endl;
} break;
case Kind::kLoad: {
auto loadInst = dynamic_cast<LoadInst *>(pInst);
std::cout << "%" << loadInst->getName() << " = load ";
printType(loadInst->getType());
std::cout << ", ";
printType(loadInst->getPointer()->getType());
std::cout << " ";
printValue(loadInst->getPointer());
if (loadInst->getNumIndices() > 0) {
std::cout << ", ";
for (size_t i = 0; i < loadInst->getNumIndices(); i++) {
if (i > 0) std::cout << ", ";
printType(Type::getIntType());
std::cout << " ";
printValue(loadInst->getIndex(i));
}
}
std::cout << ", align 4" << std::endl;
} break;
case Kind::kLa: {
auto laInst = dynamic_cast<LaInst *>(pInst);
std::cout << "%" << laInst->getName() << " = getelementptr inbounds ";
auto ptrType = dynamic_cast<PointerType*>(laInst->getPointer()->getType());
printType(ptrType->getBaseType());
std::cout << ", ";
printType(laInst->getPointer()->getType());
std::cout << " ";
printValue(laInst->getPointer());
std::cout << ", ";
for (size_t i = 0; i < laInst->getNumIndices(); i++) {
if (i > 0) std::cout << ", ";
printType(Type::getIntType());
std::cout << " ";
printValue(laInst->getIndex(i));
}
std::cout << std::endl;
} break;
case Kind::kStore: {
auto storeInst = dynamic_cast<StoreInst *>(pInst);
std::cout << "store ";
printType(storeInst->getValue()->getType());
std::cout << " ";
printValue(storeInst->getValue());
std::cout << ", ";
printType(storeInst->getPointer()->getType());
std::cout << " ";
printValue(storeInst->getPointer());
if (storeInst->getNumIndices() > 0) {
std::cout << ", ";
for (size_t i = 0; i < storeInst->getNumIndices(); i++) {
if (i > 0) std::cout << ", ";
printType(Type::getIntType());
std::cout << " ";
printValue(storeInst->getIndex(i));
}
}
std::cout << ", align 4" << std::endl;
} break;
case Kind::kMemset: {
auto memsetInst = dynamic_cast<MemsetInst *>(pInst);
std::cout << "call void @llvm.memset.p0.";
printType(memsetInst->getPointer()->getType());
std::cout << "(";
printType(memsetInst->getPointer()->getType());
std::cout << " ";
printValue(memsetInst->getPointer());
std::cout << ", i8 ";
printValue(memsetInst->getValue());
std::cout << ", i32 ";
printValue(memsetInst->getSize());
std::cout << ", i1 false)" << std::endl;
} break;
case Kind::kPhi: {
auto phiInst = dynamic_cast<PhiInst *>(pInst);
printValue(phiInst->getOperand(0));
std::cout << " = phi ";
printType(phiInst->getType());
for (unsigned i = 1; i < phiInst->getNumOperands(); i++) {
if (i > 0) std::cout << ", ";
std::cout << "[ ";
printValue(phiInst->getOperand(i));
std::cout << " ]";
}
std::cout << std::endl;
} break;
case Kind::kGetSubArray: {
auto getSubArrayInst = dynamic_cast<GetSubArrayInst *>(pInst);
std::cout << "%" << getSubArrayInst->getName() << " = getelementptr inbounds ";
auto ptrType = dynamic_cast<PointerType*>(getSubArrayInst->getFatherArray()->getType());
printType(ptrType->getBaseType());
std::cout << ", ";
printType(getSubArrayInst->getFatherArray()->getType());
std::cout << " ";
printValue(getSubArrayInst->getFatherArray());
std::cout << ", ";
bool firstIndex = true;
for (auto &index : getSubArrayInst->getIndices()) {
if (!firstIndex) std::cout << ", ";
firstIndex = false;
printType(Type::getIntType());
std::cout << " ";
printValue(index->getValue());
}
std::cout << std::endl;
} break;
default:
assert(false && "Unsupported instruction kind");
break;
}
}
} // namespace sysy

View File

@ -0,0 +1,25 @@
# src/backend/RISCv64/CMakeLists.txt
add_library(riscv64_backend_lib STATIC
RISCv64AsmPrinter.cpp
RISCv64Backend.cpp
RISCv64ISel.cpp
RISCv64LLIR.cpp
RISCv64RegAlloc.cpp
Handler/CalleeSavedHandler.cpp
Handler/LegalizeImmediates.cpp
Handler/PrologueEpilogueInsertion.cpp
Handler/EliminateFrameIndices.cpp
Optimize/Peephole.cpp
Optimize/PostRA_Scheduler.cpp
Optimize/PreRA_Scheduler.cpp
Optimize/DivStrengthReduction.cpp
)
# 包含后端模块所需的头文件路径
target_include_directories(riscv64_backend_lib PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../../include/backend/RISCv64 # 后端顶层头文件
${CMAKE_CURRENT_SOURCE_DIR}/../../include/backend/RISCv64/Handler # 增加 Handler 头文件路径
${CMAKE_CURRENT_SOURCE_DIR}/../../include/backend/RISCv64/Optimize # 增加 Optimize 头文件路径
${CMAKE_CURRENT_SOURCE_DIR}/../../include/midend # 增加 midend 头文件路径 (已存在)
${CMAKE_CURRENT_SOURCE_DIR}/../../include/midend/Pass # 增加 midend 头文件路径 (已存在)
)

View File

@ -0,0 +1,51 @@
#include "CalleeSavedHandler.h"
#include <set>
#include <vector>
#include <algorithm>
#include <iterator>
namespace sysy {
char CalleeSavedHandler::ID = 0;
bool CalleeSavedHandler::runOnFunction(Function *F, AnalysisManager& AM) {
// This pass works on MachineFunction level, not IR level
return false;
}
void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
StackFrameInfo& frame_info = mfunc->getFrameInfo();
const std::set<PhysicalReg>& used_callee_saved = frame_info.used_callee_saved_regs;
if (used_callee_saved.empty()) {
frame_info.callee_saved_size = 0;
frame_info.callee_saved_regs_to_store.clear();
return;
}
// 1. 计算被调用者保存寄存器所需的总空间大小
// s0 总是由 PEI Pass 单独处理,这里不计入大小,但要确保它在列表中
int size = 0;
std::set<PhysicalReg> regs_to_save = used_callee_saved;
if (regs_to_save.count(PhysicalReg::S0)) {
regs_to_save.erase(PhysicalReg::S0);
}
size = regs_to_save.size() * 8; // 每个寄存器占8字节 (64-bit)
frame_info.callee_saved_size = size;
// 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;
// 3. 更新栈帧总大小。
// 这是初步计算PEI Pass 会进行最终的对齐。
frame_info.total_size = frame_info.locals_size +
frame_info.spill_size +
frame_info.callee_saved_size;
}
} // 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

@ -0,0 +1,171 @@
#include "LegalizeImmediates.h"
#include "RISCv64ISel.h" // 需要包含它以调用 getNewVReg()
#include "RISCv64AsmPrinter.h"
#include <vector>
#include <iostream>
// 声明外部调试控制变量
extern int DEBUG;
extern int DEEPDEBUG;
namespace sysy {
char LegalizeImmediatesPass::ID = 0;
// 辅助函数检查一个立即数是否在RISC-V的12位有符号范围内
static bool isLegalImmediate(int64_t imm) {
return imm >= -2048 && imm <= 2047;
}
void LegalizeImmediatesPass::runOnMachineFunction(MachineFunction* mfunc) {
if (DEBUG) {
std::cerr << "===== Running Legalize Immediates Pass on function: " << mfunc->getName() << " =====\n";
}
// 定义我们保留的、用于暂存的物理寄存器
const PhysicalReg TEMP_REG = PhysicalReg::T5;
// 创建一个临时的AsmPrinter用于打印指令方便调试
RISCv64AsmPrinter temp_printer(mfunc);
if (DEEPDEBUG) {
temp_printer.setStream(std::cerr);
}
for (auto& mbb : mfunc->getBlocks()) {
if (DEEPDEBUG) {
std::cerr << "--- Processing Basic Block: " << mbb->getName() << " ---\n";
}
// 创建一个新的指令列表,用于存放合法化后的指令
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
for (auto& instr_ptr : mbb->getInstructions()) {
if (DEEPDEBUG) {
std::cerr << " Checking: ";
// 打印指令时末尾会带换行符,所以这里不用 std::endl
temp_printer.printInstruction(instr_ptr.get(), true);
}
bool legalized = false; // 标记当前指令是否已被展开处理
switch (instr_ptr->getOpcode()) {
case RVOpcodes::ADDI:
case RVOpcodes::ADDIW: {
auto& operands = instr_ptr->getOperands();
// 确保操作数足够多,以防万一
if (operands.size() < 3) break;
auto imm_op = static_cast<ImmOperand*>(operands.back().get());
if (!isLegalImmediate(imm_op->getValue())) {
if (DEEPDEBUG) {
std::cerr << " >> ILLEGAL immediate (" << imm_op->getValue() << "). Expanding...\n";
}
// 立即数超出范围,需要展开
auto rd_op = std::make_unique<RegOperand>(*static_cast<RegOperand*>(operands[0].get()));
auto rs1_op = std::make_unique<RegOperand>(*static_cast<RegOperand*>(operands[1].get()));
// 1. li t5, immediate
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(TEMP_REG));
li->addOperand(std::make_unique<ImmOperand>(imm_op->getValue()));
// 2. add/addw rd, rs1, t5
auto new_op = (instr_ptr->getOpcode() == RVOpcodes::ADDI) ? RVOpcodes::ADD : RVOpcodes::ADDW;
auto add = std::make_unique<MachineInstr>(new_op);
add->addOperand(std::move(rd_op));
add->addOperand(std::move(rs1_op));
add->addOperand(std::make_unique<RegOperand>(TEMP_REG));
if (DEEPDEBUG) {
std::cerr << " New sequence:\n ";
temp_printer.printInstruction(li.get(), true);
std::cerr << " ";
temp_printer.printInstruction(add.get(), true);
}
new_instructions.push_back(std::move(li));
new_instructions.push_back(std::move(add));
legalized = true;
}
break;
}
// 处理所有内存加载/存储指令
case RVOpcodes::LB: case RVOpcodes::LH: case RVOpcodes::LW: case RVOpcodes::LD:
case RVOpcodes::LBU: case RVOpcodes::LHU: case RVOpcodes::LWU:
case RVOpcodes::SB: case RVOpcodes::SH: case RVOpcodes::SW: case RVOpcodes::SD:
case RVOpcodes::FLW: case RVOpcodes::FSW: {
auto& operands = instr_ptr->getOperands();
auto mem_op = static_cast<MemOperand*>(operands.back().get());
auto offset_op = mem_op->getOffset();
if (!isLegalImmediate(offset_op->getValue())) {
if (DEEPDEBUG) {
std::cerr << " >> ILLEGAL immediate offset (" << offset_op->getValue() << "). Expanding...\n";
}
// 偏移量超出范围,需要展开
auto data_reg_op = std::make_unique<RegOperand>(*static_cast<RegOperand*>(operands[0].get()));
auto base_reg_op = std::make_unique<RegOperand>(*mem_op->getBase());
// 1. li t5, offset
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(TEMP_REG));
li->addOperand(std::make_unique<ImmOperand>(offset_op->getValue()));
// 2. add t5, base_reg, t5 (计算最终地址结果也放在t5)
auto add = std::make_unique<MachineInstr>(RVOpcodes::ADD);
add->addOperand(std::make_unique<RegOperand>(TEMP_REG));
add->addOperand(std::move(base_reg_op));
add->addOperand(std::make_unique<RegOperand>(TEMP_REG));
// 3. lw/sw data_reg, 0(t5)
auto mem_instr = std::make_unique<MachineInstr>(instr_ptr->getOpcode());
mem_instr->addOperand(std::move(data_reg_op));
mem_instr->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(TEMP_REG),
std::make_unique<ImmOperand>(0)
));
if (DEEPDEBUG) {
std::cerr << " New sequence:\n ";
temp_printer.printInstruction(li.get(), true);
std::cerr << " ";
temp_printer.printInstruction(add.get(), true);
std::cerr << " ";
temp_printer.printInstruction(mem_instr.get(), true);
}
new_instructions.push_back(std::move(li));
new_instructions.push_back(std::move(add));
new_instructions.push_back(std::move(mem_instr));
legalized = true;
}
break;
}
default:
// 其他指令不需要处理
break;
}
if (!legalized) {
if (DEEPDEBUG) {
std::cerr << " -- Immediate is legal. Skipping.\n";
}
// 如果当前指令不需要合法化,直接将其移动到新列表中
new_instructions.push_back(std::move(instr_ptr));
}
}
// 用新的、已合法化的指令列表替换旧的列表
mbb->getInstructions() = std::move(new_instructions);
}
if (DEBUG) {
std::cerr << "===== Finished Legalize Immediates Pass =====\n\n";
}
}
} // namespace sysy

View File

@ -0,0 +1,182 @@
#include "PrologueEpilogueInsertion.h"
#include "RISCv64LLIR.h" // 假设包含了 PhysicalReg, RVOpcodes 等定义
#include "RISCv64ISel.h"
#include <algorithm>
#include <vector>
#include <set>
namespace sysy {
char PrologueEpilogueInsertionPass::ID = 0;
void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) {
StackFrameInfo& frame_info = mfunc->getFrameInfo();
Function* F = mfunc->getFunc();
RISCv64ISel* isel = mfunc->getISel();
// 1. 清理 KEEPALIVE 伪指令
for (auto& mbb : mfunc->getBlocks()) {
auto& instrs = mbb->getInstructions();
instrs.erase(
std::remove_if(instrs.begin(), instrs.end(),
[](const std::unique_ptr<MachineInstr>& instr) {
return instr->getOpcode() == RVOpcodes::PSEUDO_KEEPALIVE;
}
),
instrs.end()
);
}
// 2. 确定需要保存的被调用者保存寄存器 (callee-saved)
auto& vreg_to_preg_map = frame_info.vreg_to_preg_map;
std::set<PhysicalReg> used_callee_saved_regs_set;
const auto& callee_saved_int = getCalleeSavedIntRegs();
const auto& callee_saved_fp = getCalleeSavedFpRegs();
for (const auto& pair : vreg_to_preg_map) {
PhysicalReg preg = pair.second;
bool is_int_cs = std::find(callee_saved_int.begin(), callee_saved_int.end(), preg) != callee_saved_int.end();
bool is_fp_cs = std::find(callee_saved_fp.begin(), callee_saved_fp.end(), preg) != callee_saved_fp.end();
if ((is_int_cs && preg != PhysicalReg::S0) || is_fp_cs) {
used_callee_saved_regs_set.insert(preg);
}
}
frame_info.callee_saved_regs_to_store.assign(
used_callee_saved_regs_set.begin(), used_callee_saved_regs_set.end()
);
std::sort(frame_info.callee_saved_regs_to_store.begin(), frame_info.callee_saved_regs_to_store.end());
frame_info.callee_saved_size = frame_info.callee_saved_regs_to_store.size() * 8;
// 3. 计算最终的栈帧总大小,包含栈溢出保护
int total_stack_size = frame_info.locals_size +
frame_info.spill_size +
frame_info.callee_saved_size +
16;
// 栈溢出保护:增加最大栈帧大小以容纳大型数组
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) {
// --- 4. 插入完整的序言 ---
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
auto& entry_instrs = entry_block->getInstructions();
std::vector<std::unique_ptr<MachineInstr>> prologue_instrs;
// 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));
// 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>(
std::make_unique<RegOperand>(PhysicalReg::SP),
std::make_unique<ImmOperand>(aligned_stack_size - 8)
));
prologue_instrs.push_back(std::move(save_ra));
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>(
std::make_unique<RegOperand>(PhysicalReg::SP),
std::make_unique<ImmOperand>(aligned_stack_size - 16)
));
prologue_instrs.push_back(std::move(save_fp));
// 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));
// 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));
// 不再需要在循环末尾递减
}
// 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));
}
// 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>(
std::make_unique<RegOperand>(PhysicalReg::SP),
std::make_unique<ImmOperand>(aligned_stack_size - 8)
));
epilogue_instrs.push_back(std::move(restore_ra));
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>(
std::make_unique<RegOperand>(PhysicalReg::SP),
std::make_unique<ImmOperand>(aligned_stack_size - 16)
));
epilogue_instrs.push_back(std::move(restore_fp));
// 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));
// 将尾声指令插入到 RET 指令之前
mbb->getInstructions().insert(it,
std::make_move_iterator(epilogue_instrs.begin()),
std::make_move_iterator(epilogue_instrs.end()));
goto next_block;
}
}
next_block:;
}
}
}
} // namespace sysy

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

@ -0,0 +1,652 @@
#include "Peephole.h"
#include <functional>
namespace sysy {
char PeepholeOptimizer::ID = 0;
bool PeepholeOptimizer::runOnFunction(Function *F, AnalysisManager& AM) {
// This pass works on MachineFunction level, not IR level
return false;
}
void PeepholeOptimizer::runOnMachineFunction(MachineFunction *mfunc) {
if (!mfunc)
return;
using namespace sysy;
// areRegsEqual: 检查两个寄存器操作数是否相等(考虑虚拟和物理寄存器)。
auto areRegsEqual = [](RegOperand *r1, RegOperand *r2) {
if (!r1 || !r2 || r1->isVirtual() != r2->isVirtual()) {
return false;
}
if (r1->isVirtual()) {
return r1->getVRegNum() == r2->getVRegNum();
} else {
return r1->getPReg() == r2->getPReg();
}
};
// 改进的 isRegUsedLater 函数 - 更完整和准确的实现
auto isRegUsedLater =
[&](const std::vector<std::unique_ptr<MachineInstr>> &instrs,
RegOperand *reg, size_t start_idx) -> bool {
for (size_t j = start_idx; j < instrs.size(); ++j) {
auto *instr = instrs[j].get();
auto opcode = instr->getOpcode();
// 检查所有操作数
for (size_t k = 0; k < instr->getOperands().size(); ++k) {
bool isDefOperand = false;
// 更完整的定义操作数判断逻辑
if (k == 0) { // 第一个操作数通常是目标寄存器
switch (opcode) {
// 算术和逻辑指令 - 第一个操作数是定义
case RVOpcodes::MV:
case RVOpcodes::ADDI:
case RVOpcodes::SLLI:
case RVOpcodes::SRLI:
case RVOpcodes::SRAI:
case RVOpcodes::SLTI:
case RVOpcodes::SLTIU:
case RVOpcodes::XORI:
case RVOpcodes::ORI:
case RVOpcodes::ANDI:
case RVOpcodes::ADD:
case RVOpcodes::SUB:
case RVOpcodes::SLL:
case RVOpcodes::SLT:
case RVOpcodes::SLTU:
case RVOpcodes::XOR:
case RVOpcodes::SRL:
case RVOpcodes::SRA:
case RVOpcodes::OR:
case RVOpcodes::AND:
case RVOpcodes::MUL:
case RVOpcodes::DIV:
case RVOpcodes::REM:
case RVOpcodes::LW:
case RVOpcodes::LH:
case RVOpcodes::LB:
case RVOpcodes::LHU:
case RVOpcodes::LBU:
// 存储指令 - 第一个操作数是使用(要存储的值)
case RVOpcodes::SW:
case RVOpcodes::SH:
case RVOpcodes::SB:
// 分支指令 - 第一个操作数是使用
case RVOpcodes::BEQ:
case RVOpcodes::BNE:
case RVOpcodes::BLT:
case RVOpcodes::BGE:
case RVOpcodes::BLTU:
case RVOpcodes::BGEU:
// 跳转指令 - 可能使用寄存器
case RVOpcodes::JALR:
isDefOperand = false;
break;
default:
// 对于未知指令,保守地假设第一个操作数可能是使用
isDefOperand = false;
break;
}
}
// 如果不是定义操作数,检查是否使用了目标寄存器
if (!isDefOperand) {
if (instr->getOperands()[k]->getKind() == MachineOperand::KIND_REG) {
auto *use_reg =
static_cast<RegOperand *>(instr->getOperands()[k].get());
if (areRegsEqual(reg, use_reg))
return true;
}
// 检查内存操作数中的基址寄存器
if (instr->getOperands()[k]->getKind() == MachineOperand::KIND_MEM) {
auto *mem =
static_cast<MemOperand *>(instr->getOperands()[k].get());
if (areRegsEqual(reg, mem->getBase()))
return true;
}
}
}
}
return false;
};
// 检查寄存器是否在指令中被重新定义(用于更精确的分析)
auto isRegRedefinedAt =
[](MachineInstr *instr, RegOperand *reg,
const std::function<bool(RegOperand *, RegOperand *)> &areRegsEqual)
-> bool {
if (instr->getOperands().empty())
return false;
auto opcode = instr->getOpcode();
// 只有当第一个操作数是定义操作数时才检查
switch (opcode) {
case RVOpcodes::MV:
case RVOpcodes::ADDI:
case RVOpcodes::ADD:
case RVOpcodes::SUB:
case RVOpcodes::MUL:
case RVOpcodes::LW:
// ... 其他定义指令
if (instr->getOperands()[0]->getKind() == MachineOperand::KIND_REG) {
auto *def_reg =
static_cast<RegOperand *>(instr->getOperands()[0].get());
return areRegsEqual(reg, def_reg);
}
break;
default:
break;
}
return false;
};
// 检查是否为存储-加载模式,支持不同大小的访问
auto isStoreLoadPattern = [](MachineInstr *store_instr,
MachineInstr *load_instr) -> bool {
auto store_op = store_instr->getOpcode();
auto load_op = load_instr->getOpcode();
// 检查存储-加载对应关系
return (store_op == RVOpcodes::SW && load_op == RVOpcodes::LW) || // 32位
(store_op == RVOpcodes::SH &&
load_op == RVOpcodes::LH) || // 16位有符号
(store_op == RVOpcodes::SH &&
load_op == RVOpcodes::LHU) || // 16位无符号
(store_op == RVOpcodes::SB &&
load_op == RVOpcodes::LB) || // 8位有符号
(store_op == RVOpcodes::SB &&
load_op == RVOpcodes::LBU) || // 8位无符号
(store_op == RVOpcodes::SD && load_op == RVOpcodes::LD); // 64位
};
// 检查两个内存访问是否访问相同的内存位置
auto areMemoryAccessesEqual =
[&areRegsEqual](MachineInstr *store_instr, MemOperand *store_mem,
MachineInstr *load_instr, MemOperand *load_mem) -> bool {
// 基址寄存器必须相同
if (!areRegsEqual(store_mem->getBase(), load_mem->getBase())) {
return false;
}
// 偏移量必须相同
if (store_mem->getOffset()->getValue() !=
load_mem->getOffset()->getValue()) {
return false;
}
// 检查访问大小是否兼容
auto store_op = store_instr->getOpcode();
auto load_op = load_instr->getOpcode();
// 获取访问大小(字节数)
auto getAccessSize = [](RVOpcodes opcode) -> int {
switch (opcode) {
case RVOpcodes::LB:
case RVOpcodes::LBU:
case RVOpcodes::SB:
return 1; // 8位
case RVOpcodes::LH:
case RVOpcodes::LHU:
case RVOpcodes::SH:
return 2; // 16位
case RVOpcodes::LW:
case RVOpcodes::SW:
return 4; // 32位
case RVOpcodes::LD:
case RVOpcodes::SD:
return 8; // 64位
default:
return -1; // 未知
}
};
int store_size = getAccessSize(store_op);
int load_size = getAccessSize(load_op);
// 只有访问大小完全匹配时才能进行优化
// 这避免了部分重叠访问的复杂情况
return store_size > 0 && store_size == load_size;
};
// 简单的内存别名分析:检查两个内存访问之间是否可能有冲突的内存操作
auto isMemoryAccessSafe =
[&](const std::vector<std::unique_ptr<MachineInstr>> &instrs,
size_t store_idx, size_t load_idx, MemOperand *mem) -> bool {
// 检查存储和加载之间是否有可能影响内存的指令
for (size_t j = store_idx + 1; j < load_idx; ++j) {
auto *between_instr = instrs[j].get();
auto between_op = between_instr->getOpcode();
// 检查是否有其他内存写入操作
switch (between_op) {
case RVOpcodes::SW:
case RVOpcodes::SH:
case RVOpcodes::SB:
case RVOpcodes::SD: {
// 如果有其他存储操作,需要检查是否可能访问相同的内存
if (between_instr->getOperands().size() >= 2 &&
between_instr->getOperands()[1]->getKind() ==
MachineOperand::KIND_MEM) {
auto *other_mem =
static_cast<MemOperand *>(between_instr->getOperands()[1].get());
// 保守的别名分析:如果使用不同的基址寄存器,假设可能别名
if (!areRegsEqual(mem->getBase(), other_mem->getBase())) {
return false; // 可能的别名,不安全
}
// 如果基址相同但偏移量不同,检查是否重叠
int64_t offset1 = mem->getOffset()->getValue();
int64_t offset2 = other_mem->getOffset()->getValue();
// 获取访问大小来检查重叠
auto getAccessSize = [](RVOpcodes opcode) -> int {
switch (opcode) {
case RVOpcodes::SB:
return 1;
case RVOpcodes::SH:
return 2;
case RVOpcodes::SW:
return 4;
case RVOpcodes::SD:
return 8;
default:
return 4; // 默认假设4字节
}
};
int size1 = getAccessSize(RVOpcodes::SW); // 从原存储指令推断
int size2 = getAccessSize(between_op);
// 检查内存区域是否重叠
bool overlaps =
!(offset1 + size1 <= offset2 || offset2 + size2 <= offset1);
if (overlaps) {
return false; // 内存重叠,不安全
}
}
break;
}
// 函数调用可能有副作用
case RVOpcodes::JAL:
case RVOpcodes::JALR:
return false; // 函数调用可能修改内存,不安全
// 原子操作或其他可能修改内存的指令
// 根据具体的RISC-V扩展添加更多指令
default:
// 对于未知指令,采用保守策略
// 可以根据具体需求调整
break;
}
}
return true; // 没有发现潜在的内存冲突
};
// isPowerOfTwo: 检查数值是否为2的幂次并返回其指数。
auto isPowerOfTwo = [](int64_t n) -> int {
if (n <= 0 || (n & (n - 1)) != 0)
return -1;
int shift = 0;
while (n > 1) {
n >>= 1;
shift++;
}
return shift;
};
for (auto &mbb_uptr : mfunc->getBlocks()) {
auto &mbb = *mbb_uptr;
auto &instrs = mbb.getInstructions();
if (instrs.size() < 2)
continue; // 基本块至少需要两条指令进行窥孔
// 遍历指令序列进行窥孔优化
for (size_t i = 0; i + 1 < instrs.size();) {
auto *mi1 = instrs[i].get();
auto *mi2 = instrs[i + 1].get();
bool changed = false;
// 1. 消除冗余交换移动: mv a, b; mv b, a -> mv a, b
if (mi1->getOpcode() == RVOpcodes::MV &&
mi2->getOpcode() == RVOpcodes::MV) {
if (mi1->getOperands().size() == 2 && mi2->getOperands().size() == 2) {
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG &&
mi2->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi2->getOperands()[1]->getKind() == MachineOperand::KIND_REG) {
auto *dst1 = static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *src1 = static_cast<RegOperand *>(mi1->getOperands()[1].get());
auto *dst2 = static_cast<RegOperand *>(mi2->getOperands()[0].get());
auto *src2 = static_cast<RegOperand *>(mi2->getOperands()[1].get());
if (areRegsEqual(dst1, src2) && areRegsEqual(src1, dst2)) {
instrs.erase(instrs.begin() + i + 1); // 移除第二条指令
changed = true;
}
}
}
}
// 2. 冗余加载消除: sw t0, offset(base); lw t1, offset(base) -> 替换或消除
// lw 添加ld sd支持
else if (isStoreLoadPattern(mi1, mi2)) {
if (mi1->getOperands().size() == 2 && mi2->getOperands().size() == 2) {
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_MEM &&
mi2->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi2->getOperands()[1]->getKind() == MachineOperand::KIND_MEM) {
auto *store_val =
static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *store_mem =
static_cast<MemOperand *>(mi1->getOperands()[1].get());
auto *load_val =
static_cast<RegOperand *>(mi2->getOperands()[0].get());
auto *load_mem =
static_cast<MemOperand *>(mi2->getOperands()[1].get());
// 检查内存访问是否匹配(基址、偏移量和访问大小)
if (areMemoryAccessesEqual(mi1, store_mem, mi2, load_mem)) {
// 进行简单的内存别名分析
if (isMemoryAccessSafe(instrs, i, i + 1, store_mem)) {
if (areRegsEqual(store_val, load_val)) {
// sw r1, mem; lw r1, mem -> 消除冗余的lw
instrs.erase(instrs.begin() + i + 1);
changed = true;
} else {
// sw r1, mem; lw r2, mem -> 替换lw为mv r2, r1
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::MV);
newInstr->addOperand(std::make_unique<RegOperand>(*load_val));
newInstr->addOperand(
std::make_unique<RegOperand>(*store_val));
instrs[i + 1] = std::move(newInstr);
changed = true;
}
}
}
}
}
}
// 3. 强度削减: mul y, x, 2^n -> slli y, x, n
else if (mi1->getOpcode() == RVOpcodes::MUL &&
mi1->getOperands().size() == 3) {
auto *dst_op = mi1->getOperands()[0].get();
auto *src1_op = mi1->getOperands()[1].get();
auto *src2_op = mi1->getOperands()[2].get();
if (dst_op->getKind() == MachineOperand::KIND_REG) {
auto *dst_reg = static_cast<RegOperand *>(dst_op);
RegOperand *src_reg = nullptr;
int shift = -1;
if (src1_op->getKind() == MachineOperand::KIND_REG &&
src2_op->getKind() == MachineOperand::KIND_IMM) {
shift =
isPowerOfTwo(static_cast<ImmOperand *>(src2_op)->getValue());
if (shift >= 0)
src_reg = static_cast<RegOperand *>(src1_op);
} else if (src1_op->getKind() == MachineOperand::KIND_IMM &&
src2_op->getKind() == MachineOperand::KIND_REG) {
shift =
isPowerOfTwo(static_cast<ImmOperand *>(src1_op)->getValue());
if (shift >= 0)
src_reg = static_cast<RegOperand *>(src2_op);
}
if (src_reg && shift >= 0 &&
shift <= 31) { // RISC-V 移位量限制 (0-31)
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::SLLI);
newInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
newInstr->addOperand(std::make_unique<RegOperand>(*src_reg));
newInstr->addOperand(std::make_unique<ImmOperand>(shift));
instrs[i] = std::move(newInstr);
changed = true;
}
}
}
// 4. 地址计算优化: addi dst, base, imm1; lw/sw val, imm2(dst) -> lw/sw
// val, (imm1+imm2)(base)
else if (mi1->getOpcode() == RVOpcodes::ADDI &&
mi1->getOperands().size() == 3) {
auto opcode2 = mi2->getOpcode();
if (opcode2 == RVOpcodes::LW || opcode2 == RVOpcodes::SW) {
if (mi2->getOperands().size() == 2 &&
mi2->getOperands()[1]->getKind() == MachineOperand::KIND_MEM &&
mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[2]->getKind() == MachineOperand::KIND_IMM) {
auto *addi_dst =
static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *addi_base =
static_cast<RegOperand *>(mi1->getOperands()[1].get());
auto *addi_imm =
static_cast<ImmOperand *>(mi1->getOperands()[2].get());
auto *mem_op =
static_cast<MemOperand *>(mi2->getOperands()[1].get());
auto *mem_base = mem_op->getBase();
auto *mem_imm = mem_op->getOffset();
// 检查 ADDI 的目标寄存器是否是内存操作的基址
if (areRegsEqual(addi_dst, mem_base)) {
// 改进的使用检查:考虑寄存器可能在后续被重新定义的情况
bool canOptimize = true;
// 检查从 i+2 开始的指令
for (size_t j = i + 2; j < instrs.size(); ++j) {
auto *later_instr = instrs[j].get();
// 如果寄存器被重新定义,那么它后面的使用就不相关了
if (isRegRedefinedAt(later_instr, addi_dst, areRegsEqual)) {
break; // 寄存器被重新定义,可以安全优化
}
// 如果寄存器被使用,则不能优化
if (isRegUsedLater(instrs, addi_dst, j)) {
canOptimize = false;
break;
}
}
if (canOptimize) {
int64_t new_offset = addi_imm->getValue() + mem_imm->getValue();
// 检查新偏移量是否符合 RISC-V 12位有符号立即数范围
if (new_offset >= -2048 && new_offset <= 2047) {
auto new_mem_op = std::make_unique<MemOperand>(
std::make_unique<RegOperand>(*addi_base),
std::make_unique<ImmOperand>(new_offset));
mi2->getOperands()[1] = std::move(new_mem_op);
instrs.erase(instrs.begin() + i);
changed = true;
}
}
}
}
}
}
// 5. 冗余移动指令消除: mv x, y; op z, x, ... -> op z, y, ... (如果 x
// 之后不再使用)
else if (mi1->getOpcode() == RVOpcodes::MV &&
mi1->getOperands().size() == 2) {
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG) {
auto *mv_dst = static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *mv_src = static_cast<RegOperand *>(mi1->getOperands()[1].get());
// 检查第二条指令是否使用了 mv 的目标寄存器
std::vector<size_t> use_positions;
for (size_t k = 1; k < mi2->getOperands().size(); ++k) {
if (mi2->getOperands()[k]->getKind() == MachineOperand::KIND_REG) {
auto *use_reg =
static_cast<RegOperand *>(mi2->getOperands()[k].get());
if (areRegsEqual(mv_dst, use_reg)) {
use_positions.push_back(k);
}
}
// 也检查内存操作数中的基址寄存器
else if (mi2->getOperands()[k]->getKind() ==
MachineOperand::KIND_MEM) {
auto *mem =
static_cast<MemOperand *>(mi2->getOperands()[k].get());
if (areRegsEqual(mv_dst, mem->getBase())) {
// 对于内存操作数我们需要创建新的MemOperand
auto new_mem = std::make_unique<MemOperand>(
std::make_unique<RegOperand>(*mv_src),
std::make_unique<ImmOperand>(mem->getOffset()->getValue()));
mi2->getOperands()[k] = std::move(new_mem);
use_positions.push_back(k); // 标记已处理
}
}
}
if (!use_positions.empty()) {
// 改进的后续使用检查
bool canOptimize = true;
for (size_t j = i + 2; j < instrs.size(); ++j) {
auto *later_instr = instrs[j].get();
// 如果寄存器被重新定义,后续使用就不相关了
if (isRegRedefinedAt(later_instr, mv_dst, areRegsEqual)) {
break;
}
// 检查是否还有其他使用
if (isRegUsedLater(instrs, mv_dst, j)) {
canOptimize = false;
break;
}
}
if (canOptimize) {
// 替换所有寄存器使用(内存操作数已在上面处理)
for (size_t pos : use_positions) {
if (mi2->getOperands()[pos]->getKind() ==
MachineOperand::KIND_REG) {
mi2->getOperands()[pos] =
std::make_unique<RegOperand>(*mv_src);
}
}
instrs.erase(instrs.begin() + i);
changed = true;
}
}
}
}
// 6. 连续加法指令合并: addi t1, t0, imm1; addi t2, t1, imm2 -> addi t2,
// t0, (imm1+imm2)
else if (mi1->getOpcode() == RVOpcodes::ADDI &&
mi2->getOpcode() == RVOpcodes::ADDI) {
if (mi1->getOperands().size() == 3 && mi2->getOperands().size() == 3) {
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[2]->getKind() == MachineOperand::KIND_IMM &&
mi2->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi2->getOperands()[1]->getKind() == MachineOperand::KIND_REG &&
mi2->getOperands()[2]->getKind() == MachineOperand::KIND_IMM) {
auto *addi1_dst =
static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *addi1_src =
static_cast<RegOperand *>(mi1->getOperands()[1].get());
auto *addi1_imm =
static_cast<ImmOperand *>(mi1->getOperands()[2].get());
auto *addi2_dst =
static_cast<RegOperand *>(mi2->getOperands()[0].get());
auto *addi2_src =
static_cast<RegOperand *>(mi2->getOperands()[1].get());
auto *addi2_imm =
static_cast<ImmOperand *>(mi2->getOperands()[2].get());
// 检查第一个ADDI的目标是否是第二个ADDI的源
if (areRegsEqual(addi1_dst, addi2_src)) {
// 改进的中间寄存器使用检查
bool canOptimize = true;
for (size_t j = i + 2; j < instrs.size(); ++j) {
auto *later_instr = instrs[j].get();
// 如果中间寄存器被重新定义,后续使用不相关
if (isRegRedefinedAt(later_instr, addi1_dst, areRegsEqual)) {
break;
}
// 检查是否有其他使用
if (isRegUsedLater(instrs, addi1_dst, j)) {
canOptimize = false;
break;
}
}
if (canOptimize) {
int64_t new_imm = addi1_imm->getValue() + addi2_imm->getValue();
// 检查新立即数范围
if (new_imm >= -2048 && new_imm <= 2047) {
auto newInstr =
std::make_unique<MachineInstr>(RVOpcodes::ADDI);
newInstr->addOperand(
std::make_unique<RegOperand>(*addi2_dst));
newInstr->addOperand(
std::make_unique<RegOperand>(*addi1_src));
newInstr->addOperand(std::make_unique<ImmOperand>(new_imm));
instrs[i + 1] = std::move(newInstr);
instrs.erase(instrs.begin() + i);
changed = true;
}
}
}
}
}
}
// 7. ADD with zero optimization: add r1, r2, zero -> mv r1, r2
else if (mi1->getOpcode() == RVOpcodes::ADD &&
mi1->getOperands().size() == 3) {
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[2]->getKind() == MachineOperand::KIND_REG) {
auto *add_dst =
static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *add_src1 =
static_cast<RegOperand *>(mi1->getOperands()[1].get());
auto *add_src2 =
static_cast<RegOperand *>(mi1->getOperands()[2].get());
// 检查第二个源操作数是否为ZERO寄存器
if (!add_src2->isVirtual() &&
add_src2->getPReg() == PhysicalReg::ZERO) {
// 创建新的 MV 指令
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::MV);
newInstr->addOperand(std::make_unique<RegOperand>(*add_dst));
newInstr->addOperand(std::make_unique<RegOperand>(*add_src1));
instrs[i] = std::move(newInstr);
changed = true;
}
}
}
// 根据是否发生变化调整遍历索引
if (!changed) {
++i; // 没有优化,继续检查下一对指令
} else {
// 发生变化,适当回退以捕获新的优化机会。
// 这是一种安全的回退策略,可以触发连锁优化,且不会导致无限循环。
if (i > 0) {
--i;
}
}
}
}
}
} // namespace sysy

View File

@ -0,0 +1,416 @@
#include "PostRA_Scheduler.h"
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#define MAX_SCHEDULING_BLOCK_SIZE 10000 // 限制调度块大小,避免过大导致性能问题
namespace sysy {
char PostRA_Scheduler::ID = 0;
// 检查指令是否是加载指令 (LW, LD)
bool isLoadInstr(MachineInstr *instr) {
RVOpcodes opcode = instr->getOpcode();
return opcode == RVOpcodes::LW || opcode == RVOpcodes::LD ||
opcode == RVOpcodes::LH || opcode == RVOpcodes::LB ||
opcode == RVOpcodes::LHU || opcode == RVOpcodes::LBU ||
opcode == RVOpcodes::LWU;
}
// 检查指令是否是存储指令 (SW, SD)
bool isStoreInstr(MachineInstr *instr) {
RVOpcodes opcode = instr->getOpcode();
return opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
opcode == RVOpcodes::SH || opcode == RVOpcodes::SB;
}
// 检查指令是否为控制流指令
bool isControlFlowInstr(MachineInstr *instr) {
RVOpcodes opcode = instr->getOpcode();
return opcode == RVOpcodes::RET || opcode == RVOpcodes::J ||
opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
opcode == RVOpcodes::CALL;
}
// 预计算指令信息的缓存
static std::unordered_map<MachineInstr *, InstrRegInfo> instr_info_cache;
// 获取指令定义的寄存器 - 优化版本
std::unordered_set<PhysicalReg> getDefinedRegisters(MachineInstr *instr) {
std::unordered_set<PhysicalReg> defined_regs;
RVOpcodes opcode = instr->getOpcode();
// 特殊处理CALL指令
if (opcode == RVOpcodes::CALL) {
// CALL指令可能定义返回值寄存器
if (!instr->getOperands().empty() &&
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
auto reg_op =
static_cast<RegOperand *>(instr->getOperands().front().get());
if (!reg_op->isVirtual()) {
defined_regs.insert(reg_op->getPReg());
}
}
return defined_regs;
}
// 存储指令不定义寄存器
if (isStoreInstr(instr)) {
return defined_regs;
}
// 分支指令不定义寄存器
if (opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
opcode == RVOpcodes::J || opcode == RVOpcodes::RET) {
return defined_regs;
}
// 对于其他指令,第一个寄存器操作数通常是定义的
if (!instr->getOperands().empty() &&
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand *>(instr->getOperands().front().get());
if (!reg_op->isVirtual()) {
defined_regs.insert(reg_op->getPReg());
}
}
return defined_regs;
}
// 获取指令使用的寄存器 - 优化版本
std::unordered_set<PhysicalReg> getUsedRegisters(MachineInstr *instr) {
std::unordered_set<PhysicalReg> used_regs;
RVOpcodes opcode = instr->getOpcode();
// 特殊处理CALL指令
if (opcode == RVOpcodes::CALL) {
bool first_reg_skipped = false;
for (const auto &op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
if (!first_reg_skipped) {
first_reg_skipped = true;
continue; // 跳过返回值寄存器
}
auto reg_op = static_cast<RegOperand *>(op.get());
if (!reg_op->isVirtual()) {
used_regs.insert(reg_op->getPReg());
}
}
}
return used_regs;
}
// 对于存储指令,所有寄存器操作数都是使用的
if (isStoreInstr(instr)) {
for (const auto &op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand *>(op.get());
if (!reg_op->isVirtual()) {
used_regs.insert(reg_op->getPReg());
}
} else if (op->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand *>(op.get());
if (!mem_op->getBase()->isVirtual()) {
used_regs.insert(mem_op->getBase()->getPReg());
}
}
}
return used_regs;
}
// 对于分支指令,所有寄存器操作数都是使用的
if (opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU) {
for (const auto &op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand *>(op.get());
if (!reg_op->isVirtual()) {
used_regs.insert(reg_op->getPReg());
}
}
}
return used_regs;
}
// 对于其他指令,除了第一个寄存器操作数(通常是定义),其余都是使用的
bool first_reg = true;
for (const auto &op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
if (first_reg) {
first_reg = false;
continue; // 跳过第一个寄存器(定义)
}
auto reg_op = static_cast<RegOperand *>(op.get());
if (!reg_op->isVirtual()) {
used_regs.insert(reg_op->getPReg());
}
} else if (op->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand *>(op.get());
if (!mem_op->getBase()->isVirtual()) {
used_regs.insert(mem_op->getBase()->getPReg());
}
}
}
return used_regs;
}
// 获取内存访问的基址和偏移
MemoryAccess getMemoryAccess(MachineInstr *instr) {
if (!isLoadInstr(instr) && !isStoreInstr(instr)) {
return MemoryAccess();
}
// 查找内存操作数
for (const auto &op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand *>(op.get());
if (!mem_op->getBase()->isVirtual()) {
return MemoryAccess(mem_op->getBase()->getPReg(),
mem_op->getOffset()->getValue());
}
}
}
return MemoryAccess();
}
// 预计算指令信息
InstrRegInfo &getInstrInfo(MachineInstr *instr) {
auto it = instr_info_cache.find(instr);
if (it != instr_info_cache.end()) {
return it->second;
}
InstrRegInfo &info = instr_info_cache[instr];
info.defined_regs = getDefinedRegisters(instr);
info.used_regs = getUsedRegisters(instr);
info.is_load = isLoadInstr(instr);
info.is_store = isStoreInstr(instr);
info.is_control_flow = isControlFlowInstr(instr);
info.mem_access = getMemoryAccess(instr);
return info;
}
// 检查内存依赖 - 优化版本
bool hasMemoryDependency(const InstrRegInfo &info1, const InstrRegInfo &info2) {
// 如果都不是内存指令,没有内存依赖
if (!info1.is_load && !info1.is_store && !info2.is_load && !info2.is_store) {
return false;
}
const MemoryAccess &mem1 = info1.mem_access;
const MemoryAccess &mem2 = info2.mem_access;
if (!mem1.valid || !mem2.valid) {
// 如果无法确定内存访问模式,保守地认为存在依赖
return true;
}
// 如果访问相同的内存位置
if (mem1.base_reg == mem2.base_reg && mem1.offset == mem2.offset) {
// Store->Load: RAW依赖
// Load->Store: WAR依赖
// Store->Store: WAW依赖
return info1.is_store || info2.is_store;
}
// 不同内存位置通常没有依赖,但为了安全起见,
// 如果涉及store指令我们需要更保守
if (info1.is_store && info2.is_load) {
// 保守处理不同store和load之间可能有别名
return false; // 这里可以根据需要调整策略
}
return false;
}
// 检查两个指令之间是否存在依赖关系 - 优化版本
bool hasDependency(MachineInstr *instr1, MachineInstr *instr2) {
const InstrRegInfo &info1 = getInstrInfo(instr1);
const InstrRegInfo &info2 = getInstrInfo(instr2);
// 检查RAW依赖instr1定义的寄存器是否被instr2使用
for (const auto &reg : info1.defined_regs) {
if (info2.used_regs.find(reg) != info2.used_regs.end()) {
return true; // RAW依赖 - instr2读取instr1写入的值
}
}
// 检查WAR依赖instr1使用的寄存器是否被instr2定义
for (const auto &reg : info1.used_regs) {
if (info2.defined_regs.find(reg) != info2.defined_regs.end()) {
return true; // WAR依赖 - instr2覆盖instr1需要的值
}
}
// 检查WAW依赖两个指令定义相同寄存器
for (const auto &reg : info1.defined_regs) {
if (info2.defined_regs.find(reg) != info2.defined_regs.end()) {
return true; // WAW依赖 - 两条指令写入同一寄存器
}
}
// 检查内存依赖
if (hasMemoryDependency(info1, info2)) {
return true;
}
return false;
}
// 检查是否可以安全地将instr1和instr2交换位置 - 优化版本
bool canSwapInstructions(MachineInstr *instr1, MachineInstr *instr2) {
const InstrRegInfo &info1 = getInstrInfo(instr1);
const InstrRegInfo &info2 = getInstrInfo(instr2);
// 不能移动控制流指令
if (info1.is_control_flow || info2.is_control_flow) {
return false;
}
// 检查双向依赖关系
return !hasDependency(instr1, instr2) && !hasDependency(instr2, instr1);
}
// 新增:验证调度结果的正确性 - 优化版本
void validateSchedule(const std::vector<MachineInstr *> &instr_list) {
for (int i = 0; i < (int)instr_list.size(); i++) {
for (int j = i + 1; j < (int)instr_list.size(); j++) {
MachineInstr *earlier = instr_list[i];
MachineInstr *later = instr_list[j];
const InstrRegInfo &info_earlier = getInstrInfo(earlier);
const InstrRegInfo &info_later = getInstrInfo(later);
// 检查是否存在被违反的依赖关系
// 检查RAW依赖
for (const auto &reg : info_earlier.defined_regs) {
if (info_later.used_regs.find(reg) != info_later.used_regs.end()) {
// 这是正常的依赖关系earlier应该在later之前
continue;
}
}
// 检查内存依赖
if (hasMemoryDependency(info_earlier, info_later)) {
const MemoryAccess &mem1 = info_earlier.mem_access;
const MemoryAccess &mem2 = info_later.mem_access;
if (mem1.valid && mem2.valid && mem1.base_reg == mem2.base_reg &&
mem1.offset == mem2.offset) {
if (info_earlier.is_store && info_later.is_load) {
// Store->Load依赖顺序正确
continue;
}
}
}
}
}
}
// 在基本块内对指令进行调度优化 - 优化版本
void scheduleBlock(MachineBasicBlock *mbb) {
auto &instructions = mbb->getInstructions();
if (instructions.size() <= 1)
return;
if (instructions.size() > MAX_SCHEDULING_BLOCK_SIZE) {
return; // 跳过超大块,防止卡住
}
// 清理缓存,避免无效指针
instr_info_cache.clear();
std::vector<MachineInstr *> instr_list;
instr_list.reserve(instructions.size()); // 预分配容量
for (auto &instr : instructions) {
instr_list.push_back(instr.get());
}
// 预计算所有指令的信息
for (auto *instr : instr_list) {
getInstrInfo(instr);
}
// 使用更严格的调度策略,避免破坏依赖关系
bool changed = true;
int max_iterations = 10; // 限制迭代次数避免死循环
int iteration = 0;
while (changed && iteration < max_iterations) {
changed = false;
iteration++;
for (int i = 0; i < (int)instr_list.size() - 1; i++) {
MachineInstr *instr1 = instr_list[i];
MachineInstr *instr2 = instr_list[i + 1];
const InstrRegInfo &info1 = getInstrInfo(instr1);
const InstrRegInfo &info2 = getInstrInfo(instr2);
// 只进行非常保守的优化
bool should_swap = false;
// 策略1: 将load指令提前减少load-use延迟
if (info2.is_load && !info1.is_load && !info1.is_store) {
should_swap = canSwapInstructions(instr1, instr2);
}
// 策略2: 将非关键store指令延后为其他指令让路
else if (info1.is_store && !info2.is_load && !info2.is_store) {
should_swap = canSwapInstructions(instr1, instr2);
}
if (should_swap) {
std::swap(instr_list[i], instr_list[i + 1]);
changed = true;
// 调试输出
// std::cout << "Swapped instructions at positions " << i << " and " <<
// (i+1) << std::endl;
}
}
}
// 验证调度结果的正确性
validateSchedule(instr_list);
// 将调度后的指令顺序写回
std::unordered_map<MachineInstr *, std::unique_ptr<MachineInstr>> instr_map;
instr_map.reserve(instructions.size()); // 预分配容量
for (auto &instr : instructions) {
instr_map[instr.get()] = std::move(instr);
}
instructions.clear();
instructions.reserve(instr_list.size()); // 预分配容量
for (auto instr : instr_list) {
instructions.push_back(std::move(instr_map[instr]));
}
}
bool PostRA_Scheduler::runOnFunction(Function *F, AnalysisManager &AM) {
// 这个函数在IR级别运行但我们需要在机器指令级别运行
// 所以我们返回false表示没有对IR进行修改
return false;
}
void PostRA_Scheduler::runOnMachineFunction(MachineFunction *mfunc) {
// std::cout << "Running Post-RA Local Scheduler... " << std::endl;
// 遍历每个机器基本块
for (auto &mbb : mfunc->getBlocks()) {
scheduleBlock(mbb.get());
}
// 清理全局缓存
instr_info_cache.clear();
}
} // namespace sysy

View File

@ -0,0 +1,466 @@
#include "PreRA_Scheduler.h"
#include "RISCv64LLIR.h"
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#define MAX_SCHEDULING_BLOCK_SIZE 1000 // 严格限制调度块大小
namespace sysy {
char PreRA_Scheduler::ID = 0;
// 检查指令是否是加载指令 (LW, LD)
static bool isLoadInstr(MachineInstr *instr) {
RVOpcodes opcode = instr->getOpcode();
return opcode == RVOpcodes::LW || opcode == RVOpcodes::LD ||
opcode == RVOpcodes::LH || opcode == RVOpcodes::LB ||
opcode == RVOpcodes::LHU || opcode == RVOpcodes::LBU ||
opcode == RVOpcodes::LWU;
}
// 检查指令是否是存储指令 (SW, SD)
static bool isStoreInstr(MachineInstr *instr) {
RVOpcodes opcode = instr->getOpcode();
return opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
opcode == RVOpcodes::SH || opcode == RVOpcodes::SB;
}
// 检查指令是否为分支指令
static bool isBranchInstr(MachineInstr *instr) {
RVOpcodes opcode = instr->getOpcode();
return opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU;
}
// 检查指令是否为跳转指令
static bool isJumpInstr(MachineInstr *instr) {
RVOpcodes opcode = instr->getOpcode();
return opcode == RVOpcodes::J;
}
// 检查指令是否为返回指令
static bool isReturnInstr(MachineInstr *instr) {
return instr->getOpcode() == RVOpcodes::RET;
}
// 检查指令是否为调用指令
static bool isCallInstr(MachineInstr *instr) {
return instr->getOpcode() == RVOpcodes::CALL;
}
// 检查指令是否为块终结指令(必须保持在块尾)
static bool isTerminatorInstr(MachineInstr *instr) {
return isBranchInstr(instr) || isJumpInstr(instr) || isReturnInstr(instr);
}
// 检查指令是否有副作用(需要谨慎处理)
static bool hasSideEffect(MachineInstr *instr) {
return isStoreInstr(instr) || isCallInstr(instr) || isTerminatorInstr(instr);
}
// 检查指令是否涉及内存操作
static bool hasMemoryAccess(MachineInstr *instr) {
return isLoadInstr(instr) || isStoreInstr(instr);
}
// 获取内存访问位置信息
struct MemoryLocation {
unsigned base_reg;
int64_t offset;
bool is_valid;
MemoryLocation() : base_reg(0), offset(0), is_valid(false) {}
MemoryLocation(unsigned base, int64_t off)
: base_reg(base), offset(off), is_valid(true) {}
bool operator==(const MemoryLocation &other) const {
return is_valid && other.is_valid && base_reg == other.base_reg &&
offset == other.offset;
}
};
// 缓存指令分析信息
struct InstrInfo {
std::unordered_set<unsigned> defined_regs;
std::unordered_set<unsigned> used_regs;
MemoryLocation mem_location;
bool is_load;
bool is_store;
bool is_terminator;
bool is_call;
bool has_side_effect;
bool has_memory_access;
InstrInfo() : is_load(false), is_store(false), is_terminator(false),
is_call(false), has_side_effect(false), has_memory_access(false) {}
};
// 指令信息缓存
static std::unordered_map<MachineInstr*, InstrInfo> instr_info_cache;
// 获取指令定义的虚拟寄存器 - 优化版本
static std::unordered_set<unsigned> getDefinedVirtualRegisters(MachineInstr *instr) {
std::unordered_set<unsigned> defined_regs;
RVOpcodes opcode = instr->getOpcode();
// CALL指令可能定义返回值寄存器
if (opcode == RVOpcodes::CALL) {
if (!instr->getOperands().empty() &&
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
auto reg_op =
static_cast<RegOperand *>(instr->getOperands().front().get());
if (reg_op->isVirtual()) {
defined_regs.insert(reg_op->getVRegNum());
}
}
return defined_regs;
}
// 存储指令和终结指令不定义寄存器
if (isStoreInstr(instr) || isTerminatorInstr(instr)) {
return defined_regs;
}
// 其他指令的第一个操作数通常是目标寄存器
if (!instr->getOperands().empty() &&
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand *>(instr->getOperands().front().get());
if (reg_op->isVirtual()) {
defined_regs.insert(reg_op->getVRegNum());
}
}
return defined_regs;
}
// 获取指令使用的虚拟寄存器 - 优化版本
static std::unordered_set<unsigned> getUsedVirtualRegisters(MachineInstr *instr) {
std::unordered_set<unsigned> used_regs;
RVOpcodes opcode = instr->getOpcode();
// CALL指令跳过第一个操作数返回值其余为参数
if (opcode == RVOpcodes::CALL) {
bool first_reg_skipped = false;
for (const auto &op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
if (!first_reg_skipped) {
first_reg_skipped = true;
continue;
}
auto reg_op = static_cast<RegOperand *>(op.get());
if (reg_op->isVirtual()) {
used_regs.insert(reg_op->getVRegNum());
}
}
}
return used_regs;
}
// 存储指令和终结指令:所有操作数都是使用的
if (isStoreInstr(instr) || isTerminatorInstr(instr)) {
for (const auto &op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand *>(op.get());
if (reg_op->isVirtual()) {
used_regs.insert(reg_op->getVRegNum());
}
} else if (op->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand *>(op.get());
if (mem_op->getBase()->isVirtual()) {
used_regs.insert(mem_op->getBase()->getVRegNum());
}
}
}
return used_regs;
}
// 其他指令:跳过第一个操作数(目标寄存器),其余为源操作数
bool first_reg = true;
for (const auto &op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
if (first_reg) {
first_reg = false;
continue;
}
auto reg_op = static_cast<RegOperand *>(op.get());
if (reg_op->isVirtual()) {
used_regs.insert(reg_op->getVRegNum());
}
} else if (op->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand *>(op.get());
if (mem_op->getBase()->isVirtual()) {
used_regs.insert(mem_op->getBase()->getVRegNum());
}
}
}
return used_regs;
}
// 获取内存访问位置
static MemoryLocation getMemoryLocation(MachineInstr *instr) {
if (!isLoadInstr(instr) && !isStoreInstr(instr)) {
return MemoryLocation();
}
for (const auto &op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand *>(op.get());
if (mem_op->getBase()->isVirtual()) {
return MemoryLocation(mem_op->getBase()->getVRegNum(),
mem_op->getOffset()->getValue());
}
}
}
return MemoryLocation();
}
// 预计算并缓存指令信息
static const InstrInfo& getInstrInfo(MachineInstr *instr) {
auto it = instr_info_cache.find(instr);
if (it != instr_info_cache.end()) {
return it->second;
}
InstrInfo& info = instr_info_cache[instr];
info.defined_regs = getDefinedVirtualRegisters(instr);
info.used_regs = getUsedVirtualRegisters(instr);
info.mem_location = getMemoryLocation(instr);
info.is_load = isLoadInstr(instr);
info.is_store = isStoreInstr(instr);
info.is_terminator = isTerminatorInstr(instr);
info.is_call = isCallInstr(instr);
info.has_side_effect = hasSideEffect(instr);
info.has_memory_access = hasMemoryAccess(instr);
return info;
}
// 检查两个内存位置是否可能别名
static bool mayAlias(const MemoryLocation &loc1, const MemoryLocation &loc2) {
if (!loc1.is_valid || !loc2.is_valid) {
return true; // 保守处理:未知位置可能别名
}
// 不同基址寄存器,保守假设可能别名
if (loc1.base_reg != loc2.base_reg) {
return true;
}
// 相同基址寄存器,检查偏移
return loc1.offset == loc2.offset;
}
// 检查两个指令之间是否存在数据依赖 - 优化版本
static bool hasDataDependency(MachineInstr *first, MachineInstr *second) {
const InstrInfo& info_first = getInstrInfo(first);
const InstrInfo& info_second = getInstrInfo(second);
// RAW依赖: second读取first写入的寄存器
for (const auto &reg : info_first.defined_regs) {
if (info_second.used_regs.find(reg) != info_second.used_regs.end()) {
return true;
}
}
// WAR依赖: second写入first读取的寄存器
for (const auto &reg : info_first.used_regs) {
if (info_second.defined_regs.find(reg) != info_second.defined_regs.end()) {
return true;
}
}
// WAW依赖: 两个指令写入同一寄存器
for (const auto &reg : info_first.defined_regs) {
if (info_second.defined_regs.find(reg) != info_second.defined_regs.end()) {
return true;
}
}
return false;
}
// 检查两个指令之间是否存在内存依赖 - 优化版本
static bool hasMemoryDependency(MachineInstr *first, MachineInstr *second) {
const InstrInfo& info_first = getInstrInfo(first);
const InstrInfo& info_second = getInstrInfo(second);
if (!info_first.has_memory_access || !info_second.has_memory_access) {
return false;
}
// 如果至少有一个是存储指令,需要检查别名
if (info_first.is_store || info_second.is_store) {
return mayAlias(info_first.mem_location, info_second.mem_location);
}
return false; // 两个加载指令之间没有依赖
}
// 检查两个指令之间是否存在控制依赖 - 优化版本
static bool hasControlDependency(MachineInstr *first, MachineInstr *second) {
const InstrInfo& info_first = getInstrInfo(first);
const InstrInfo& info_second = getInstrInfo(second);
// 终结指令与任何其他指令都有控制依赖
if (info_first.is_terminator) {
return true; // first是终结指令second不能移动到first之前
}
if (info_second.is_terminator) {
return false; // second是终结指令可以保持在后面
}
// CALL指令具有控制副作用但可以参与有限的调度
if (info_first.is_call || info_second.is_call) {
// CALL指令之间保持顺序
if (info_first.is_call && info_second.is_call) {
return true;
}
// 其他情况允许调度(通过数据依赖控制)
}
return false;
}
// 综合检查两个指令是否可以交换 - 优化版本
static bool canSwapInstructions(MachineInstr *first, MachineInstr *second) {
// 检查所有类型的依赖
if (hasDataDependency(first, second) || hasDataDependency(second, first)) {
return false;
}
if (hasMemoryDependency(first, second)) {
return false;
}
if (hasControlDependency(first, second) ||
hasControlDependency(second, first)) {
return false;
}
return true;
}
// 找到基本块中的调度边界 - 优化版本
static std::vector<size_t>
findSchedulingBoundaries(const std::vector<MachineInstr *> &instrs) {
std::vector<size_t> boundaries;
boundaries.reserve(instrs.size() / 10); // 预估边界数量
boundaries.push_back(0); // 起始边界
for (size_t i = 0; i < instrs.size(); i++) {
const InstrInfo& info = getInstrInfo(instrs[i]);
// 终结指令前后都是边界
if (info.is_terminator) {
if (i > 0)
boundaries.push_back(i);
if (i + 1 < instrs.size())
boundaries.push_back(i + 1);
}
// 跳转目标标签也可能是边界(这里简化处理)
}
boundaries.push_back(instrs.size()); // 结束边界
// 去重并排序
std::sort(boundaries.begin(), boundaries.end());
boundaries.erase(std::unique(boundaries.begin(), boundaries.end()),
boundaries.end());
return boundaries;
}
// 在单个调度区域内进行指令调度 - 优化版本
static void scheduleRegion(std::vector<MachineInstr *> &instrs, size_t start,
size_t end) {
if (end - start <= 1) {
return; // 区域太小,无需调度
}
// 保守的调度策略:
// 1. 只对小规模区域进行调度
// 2. 优先将加载指令向前调度,以隐藏内存延迟
// 3. 确保不破坏数据依赖和内存依赖
// 简单的调度算法:只尝试将加载指令尽可能前移
for (size_t i = start + 1; i < end; i++) {
const InstrInfo& info = getInstrInfo(instrs[i]);
if (info.is_load) {
// 尝试将加载指令向前移动
for (size_t j = i; j > start; j--) {
// 检查是否可以与前一条指令交换
if (canSwapInstructions(instrs[j - 1], instrs[j])) {
std::swap(instrs[j - 1], instrs[j]);
} else {
// 一旦遇到依赖关系就停止移动
break;
}
}
}
}
}
static void scheduleBlock(MachineBasicBlock *mbb) {
auto &instructions = mbb->getInstructions();
if (instructions.size() <= 1 ||
instructions.size() > MAX_SCHEDULING_BLOCK_SIZE) {
return;
}
// 清理缓存,避免无效指针
instr_info_cache.clear();
// 构建指令列表
std::vector<MachineInstr *> instr_list;
instr_list.reserve(instructions.size()); // 预分配容量
for (auto &instr : instructions) {
instr_list.push_back(instr.get());
}
// 预计算所有指令信息
for (auto* instr : instr_list) {
getInstrInfo(instr);
}
// 找到调度边界
std::vector<size_t> boundaries = findSchedulingBoundaries(instr_list);
// 在每个调度区域内进行局部调度
for (size_t i = 0; i < boundaries.size() - 1; i++) {
size_t region_start = boundaries[i];
size_t region_end = boundaries[i + 1];
scheduleRegion(instr_list, region_start, region_end);
}
// 重建指令序列
std::unordered_map<MachineInstr *, std::unique_ptr<MachineInstr>> instr_map;
instr_map.reserve(instructions.size()); // 预分配容量
for (auto &instr : instructions) {
instr_map[instr.get()] = std::move(instr);
}
instructions.clear();
instructions.reserve(instr_list.size()); // 预分配容量
for (auto *instr : instr_list) {
instructions.push_back(std::move(instr_map[instr]));
}
}
bool PreRA_Scheduler::runOnFunction(Function *F, AnalysisManager &AM) {
return false;
}
void PreRA_Scheduler::runOnMachineFunction(MachineFunction *mfunc) {
for (auto &mbb : mfunc->getBlocks()) {
scheduleBlock(mbb.get());
}
// 清理全局缓存
instr_info_cache.clear();
}
} // namespace sysy

View File

@ -1,15 +1,22 @@
#include "RISCv64AsmPrinter.h"
#include "RISCv64ISel.h"
#include <stdexcept>
#include <sstream>
#include <iostream>
namespace sysy {
// 检查是否为内存加载/存储指令,以处理特殊的打印格式
bool isMemoryOp(RVOpcodes opcode) {
switch (opcode) {
// --- 整数加载/存储 (原有逻辑) ---
case RVOpcodes::LB: case RVOpcodes::LH: case RVOpcodes::LW: case RVOpcodes::LD:
case RVOpcodes::LBU: case RVOpcodes::LHU: case RVOpcodes::LWU:
case RVOpcodes::SB: case RVOpcodes::SH: case RVOpcodes::SW: case RVOpcodes::SD:
case RVOpcodes::FLW:
case RVOpcodes::FSW:
// 如果未来支持双精度也在这里添加FLD/FSD
// case RVOpcodes::FLD:
// case RVOpcodes::FSD:
return true;
default:
return false;
@ -18,84 +25,43 @@ bool isMemoryOp(RVOpcodes opcode) {
RISCv64AsmPrinter::RISCv64AsmPrinter(MachineFunction* mfunc) : MFunc(mfunc) {}
void RISCv64AsmPrinter::run(std::ostream& os) {
void RISCv64AsmPrinter::run(std::ostream& os, bool debug) {
OS = &os;
*OS << ".globl " << MFunc->getName() << "\n";
*OS << MFunc->getName() << ":\n";
printPrologue();
for (auto& mbb : MFunc->getBlocks()) {
printBasicBlock(mbb.get());
printBasicBlock(mbb.get(), debug);
}
}
void RISCv64AsmPrinter::printPrologue() {
StackFrameInfo& frame_info = MFunc->getFrameInfo();
// 序言需要为保存ra和s0预留16字节
int total_stack_size = frame_info.locals_size + frame_info.spill_size + 16;
int aligned_stack_size = (total_stack_size + 15) & ~15;
frame_info.total_size = aligned_stack_size;
if (aligned_stack_size > 0) {
*OS << " addi sp, sp, -" << aligned_stack_size << "\n";
*OS << " sd ra, " << (aligned_stack_size - 8) << "(sp)\n";
*OS << " sd s0, " << (aligned_stack_size - 16) << "(sp)\n";
*OS << " mv s0, sp\n";
}
// 忠实还原保存函数入口参数的逻辑
Function* F = MFunc->getFunc();
if (F && F->getEntryBlock()) {
int arg_idx = 0;
RISCv64ISel* isel = MFunc->getISel();
for (AllocaInst* alloca_for_param : F->getEntryBlock()->getArguments()) {
if (arg_idx >= 8) break;
unsigned vreg = isel->getVReg(alloca_for_param);
if (frame_info.alloca_offsets.count(vreg)) {
int offset = frame_info.alloca_offsets.at(vreg);
auto arg_reg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + arg_idx);
*OS << " sw " << regToString(arg_reg) << ", " << offset << "(s0)\n";
}
arg_idx++;
}
}
}
void RISCv64AsmPrinter::printEpilogue() {
int aligned_stack_size = MFunc->getFrameInfo().total_size;
if (aligned_stack_size > 0) {
*OS << " ld ra, " << (aligned_stack_size - 8) << "(sp)\n";
*OS << " ld s0, " << (aligned_stack_size - 16) << "(sp)\n";
*OS << " addi sp, sp, " << aligned_stack_size << "\n";
}
}
void RISCv64AsmPrinter::printBasicBlock(MachineBasicBlock* mbb) {
void RISCv64AsmPrinter::printBasicBlock(MachineBasicBlock* mbb, bool debug) {
if (!mbb->getName().empty()) {
*OS << mbb->getName() << ":\n";
}
for (auto& instr : mbb->getInstructions()) {
printInstruction(instr.get());
printInstruction(instr.get(), debug);
}
}
void RISCv64AsmPrinter::printInstruction(MachineInstr* instr) {
void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
auto opcode = instr->getOpcode();
if (opcode == RVOpcodes::RET) {
printEpilogue();
}
if (opcode != RVOpcodes::LABEL) {
*OS << " ";
if (opcode == RVOpcodes::LABEL) {
// 标签直接打印,不加缩进
printOperand(instr->getOperands()[0].get());
*OS << ":\n";
return; // 处理完毕,直接返回
}
// 对于所有非标签指令,先打印缩进
*OS << " ";
switch (opcode) {
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;
@ -114,7 +80,9 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr) {
case RVOpcodes::LHU: *OS << "lhu "; break; case RVOpcodes::LBU: *OS << "lbu "; break;
case RVOpcodes::SW: *OS << "sw "; break; case RVOpcodes::SH: *OS << "sh "; break;
case RVOpcodes::SB: *OS << "sb "; break; case RVOpcodes::LD: *OS << "ld "; break;
case RVOpcodes::SD: *OS << "sd "; break;
case RVOpcodes::SD: *OS << "sd "; break; case RVOpcodes::FLW: *OS << "flw "; break;
case RVOpcodes::FSW: *OS << "fsw "; break; case RVOpcodes::FLD: *OS << "fld "; break;
case RVOpcodes::FSD: *OS << "fsd "; break;
case RVOpcodes::J: *OS << "j "; break; case RVOpcodes::JAL: *OS << "jal "; break;
case RVOpcodes::JALR: *OS << "jalr "; break; case RVOpcodes::RET: *OS << "ret"; break;
case RVOpcodes::BEQ: *OS << "beq "; break; case RVOpcodes::BNE: *OS << "bne "; break;
@ -123,16 +91,63 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr) {
case RVOpcodes::LI: *OS << "li "; break; case RVOpcodes::LA: *OS << "la "; break;
case RVOpcodes::MV: *OS << "mv "; break; case RVOpcodes::NEG: *OS << "neg "; break;
case RVOpcodes::NEGW: *OS << "negw "; break; case RVOpcodes::SEQZ: *OS << "seqz "; break;
case RVOpcodes::SNEZ: *OS << "snez "; break;
case RVOpcodes::CALL: *OS << "call "; break;
case RVOpcodes::SNEZ: *OS << "snez "; break;
case RVOpcodes::FADD_S: *OS << "fadd.s "; break;
case RVOpcodes::FSUB_S: *OS << "fsub.s "; break;
case RVOpcodes::FMUL_S: *OS << "fmul.s "; break;
case RVOpcodes::FDIV_S: *OS << "fdiv.s "; break;
case RVOpcodes::FNEG_S: *OS << "fneg.s "; break;
case RVOpcodes::FEQ_S: *OS << "feq.s "; break;
case RVOpcodes::FLT_S: *OS << "flt.s "; break;
case RVOpcodes::FLE_S: *OS << "fle.s "; break;
case RVOpcodes::FCVT_S_W: *OS << "fcvt.s.w "; break;
case RVOpcodes::FCVT_W_S: *OS << "fcvt.w.s "; break;
case RVOpcodes::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指令添加特殊处理逻辑
*OS << "call ";
// 遍历所有操作数,只寻找并打印函数名标签
for (const auto& op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_LABEL) {
printOperand(op.get());
break; // 找到标签后即可退出
}
}
*OS << "\n";
return; // 处理完毕,直接返回,不再执行后续的通用操作数打印
}
case RVOpcodes::LABEL:
printOperand(instr->getOperands()[0].get());
*OS << ":";
break;
case RVOpcodes::FRAME_LOAD:
case RVOpcodes::FRAME_STORE:
// These should have been eliminated by RegAlloc
throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
case RVOpcodes::FRAME_LOAD_W:
// It should have been eliminated by RegAlloc
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
*OS << "frame_load_w "; break;
case RVOpcodes::FRAME_LOAD_D:
// It should have been eliminated by RegAlloc
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
*OS << "frame_load_d "; break;
case RVOpcodes::FRAME_STORE_W:
// It should have been eliminated by RegAlloc
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
*OS << "frame_store_w "; break;
case RVOpcodes::FRAME_STORE_D:
// It should have been eliminated by RegAlloc
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
*OS << "frame_store_d "; break;
case RVOpcodes::FRAME_ADDR:
// It should have been eliminated by RegAlloc
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
*OS << "frame_addr "; break;
case RVOpcodes::FRAME_LOAD_F:
if (!debug) throw std::runtime_error("FRAME_LOAD_F not eliminated before AsmPrinter");
*OS << "frame_load_f "; break;
case RVOpcodes::FRAME_STORE_F:
if (!debug) throw std::runtime_error("FRAME_STORE_F not eliminated before AsmPrinter");
*OS << "frame_store_f "; break;
case RVOpcodes::PSEUDO_KEEPALIVE:
if (!debug) throw std::runtime_error("PSEUDO_KEEPALIVE not eliminated before AsmPrinter");
*OS << "keepalive "; break;
default:
throw std::runtime_error("Unknown opcode in AsmPrinter");
}
@ -222,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

@ -0,0 +1,282 @@
#include "RISCv64Backend.h"
#include "RISCv64ISel.h"
#include "RISCv64RegAlloc.h"
#include "RISCv64AsmPrinter.h"
#include "RISCv64Passes.h"
#include <sstream>
namespace sysy {
// 顶层入口
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将全局变量(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();
// 检查初始化值是否全部为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 {
data_globals.push_back(global);
}
}
// --- 步骤2生成 .bss 段的代码 ---
if (!bss_globals.empty()) {
ss << ".bss\n";
for (GlobalValue* global : bss_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";
ss << " .space " << total_size << "\n";
}
}
// --- 步骤3生成 .data 段的代码 ---
if (!data_globals.empty() || !module->getConsts().empty()) {
ss << ".data\n";
// a. 处理普通的全局变量 (GlobalValue)
for (GlobalValue* global : data_globals) {
Type* allocated_type = global->getType()->as<PointerType>()->getBaseType();
unsigned total_size = getTypeSizeInBytes(allocated_type);
ss << " .align 3\n";
ss << ".globl " << global->getName() << "\n";
ss << ".type " << global->getName() << ", @object\n";
ss << ".size " << global->getName() << ", " << total_size << "\n";
ss << global->getName() << ":\n";
bool is_all_zeros = true;
const auto& init_values = global->getInitValues();
if (init_values.getValues().empty()) {
is_all_zeros = true;
} else {
for (auto val : init_values.getValues()) {
if (auto const_val = dynamic_cast<ConstantValue*>(val)) {
if (!const_val->isZero()) {
is_all_zeros = false;
break;
}
} else {
is_all_zeros = false;
break;
}
}
}
if (is_all_zeros) {
ss << " .zero " << total_size << "\n";
} else {
// 对于有非零初始值的变量,保持原有的打印逻辑。
printInitializer(ss, global->getInitValues());
}
}
// b. 处理全局常量 (ConstantVariable)
for (const auto& const_ptr : module->getConsts()) {
ConstantVariable* cnst = const_ptr.get();
Type* allocated_type = cnst->getType()->as<PointerType>()->getBaseType();
unsigned total_size = getTypeSizeInBytes(allocated_type);
ss << " .align 3\n";
ss << ".globl " << cnst->getName() << "\n";
ss << ".type " << cnst->getName() << ", @object\n";
ss << ".size " << cnst->getName() << ", " << total_size << "\n";
ss << cnst->getName() << ":\n";
printInitializer(ss, cnst->getInitValues());
}
}
// --- 步骤4处理函数 (.text段) 的逻辑 ---
if (!module->getFunctions().empty()) {
ss << ".text\n";
for (const auto& func_pair : module->getFunctions()) {
if (func_pair.second.get() && !func_pair.second->getBasicBlocks().empty()) {
ss << function_gen(func_pair.second.get());
if (DEBUG) std::cerr << "Function: " << func_pair.first << " generated.\n";
}
}
}
return ss.str();
}
std::string RISCv64CodeGen::function_gen(Function* func) {
// === 完整的后端处理流水线 ===
// 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers)
DEBUG = 0;
DEEPDEBUG = 0;
RISCv64ISel isel;
std::unique_ptr<MachineFunction> mfunc = isel.runOnFunction(func);
// 第一次调试打印输出
std::stringstream ss_after_isel;
RISCv64AsmPrinter printer_isel(mfunc.get());
printer_isel.run(ss_after_isel, true);
if (DEBUG) {
std::cout << ss_after_isel.str();
}
if (DEBUG) {
std::cerr << "====== Intermediate Representation after Instruction Selection ======\n"
<< ss_after_isel.str();
}
// 阶段 2: 消除帧索引 (展开伪指令,计算局部变量偏移)
// 这个Pass必须在寄存器分配之前运行
EliminateFrameIndicesPass efi_pass;
efi_pass.runOnMachineFunction(mfunc.get());
if (DEBUG) {
std::cerr << "====== stack info after eliminate frame indices ======\n";
mfunc->dumpStackFrameInfo(std::cerr);
std::stringstream ss_after_eli;
printer_isel.run(ss_after_eli, true);
std::cerr << "====== LLIR after eliminate frame indices ======\n"
<< ss_after_eli.str();
}
// 阶段 2: 除法强度削弱优化 (Division Strength Reduction)
DivStrengthReduction div_strength_reduction;
div_strength_reduction.runOnMachineFunction(mfunc.get());
// 阶段 2.1: 指令调度 (Instruction Scheduling)
PreRA_Scheduler scheduler;
scheduler.runOnMachineFunction(mfunc.get());
// 阶段 3: 物理寄存器分配 (Register Allocation)
RISCv64RegAlloc reg_alloc(mfunc.get());
reg_alloc.run();
if (DEBUG) {
std::cerr << "====== 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());
// 阶段 5: 局部指令调度 (Local Scheduling)
PostRA_Scheduler local_scheduler;
local_scheduler.runOnMachineFunction(mfunc.get());
// 阶段 3.2: 插入序言和尾声
PrologueEpilogueInsertionPass pei_pass;
pei_pass.runOnMachineFunction(mfunc.get());
// 阶段 3.3: 大立即数合法化
LegalizeImmediatesPass legalizer;
legalizer.runOnMachineFunction(mfunc.get());
// 阶段 6: 代码发射 (Code Emission)
std::stringstream ss;
RISCv64AsmPrinter printer(mfunc.get());
printer.run(ss);
return ss.str();
}
} // namespace sysy

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +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,17 @@
# src/frontend/CMakeLists.txt
add_library(frontend_lib STATIC
SysYBaseVisitor.cpp
SysY.g4
SysYLexer.cpp
SysYParser.cpp
SysYVisitor.cpp
)
# 包含前端模块所需的头文件路径
target_include_directories(frontend_lib PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../include/frontend # 前端头文件
${ANTLR_RUNTIME}/runtime/src # ANTLR 运行时头文件
)
# 链接 ANTLR 运行时库
target_link_libraries(frontend_lib PRIVATE antlr4_shared)

View File

@ -1,59 +0,0 @@
#pragma once
#include "IR.h" // 假设IR.h包含了Module, Function, BasicBlock, Instruction, Value, IRBuilder, Type等定义
#include "IRBuilder.h" // 需要IRBuilder来创建新指令
#include "SysYIRPrinter.h" // 新增: 用于调试输出
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include <list> // 用于迭代和修改指令列表
#include <algorithm> // for std::reverse (if needed, although not used in final version)
#include <iostream> // MODIFICATION: 用于警告输出
namespace sysy {
/**
* @brief AddressCalculationExpansion Pass
*
* 这是一个IR优化Pass用于将LoadInst和StoreInst中包含的多维数组索引
* 显式地转换为IR中的BinaryInst乘法和加法序列并生成带有线性偏移量的
* LoadInst/StoreInst。
*
* 目的确保在寄存器分配之前所有中间地址计算的结果都有明确的IR指令和对应的虚拟寄存器
* 从而避免在后端DAG构建时临时创建值而导致寄存器分配缺失的问题。
*
* SysY语言特性
* - 无指针类型所有数组访问的基地址是alloca或global的AllocaType/ArrayType
* - 数据类型只有int和float且都占用4字节。
* - LoadInst和StoreInst直接接受多个索引作为额外操作数。
*/
class AddressCalculationExpansion {
private:
Module* pModule;
IRBuilder* pBuilder; // 用于在IR中插入新指令
// 数组元素的固定大小根据SysY特性int和float都是4字节
static const int ELEMENT_SIZE = 4;
// 辅助函数:根据数组的维度信息和当前索引的维度,计算该索引的步长(字节数)
// dims: 包含所有维度大小的vector例如 {2, 3, 4}
// currentDimIndex: 当前正在处理的索引在 dims 中的位置 (0, 1, 2...)
int calculateStride(const std::vector<int>& dims, size_t currentDimIndex) {
int stride = ELEMENT_SIZE; // 最内层元素大小 (4字节)
// 乘以当前维度之后的所有维度的大小
for (size_t i = currentDimIndex + 1; i < dims.size(); ++i) {
stride *= dims[i];
}
return stride;
}
public:
AddressCalculationExpansion(Module* module, IRBuilder* builder)
: pModule(module), pBuilder(builder) {}
// 运行此Pass
bool run();
};
} // namespace sysy

View File

@ -1,39 +0,0 @@
#pragma once
#include "IR.h"
#include "SysYIRAnalyser.h"
#include "SysYIRPrinter.h"
namespace sysy {
class DeadCodeElimination {
private:
Module *pModule;
ControlFlowAnalysis *pCFA; // 控制流分析指针
ActiveVarAnalysis *pAVA; // 活跃变量分析指针
DataFlowAnalysisUtils dataFlowAnalysisUtils; // 数据流分析工具类
public:
explicit DeadCodeElimination(Module *pMoudle,
ControlFlowAnalysis *pCFA = nullptr,
ActiveVarAnalysis *pAVA = nullptr)
: pModule(pMoudle), pCFA(pCFA), pAVA(pAVA), dataFlowAnalysisUtils() {} // 构造函数
// TODO根据参数传入的passes来运行不同的死代码删除流程
// void runDCEPipeline(const std::vector<std::string>& passes = {
// "dead-store", "redundant-load-store", "dead-load", "dead-alloca", "dead-global"
// });
void runDCEPipeline(); // 运行死代码删除
void eliminateDeadStores(Function* func, bool& changed); // 消除无用存储
void eliminateDeadLoads(Function* func, bool& changed); // 消除无用加载
void eliminateDeadAllocas(Function* func, bool& changed); // 消除无用内存分配
void eliminateDeadGlobals(bool& changed); // 消除无用全局变量
void eliminateDeadIndirectiveAllocas(Function* func, bool& changed); // 消除无用间接内存分配(phi节点)
void eliminateDeadRedundantLoadStore(Function* func, bool& changed); // 消除冗余加载和存储
bool isGlobal(Value *val);
bool isArr(Value *val);
void usedelete(Instruction *instr);
};
} // namespace sysy

View File

@ -1,59 +0,0 @@
#pragma once
#include <list>
#include <memory>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include "IR.h"
#include "IRBuilder.h"
#include "SysYIRAnalyser.h"
namespace sysy {
/**
* 实现静态单变量赋值核心类 mem2reg
*/
class Mem2Reg {
private:
Module *pModule;
IRBuilder *pBuilder;
ControlFlowAnalysis *controlFlowAnalysis; // 控制流分析
ActiveVarAnalysis *activeVarAnalysis; // 活跃变量分析
DataFlowAnalysisUtils dataFlowAnalysisUtils;
public:
Mem2Reg(Module *pMoudle, IRBuilder *pBuilder,
ControlFlowAnalysis *pCFA = nullptr, ActiveVarAnalysis *pAVA = nullptr) :
pModule(pMoudle), pBuilder(pBuilder), controlFlowAnalysis(pCFA), activeVarAnalysis(pAVA), dataFlowAnalysisUtils()
{} // 初始化函数
void mem2regPipeline(); ///< mem2reg
private:
// phi节点的插入需要计算IDF
std::unordered_set<BasicBlock *> computeIterDf(const std::unordered_set<BasicBlock *> &blocks); ///< 计算定义块集合的迭代支配边界
auto computeValue2Blocks() -> void; ///< 计算value2block的映射(不包括数组和global)
auto preOptimize1() -> void; ///< llvm memtoreg预优化1: 删除不含load的alloc和store
auto preOptimize2() -> void; ///< llvm memtoreg预优化2: 针对某个变量的Defblocks只有一个块的情况
auto preOptimize3() -> void; ///< llvm memtoreg预优化3: 针对某个变量的所有读写都在同一个块中的情况
auto insertPhi() -> void; ///< 为所有变量的迭代支配边界插入phi结点
auto rename(BasicBlock *block, std::unordered_map<Value *, int> &count,
std::unordered_map<Value *, std::stack<Instruction *>> &stacks) -> void; ///< 单个块的重命名
auto renameAll() -> void; ///< 重命名所有块
// private helper function.
private:
auto getPredIndex(BasicBlock *n, BasicBlock *s) -> int; ///< 获取前驱索引
auto cascade(Instruction *instr, bool &changed, Function *func, BasicBlock *block,
std::list<std::unique_ptr<Instruction>> &instrs) -> void; ///< 消除级联关系
auto isGlobal(Value *val) -> bool; ///< 判断是否是全局变量
auto isArr(Value *val) -> bool; ///< 判断是否是数组
auto usedelete(Instruction *instr) -> void; ///< 删除指令相关的value-use-user关系
};
} // namespace sysy

View File

@ -1,18 +0,0 @@
// RISCv64Passes.h
#ifndef RISCV64_PASSES_H
#define RISCV64_PASSES_H
#include "RISCv64LLIR.h"
namespace sysy {
// 此处为未来优化Pass的基类或独立类定义
// 例如:
// class PeepholeOptimizer {
// public:
// void runOnMachineFunction(MachineFunction* mfunc);
// };
} // namespace sysy
#endif // RISCV64_PASSES_H

View File

@ -1,56 +0,0 @@
#ifndef RISCV64_REGALLOC_H
#define RISCV64_REGALLOC_H
#include "RISCv64LLIR.h"
namespace sysy {
class RISCv64RegAlloc {
public:
RISCv64RegAlloc(MachineFunction* mfunc);
// 模块主入口
void run();
private:
using LiveSet = std::set<unsigned>; // 活跃虚拟寄存器集合
using InterferenceGraph = std::map<unsigned, std::set<unsigned>>;
// 栈帧管理
void eliminateFrameIndices();
// 活跃性分析
void analyzeLiveness();
// 构建干扰图
void buildInterferenceGraph();
// 图着色分配寄存器
void colorGraph();
// 重写函数替换vreg并插入溢出代码
void rewriteFunction();
// 辅助函数获取指令的Use/Def集合
void getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def);
MachineFunction* MFunc;
// 活跃性分析结果
std::map<const MachineInstr*, LiveSet> live_in_map;
std::map<const MachineInstr*, LiveSet> live_out_map;
// 干扰图
InterferenceGraph interference_graph;
// 图着色结果
std::map<unsigned, PhysicalReg> color_map; // vreg -> preg
std::set<unsigned> spilled_vregs; // 被溢出的vreg集合
// 可用的物理寄存器池
std::vector<PhysicalReg> allocable_int_regs;
};
} // namespace sysy
#endif // RISCV64_REGALLOC_H

View File

@ -1,23 +0,0 @@
#pragma once
#include "IR.h"
#include "IRBuilder.h"
namespace sysy {
/**
* Reg2Mem(后端未做phi指令翻译)
*/
class Reg2Mem {
private:
Module *pModule;
IRBuilder *pBuilder;
public:
Reg2Mem(Module *pMoudle, IRBuilder *pBuilder) : pModule(pMoudle), pBuilder(pBuilder) {}
void DeletePhiInst();
// 删除UD关系, 因为删除了phi指令会修改ud关系
void usedelete(Instruction *instr);
};
} // namespace sysy

View File

@ -1,340 +0,0 @@
#pragma once
#include "SysYBaseVisitor.h"
#include "SysYParser.h"
#include <ostream>
namespace sysy {
class SysYFormatter : public SysYBaseVisitor {
protected:
std::ostream &os;
int indent = 0;
public:
SysYFormatter(std::ostream &os) : os(os), indent(0) {}
protected:
struct Indentor {
static constexpr int TabSize = 2;
int &indent;
Indentor(int &indent) : indent(indent) { indent += TabSize; }
~Indentor() { indent -= TabSize; }
};
std::ostream &space() { return os << std::string(indent, ' '); }
template <typename T>
std::ostream &interleave(const T &container, const std::string sep = ", ") {
auto b = container.begin(), e = container.end();
(*b)->accept(this);
for (b = std::next(b); b != e; b = std::next(b)) {
os << sep;
(*b)->accept(this);
}
return os;
}
public:
// virtual std::any visitModule(SysYParser::ModuleContext *ctx) override {
// return visitChildren(ctx);
// }
virtual std::any visitBtype(SysYParser::BtypeContext *ctx) override {
os << ctx->getText();
return 0;
}
virtual std::any visitDecl(SysYParser::DeclContext *ctx) override {
space();
if (ctx->CONST())
os << ctx->CONST()->getText() << ' ';
ctx->btype()->accept(this);
os << ' ';
interleave(ctx->varDef(), ", ") << ';' << '\n';
return 0;
}
virtual std::any visitVarDef(SysYParser::VarDefContext *ctx) override {
ctx->lValue()->accept(this);
if (ctx->initValue()) {
os << ' ' << '=' << ' ';
ctx->initValue()->accept(this);
}
return 0;
}
virtual std::any visitInitValue(SysYParser::InitValueContext *ctx) override {
if (not ctx->exp()) {
os << '{';
auto values = ctx->initValue();
if (values.size())
interleave(values, ", ");
os << '}';
}
return 0;
}
virtual std::any visitFunc(SysYParser::FuncContext *ctx) override {
ctx->funcType()->accept(this);
os << ' ' << ctx->ID()->getText() << '(';
if (ctx->funcFParams())
ctx->funcFParams()->accept(this);
os << ')' << ' ';
ctx->blockStmt()->accept(this);
os << '\n';
return 0;
}
virtual std::any visitFuncType(SysYParser::FuncTypeContext *ctx) override {
os << ctx->getText();
return 0;
}
virtual std::any
visitFuncFParams(SysYParser::FuncFParamsContext *ctx) override {
interleave(ctx->funcFParam(), ", ");
return 0;
}
virtual std::any
visitFuncFParam(SysYParser::FuncFParamContext *ctx) override {
ctx->btype()->accept(this);
os << ' ' << ctx->ID()->getText();
if (not ctx->LBRACKET().empty()) {
os << '[';
auto exp = ctx->exp();
if (not exp.empty()) {
os << '[';
interleave(exp, "][") << ']';
}
}
return 0;
}
virtual std::any visitBlockStmt(SysYParser::BlockStmtContext *ctx) override {
os << '{' << '\n';
{
Indentor indentor(indent);
auto items = ctx->blockItem();
if (not items.empty())
interleave(items, "");
}
space() << ctx->RBRACE()->getText() << '\n';
return 0;
}
// virtual std::any visitBlockItem(SysYParser::BlockItemContext *ctx)
// override {
// return visitChildren(ctx);
// }
// virtual std::any visitStmt(SysYParser::StmtContext *ctx) override {
// return visitChildren(ctx);
// }
virtual std::any
visitAssignStmt(SysYParser::AssignStmtContext *ctx) override {
space();
ctx->lValue()->accept(this);
os << " = ";
ctx->exp()->accept(this);
os << ';' << '\n';
return 0;
}
virtual std::any visitExpStmt(SysYParser::ExpStmtContext *ctx) override {
space();
ctx->exp()->accept(this);
os << ';' << '\n';
return 0;
}
void wrapBlock(SysYParser::StmtContext *stmt) {
bool isBlock = stmt->blockStmt();
if (isBlock) {
stmt->accept(this);
} else {
os << "{\n";
{
Indentor indentor(indent);
stmt->accept(this);
}
space() << "}\n";
}
};
virtual std::any visitIfStmt(SysYParser::IfStmtContext *ctx) override {
space();
os << ctx->IF()->getText() << " (";
ctx->exp()->accept(this);
os << ") ";
auto stmt = ctx->stmt();
auto ifStmt = stmt[0];
wrapBlock(ifStmt);
if (stmt.size() == 2) {
auto elseStmt = stmt[1];
wrapBlock(elseStmt);
}
return 0;
}
virtual std::any visitWhileStmt(SysYParser::WhileStmtContext *ctx) override {
space();
os << ctx->WHILE()->getText() << " (";
ctx->exp()->accept(this);
os << ") ";
wrapBlock(ctx->stmt());
return 0;
}
virtual std::any visitBreakStmt(SysYParser::BreakStmtContext *ctx) override {
space() << ctx->BREAK()->getText() << ';' << '\n';
return 0;
}
virtual std::any
visitContinueStmt(SysYParser::ContinueStmtContext *ctx) override {
space() << ctx->CONTINUE()->getText() << ';' << '\n';
return 0;
}
virtual std::any
visitReturnStmt(SysYParser::ReturnStmtContext *ctx) override {
space() << ctx->RETURN()->getText();
if (ctx->exp()) {
os << ' ';
ctx->exp()->accept(this);
}
os << ';' << '\n';
return 0;
}
// virtual std::any visitEmptyStmt(SysYParser::EmptyStmtContext *ctx)
// override {
// return visitChildren(ctx);
// }
virtual std::any
visitRelationExp(SysYParser::RelationExpContext *ctx) override {
auto lhs = ctx->exp(0);
auto rhs = ctx->exp(1);
std::string op =
ctx->LT() ? "<" : (ctx->LE() ? "<=" : (ctx->GT() ? ">" : ">="));
lhs->accept(this);
os << ' ' << op << ' ';
rhs->accept(this);
return 0;
}
virtual std::any
visitMultiplicativeExp(SysYParser::MultiplicativeExpContext *ctx) override {
auto lhs = ctx->exp(0);
auto rhs = ctx->exp(1);
std::string op = ctx->MUL() ? "*" : (ctx->DIV() ? "/" : "%");
lhs->accept(this);
os << ' ' << op << ' ';
rhs->accept(this);
return 0;
}
// virtual std::any visitLValueExp(SysYParser::LValueExpContext *ctx)
// override {
// return visitChildren(ctx);
// }
// virtual std::any visitNumberExp(SysYParser::NumberExpContext *ctx)
// override {
// return visitChildren(ctx);
// }
virtual std::any visitAndExp(SysYParser::AndExpContext *ctx) override {
ctx->exp(0)->accept(this);
os << " && ";
ctx->exp(1)->accept(this);
return 0;
}
virtual std::any visitUnaryExp(SysYParser::UnaryExpContext *ctx) override {
std::string op = ctx->ADD() ? "+" : (ctx->SUB() ? "-" : "!");
os << op;
ctx->exp()->accept(this);
return 0;
}
virtual std::any visitParenExp(SysYParser::ParenExpContext *ctx) override {
os << '(';
ctx->exp()->accept(this);
os << ')';
return 0;
}
virtual std::any visitStringExp(SysYParser::StringExpContext *ctx) override {
return visitChildren(ctx);
}
virtual std::any visitOrExp(SysYParser::OrExpContext *ctx) override {
ctx->exp(0)->accept(this);
os << " || ";
ctx->exp(1)->accept(this);
return 0;
}
// virtual std::any visitCallExp(SysYParser::CallExpContext *ctx) override {
// return visitChildren(ctx);
// }
virtual std::any
visitAdditiveExp(SysYParser::AdditiveExpContext *ctx) override {
auto lhs = ctx->exp(0);
auto rhs = ctx->exp(1);
std::string op = ctx->ADD() ? "+" : "-";
lhs->accept(this);
os << ' ' << op << ' ';
rhs->accept(this);
return 0;
}
virtual std::any visitEqualExp(SysYParser::EqualExpContext *ctx) override {
auto lhs = ctx->exp(0);
auto rhs = ctx->exp(1);
std::string op = ctx->EQ() ? "==" : "!=";
lhs->accept(this);
os << ' ' << op << ' ';
rhs->accept(this);
return 0;
}
virtual std::any visitCall(SysYParser::CallContext *ctx) override {
os << ctx->ID()->getText() << '(';
if (ctx->funcRParams())
ctx->funcRParams()->accept(this);
os << ')';
return 0;
}
virtual std::any visitLValue(SysYParser::LValueContext *ctx) override {
os << ctx->ID()->getText();
auto exp = ctx->exp();
if (not exp.empty()) {
os << '[';
interleave(exp, "][") << ']';
}
return 0;
}
virtual std::any visitNumber(SysYParser::NumberContext *ctx) override {
os << ctx->getText();
return 0;
}
virtual std::any visitString(SysYParser::StringContext *ctx) override {
os << ctx->getText();
return 0;
}
virtual std::any
visitFuncRParams(SysYParser::FuncRParamsContext *ctx) override {
interleave(ctx->exp(), ", ");
return 0;
}
};
} // namespace sysy

View File

@ -1,465 +0,0 @@
#pragma once
#include "IR.h"
namespace sysy {
// 前向声明
class Loop;
// 基本块分析信息类
class BlockAnalysisInfo {
public:
using block_list = std::vector<BasicBlock*>;
using block_set = std::unordered_set<BasicBlock*>;
protected:
// 支配树相关
int domdepth = 0; ///< 支配节点所在深度
BasicBlock* idom = nullptr; ///< 直接支配结点
block_list sdoms; ///< 支配树后继
block_set dominants; ///< 必经结点集合
block_set dominant_frontiers; ///< 支配边界
// 后续添加循环分析相关
// Loop* loopbelong = nullptr; ///< 所属循环
// int loopdepth = 0; ///< 循环深度
public:
// getterface
const int getDomDepth() const { return domdepth; }
const BasicBlock* getIdom() const { return idom; }
const block_list& getSdoms() const { return sdoms; }
const block_set& getDominants() const { return dominants; }
const block_set& getDomFrontiers() const { return dominant_frontiers; }
// 支配树操作
void setDomDepth(int depth) { domdepth = depth; }
void setIdom(BasicBlock* block) { idom = block; }
void addSdoms(BasicBlock* block) { sdoms.push_back(block); }
void clearSdoms() { sdoms.clear(); }
void removeSdoms(BasicBlock* block) {
sdoms.erase(std::remove(sdoms.begin(), sdoms.end(), block), sdoms.end());
}
void addDominants(BasicBlock* block) { dominants.emplace(block); }
void addDominants(const block_set& blocks) { dominants.insert(blocks.begin(), blocks.end()); }
void setDominants(BasicBlock* block) {
dominants.clear();
addDominants(block);
}
void setDominants(const block_set& doms) {
dominants = doms;
}
void setDomFrontiers(const block_set& df) {
dominant_frontiers = df;
}
// TODO循环分析操作方法
// 清空所有分析信息
void clear() {
domdepth = -1;
idom = nullptr;
sdoms.clear();
dominants.clear();
dominant_frontiers.clear();
// loopbelong = nullptr;
// loopdepth = 0;
}
};
// 函数分析信息类
class FunctionAnalysisInfo {
public:
// 函数属性
enum FunctionAttribute : uint64_t {
PlaceHolder = 0x0UL,
Pure = 0x1UL << 0,
SelfRecursive = 0x1UL << 1,
SideEffect = 0x1UL << 2,
NoPureCauseMemRead = 0x1UL << 3
};
// 数据结构
using Loop_list = std::list<std::unique_ptr<Loop>>;
using block_loop_map = std::unordered_map<BasicBlock*, Loop*>;
using value_block_map = std::unordered_map<Value*, BasicBlock*>;
using value_block_count_map = std::unordered_map<Value*, std::unordered_map<BasicBlock*, int>>;
// 分析数据
FunctionAttribute attribute = PlaceHolder; ///< 函数属性
std::set<Function*> callees; ///< 函数调用集合
Loop_list loops; ///< 所有循环
Loop_list topLoops; ///< 顶层循环
// block_loop_map basicblock2Loop; ///< 基本块到循环映射
std::list<std::unique_ptr<AllocaInst>> indirectAllocas; ///< 间接分配内存
// 值定义/使用信息
value_block_map value2AllocBlocks; ///< 值分配位置映射
value_block_count_map value2DefBlocks; ///< 值定义位置映射
value_block_count_map value2UseBlocks; ///< 值使用位置映射
// 函数属性操作
FunctionAttribute getAttribute() const { return attribute; }
void setAttribute(FunctionAttribute attr) { attribute = static_cast<FunctionAttribute>(attribute | attr); }
void clearAttribute() { attribute = PlaceHolder; }
// 调用关系操作
void addCallee(Function* callee) { callees.insert(callee); }
void removeCallee(Function* callee) { callees.erase(callee); }
void clearCallees() { callees.clear(); }
// 值-块映射操作
BasicBlock* getAllocBlockByValue(Value* value) {
auto it = value2AllocBlocks.find(value);
return it != value2AllocBlocks.end() ? it->second : nullptr;
}
std::unordered_set<BasicBlock *> getDefBlocksByValue(Value *value) {
std::unordered_set<BasicBlock *> blocks;
if (value2DefBlocks.count(value) > 0) {
for (const auto &pair : value2DefBlocks[value]) {
blocks.insert(pair.first);
}
}
return blocks;
}
std::unordered_set<BasicBlock *> getUseBlocksByValue(Value *value) {
std::unordered_set<BasicBlock *> blocks;
if (value2UseBlocks.count(value) > 0) {
for (const auto &pair : value2UseBlocks[value]) {
blocks.insert(pair.first);
}
}
return blocks;
}
// 值定义/使用操作
void addValue2AllocBlocks(Value* value, BasicBlock* block) { value2AllocBlocks[value] = block; }
void addValue2DefBlocks(Value* value, BasicBlock* block) { ++value2DefBlocks[value][block]; }
void addValue2UseBlocks(Value* value, BasicBlock* block) { ++value2UseBlocks[value][block]; }
// 获取值定义/使用信息
std::unordered_map<Value *, BasicBlock *>& getValue2AllocBlocks() {
return value2AllocBlocks;
}
std::unordered_map<Value *, std::unordered_map<BasicBlock *, int>>& getValue2DefBlocks() {
return value2DefBlocks;
}
std::unordered_map<Value *, std::unordered_map<BasicBlock *, int>>& getValue2UseBlocks() {
return value2UseBlocks;
}
std::unordered_set<Value *> getValuesOfDefBlock() {
std::unordered_set<Value *> values;
for (const auto &pair : value2DefBlocks) {
values.insert(pair.first);
}
return values;
}
// 删除信息操作
void removeValue2AllocBlock(Value *value) { value2AllocBlocks.erase(value); }
bool removeValue2DefBlock(Value *value, BasicBlock *block) {
bool changed = false;
if (--value2DefBlocks[value][block] == 0) {
value2DefBlocks[value].erase(block);
if (value2DefBlocks[value].empty()) {
value2DefBlocks.erase(value);
changed = true;
}
}
return changed;
}
bool removeValue2UseBlock(Value *value, BasicBlock *block) {
bool changed = false;
if (--value2UseBlocks[value][block] == 0) {
value2UseBlocks[value].erase(block);
if (value2UseBlocks[value].empty()) {
value2UseBlocks.erase(value);
changed = true;
}
}
return changed;
}
// 间接分配操作
void addIndirectAlloca(AllocaInst* alloca) { indirectAllocas.emplace_back(alloca); }
std::list<std::unique_ptr<AllocaInst>>& getIndirectAllocas() { return indirectAllocas; }
// TODO循环分析操作
// 清空所有分析信息
void clear() {
attribute = PlaceHolder;
callees.clear();
loops.clear();
topLoops.clear();
// basicblock2Loop.clear();
indirectAllocas.clear();
value2AllocBlocks.clear();
value2DefBlocks.clear();
value2UseBlocks.clear();
}
};
// 循环类 - 未实现优化
class Loop {
public:
using block_list = std::vector<BasicBlock *>;
using block_set = std::unordered_set<BasicBlock *>;
using Loop_list = std::vector<Loop *>;
protected:
Function *parent; // 所属函数
block_list blocksInLoop; // 循环内的基本块
BasicBlock *preheaderBlock = nullptr; // 前驱块
BasicBlock *headerBlock = nullptr; // 循环头
block_list latchBlock; // 回边块
block_set exitingBlocks; // 退出块
block_set exitBlocks; // 退出目标块
Loop *parentloop = nullptr; // 父循环
Loop_list subLoops; // 子循环
size_t loopID; // 循环ID
unsigned loopDepth; // 循环深度
Instruction *indCondVar = nullptr; // 循环条件变量
Instruction::Kind IcmpKind; // 比较类型
Value *indEnd = nullptr; // 循环结束值
AllocaInst *IndPhi = nullptr; // 循环变量
ConstantValue *indBegin = nullptr; // 循环起始值
ConstantValue *indStep = nullptr; // 循环步长
std::set<GlobalValue *> GlobalValuechange; // 循环内改变的全局变量
int StepType = 0; // 循环步长类型
bool parallelable = false; // 是否可并行
public:
explicit Loop(BasicBlock *header, const std::string &name = "")
: headerBlock(header) {
blocksInLoop.push_back(header);
}
void setloopID() {
static unsigned loopCount = 0;
loopCount = loopCount + 1;
loopID = loopCount;
}
ConstantValue* getindBegin() { return indBegin; }
ConstantValue* getindStep() { return indStep; }
void setindBegin(ConstantValue *indBegin2set) { indBegin = indBegin2set; }
void setindStep(ConstantValue *indStep2set) { indStep = indStep2set; }
void setStepType(int StepType2Set) { StepType = StepType2Set; }
int getStepType() { return StepType; }
size_t getLoopID() { return loopID; }
BasicBlock* getHeader() const { return headerBlock; }
BasicBlock* getPreheaderBlock() const { return preheaderBlock; }
block_list& getLatchBlocks() { return latchBlock; }
block_set& getExitingBlocks() { return exitingBlocks; }
block_set& getExitBlocks() { return exitBlocks; }
Loop* getParentLoop() const { return parentloop; }
void setParentLoop(Loop *parent) { parentloop = parent; }
void addBasicBlock(BasicBlock *bb) { blocksInLoop.push_back(bb); }
void addSubLoop(Loop *loop) { subLoops.push_back(loop); }
void setLoopDepth(unsigned depth) { loopDepth = depth; }
block_list& getBasicBlocks() { return blocksInLoop; }
Loop_list& getSubLoops() { return subLoops; }
unsigned getLoopDepth() const { return loopDepth; }
bool isLoopContainsBasicBlock(BasicBlock *bb) const {
return std::find(blocksInLoop.begin(), blocksInLoop.end(), bb) != blocksInLoop.end();
}
void addExitingBlock(BasicBlock *bb) { exitingBlocks.insert(bb); }
void addExitBlock(BasicBlock *bb) { exitBlocks.insert(bb); }
void addLatchBlock(BasicBlock *bb) { latchBlock.push_back(bb); }
void setPreheaderBlock(BasicBlock *bb) { preheaderBlock = bb; }
void setIndexCondInstr(Instruction *instr) { indCondVar = instr; }
void setIcmpKind(Instruction::Kind kind) { IcmpKind = kind; }
Instruction::Kind getIcmpKind() const { return IcmpKind; }
bool isSimpleLoopInvariant(Value *value) ;
void setIndEnd(Value *value) { indEnd = value; }
void setIndPhi(AllocaInst *phi) { IndPhi = phi; }
Value* getIndEnd() const { return indEnd; }
AllocaInst* getIndPhi() const { return IndPhi; }
Instruction* getIndCondVar() const { return indCondVar; }
void addGlobalValuechange(GlobalValue *globalvaluechange2add) {
GlobalValuechange.insert(globalvaluechange2add);
}
std::set<GlobalValue *>& getGlobalValuechange() {
return GlobalValuechange;
}
void setParallelable(bool flag) { parallelable = flag; }
bool isParallelable() const { return parallelable; }
};
// 控制流分析类
class ControlFlowAnalysis {
private:
Module *pModule; ///< 模块
std::unordered_map<BasicBlock*, BlockAnalysisInfo*> blockAnalysisInfo; // 基本块分析信息表
std::unordered_map<Function*, FunctionAnalysisInfo*> functionAnalysisInfo; // 函数分析信息
public:
explicit ControlFlowAnalysis(Module *pMoudle) : pModule(pMoudle) {}
// 获取基本块分析信息
BlockAnalysisInfo* getBlockAnalysisInfo(BasicBlock *block) {
auto it = blockAnalysisInfo.find(block);
if (it != blockAnalysisInfo.end()) {
return it->second;
}
return nullptr; // 如果未找到返回nullptr
}
FunctionAnalysisInfo* getFunctionAnalysisInfo(Function *func) {
auto it = functionAnalysisInfo.find(func);
if (it != functionAnalysisInfo.end()) {
return it->second;
}
return nullptr; // 如果未找到返回nullptr
}
void init(); // 初始化分析器
void computeDomNode(); // 计算必经结点
void computeDomTree(); // 构造支配树
// std::unordered_set<BasicBlock *> computeDomFrontier(BasicBlock *block) ; // 计算单个块的支配边界(弃用)
void computeDomFrontierAllBlk(); // 计算所有块的支配边界
void runControlFlowAnalysis(); // 运行控制流分析(主要是支配树和支配边界)
void clear(){
for (auto &pair : blockAnalysisInfo) {
delete pair.second; // 清理基本块分析信息
}
blockAnalysisInfo.clear();
for (auto &pair : functionAnalysisInfo) {
delete pair.second; // 清理函数分析信息
}
functionAnalysisInfo.clear();
} // 清空分析结果
~ControlFlowAnalysis() {
clear(); // 析构时清理所有分析信息
}
private:
void intersectOP4Dom(std::unordered_set<BasicBlock *> &dom, const std::unordered_set<BasicBlock *> &other); // 交集运算,
BasicBlock* findCommonDominator(BasicBlock *a, BasicBlock *b); // 查找两个基本块的共同支配结点
};
// 数据流分析类
// 该类为抽象类,具体的数据流分析器需要继承此类
// 因为每个数据流分析器的分析动作都不一样所以需要继承并实现analyze方法
class DataFlowAnalysis {
public:
virtual ~DataFlowAnalysis() = default;
public:
virtual void init(Module *pModule) {} ///< 分析器初始化
virtual auto analyze(Module *pModule, BasicBlock *block) -> bool { return true; } ///< 分析动作若完成则返回true;
virtual void clear() {} ///< 清空
};
// 数据流分析工具类
// 该类用于管理多个数据流分析器,提供统一的前向与后向分析接口
class DataFlowAnalysisUtils {
private:
std::vector<DataFlowAnalysis *> forwardAnalysisList; ///< 前向分析器列表
std::vector<DataFlowAnalysis *> backwardAnalysisList; ///< 后向分析器列表
public:
DataFlowAnalysisUtils() = default;
~DataFlowAnalysisUtils() {
clear(); // 析构时清理所有分析器
}
// 统一添加接口
void addAnalyzers(
std::vector<DataFlowAnalysis *> forwardList,
std::vector<DataFlowAnalysis *> backwardList = {})
{
forwardAnalysisList.insert(
forwardAnalysisList.end(),
forwardList.begin(),
forwardList.end());
backwardAnalysisList.insert(
backwardAnalysisList.end(),
backwardList.begin(),
backwardList.end());
}
// 单独添加接口
void addForwardAnalyzer(DataFlowAnalysis *analyzer) {
forwardAnalysisList.push_back(analyzer);
}
void addBackwardAnalyzer(DataFlowAnalysis *analyzer) {
backwardAnalysisList.push_back(analyzer);
}
// 设置分析器列表
void setAnalyzers(
std::vector<DataFlowAnalysis *> forwardList,
std::vector<DataFlowAnalysis *> backwardList)
{
forwardAnalysisList = std::move(forwardList);
backwardAnalysisList = std::move(backwardList);
}
// 清空列表
void clear() {
forwardAnalysisList.clear();
backwardAnalysisList.clear();
}
// 访问器
const auto& getForwardAnalyzers() const { return forwardAnalysisList; }
const auto& getBackwardAnalyzers() const { return backwardAnalysisList; }
public:
void forwardAnalyze(Module *pModule); ///< 执行前向分析
void backwardAnalyze(Module *pModule); ///< 执行后向分析
};
// 活跃变量分析类
// 提供def - use分析
// 未兼容数组变量但是考虑了维度的use信息
class ActiveVarAnalysis : public DataFlowAnalysis {
private:
std::map<BasicBlock *, std::vector<std::set<User *>>> activeTable; ///< 活跃信息表,存储每个基本块内的的活跃变量信息
public:
ActiveVarAnalysis() = default;
~ActiveVarAnalysis() override = default;
public:
static std::set<User*> getUsedSet(Instruction *inst);
static User* getDefine(Instruction *inst);
public:
void init(Module *pModule) override;
bool analyze(Module *pModule, BasicBlock *block) override;
// 外部活跃信息表访问器
const std::map<BasicBlock *, std::vector<std::set<User *>>> &getActiveTable() const;
void clear() override {
activeTable.clear(); // 清空活跃信息表
}
};
// 分析管理器 后续实现
// class AnalysisManager {
// };
} // namespace sysy

View File

@ -1,37 +0,0 @@
#pragma once
#include "IR.h"
#include "IRBuilder.h"
namespace sysy {
// 优化前对SysY IR的预处理也可以视作部分CFG优化
// 主要包括删除无用指令、合并基本块、删除空块等
// 这些操作可以在SysY IR生成时就完成但为了简化IR生成过程
// 这里将其放在SysY IR生成后进行预处理
// 同时兼容phi节点的处理可以再mem2reg后再次调用优化
class SysYOptPre {
private:
Module *pModule;
IRBuilder *pBuilder;
public:
SysYOptPre(Module *pMoudle, IRBuilder *pBuilder) : pModule(pMoudle), pBuilder(pBuilder) {}
void SysYOptimizateAfterIR(){
SysYDelInstAfterBr();
SysYBlockMerge();
SysYDelNoPreBLock();
SysYDelEmptyBlock();
SysYAddReturn();
}
void SysYDelInstAfterBr(); // 删除br后面的指令
void SysYDelEmptyBlock(); // 空块删除
void SysYDelNoPreBLock(); // 删除无前驱块
void SysYBlockMerge(); // 合并基本块(主要针对嵌套if while的exit块
// 也可以修改IR生成实现回填机制
void SysYAddReturn(); // 添加return指令(主要针对Void函数)
void usedelete(Instruction *instr); // use删除
};
} // namespace sysy

View File

@ -0,0 +1,33 @@
#ifndef CALLEE_SAVED_HANDLER_H
#define CALLEE_SAVED_HANDLER_H
#include "RISCv64LLIR.h"
#include "Pass.h"
namespace sysy {
/**
* @class CalleeSavedHandler
* @brief 处理被调用者保存寄存器(Callee-Saved Registers)的Pass。
* * 这个Pass在寄存器分配之后运行。它的主要职责是
* 1. 扫描整个函数,找出所有被使用的 `s` 系列寄存器。
* 2. 在函数序言中插入 `sd` 指令来保存这些寄存器。
* 3. 在函数结尾ret指令前插入 `ld` 指令来恢复这些寄存器。
* 4. 正确计算因保存这些寄存器而需要的额外栈空间并更新StackFrameInfo。
*/
class CalleeSavedHandler : public Pass {
public:
static char ID;
CalleeSavedHandler() : Pass("callee-saved-handler", Granularity::Function, PassKind::Optimization) {}
void *getPassID() const override { return &ID; }
bool runOnFunction(Function *F, AnalysisManager& AM) override;
void runOnMachineFunction(MachineFunction* mfunc);
};
} // namespace sysy
#endif // CALLEE_SAVED_HANDLER_H

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,36 @@
#ifndef SYSY_LEGALIZE_IMMEDIATES_H
#define SYSY_LEGALIZE_IMMEDIATES_H
#include "RISCv64LLIR.h"
#include "Pass.h"
namespace sysy {
// MachineFunction 的前向声明在这里是可选的,因为 RISCv64LLIR.h 已经定义了它
// class MachineFunction;
/**
* @class LegalizeImmediatesPass
* @brief 一个用于“合法化”机器指令的Pass。
*
* 这个Pass的主要职责是遍历所有机器指令查找那些包含了超出
* 目标架构RISC-V编码范围的大立即数immediate的指令
* 并将它们展开成一个等价的、只包含合法立即数的指令序列。
*
* 它在指令选择之后、寄存器分配之前运行,确保进入后续阶段的
* 所有指令都符合硬件约束。
*/
class LegalizeImmediatesPass : public Pass {
public:
static char ID;
LegalizeImmediatesPass() : Pass("legalize-immediates", Granularity::Function, PassKind::Optimization) {}
void *getPassID() const override { return &ID; }
void runOnMachineFunction(MachineFunction* mfunc);
};
} // namespace sysy
#endif // SYSY_LEGALIZE_IMMEDIATES_H

View File

@ -0,0 +1,35 @@
#ifndef SYSY_PROLOGUE_EPILOGUE_INSERTION_H
#define SYSY_PROLOGUE_EPILOGUE_INSERTION_H
#include "RISCv64LLIR.h"
#include "Pass.h"
namespace sysy {
class MachineFunction;
/**
* @class PrologueEpilogueInsertionPass
* @brief 在函数中插入序言和尾声的机器指令。
*
* 这个Pass在所有栈帧大小计算完毕后包括局部变量、溢出槽、被调用者保存寄存器
* 在寄存器分配之后运行。它的职责是:
* 1. 根据 StackFrameInfo 中的最终栈大小,生成用于分配和释放栈帧的指令 (addi sp, sp, +/-size)。
* 2. 生成用于保存和恢复返回地址(ra)和旧帧指针(s0)的指令。
* 3. 将这些指令作为 MachineInstr 对象插入到 MachineFunction 的入口块和所有返回块中。
* 4. 这个Pass可能会生成带有大立即数的指令需要后续的 LegalizeImmediatesPass 来处理。
*/
class PrologueEpilogueInsertionPass : public Pass {
public:
static char ID;
PrologueEpilogueInsertionPass() : Pass("prologue-epilogue-insertion", Granularity::Function, PassKind::Optimization) {}
void *getPassID() const override { return &ID; }
void runOnMachineFunction(MachineFunction* mfunc);
};
} // namespace sysy
#endif // SYSY_PROLOGUE_EPILOGUE_INSERTION_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

@ -0,0 +1,30 @@
#ifndef RISCV64_PEEPHOLE_H
#define RISCV64_PEEPHOLE_H
#include "RISCv64LLIR.h"
#include "Pass.h"
namespace sysy {
/**
* @class PeepholeOptimizer
* @brief 窥孔优化器
* * 在已分配物理寄存器的指令流上,通过一个小的滑动窗口来查找
* 并替换掉一些冗余或低效的指令模式。
*/
class PeepholeOptimizer : public Pass {
public:
static char ID;
PeepholeOptimizer() : Pass("peephole-optimizer", 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_PEEPHOLE_H

View File

@ -0,0 +1,50 @@
#ifndef POST_RA_SCHEDULER_H
#define POST_RA_SCHEDULER_H
#include "RISCv64LLIR.h"
#include "Pass.h"
namespace sysy {
/**
* @class PostRA_Scheduler
* @brief 寄存器分配后的局部指令调度器
* * 主要目标是优化寄存器分配器插入的spill/fill代码(lw/sw)
* 尝试将加载指令提前,以隐藏其访存延迟。
*/
struct MemoryAccess {
PhysicalReg base_reg;
int64_t offset;
bool valid;
MemoryAccess() : valid(false) {}
MemoryAccess(PhysicalReg base, int64_t off) : base_reg(base), offset(off), valid(true) {}
};
struct InstrRegInfo {
std::unordered_set<PhysicalReg> defined_regs;
std::unordered_set<PhysicalReg> used_regs;
bool is_load;
bool is_store;
bool is_control_flow;
MemoryAccess mem_access;
InstrRegInfo() : is_load(false), is_store(false), is_control_flow(false) {}
};
class PostRA_Scheduler : public Pass {
public:
static char ID;
PostRA_Scheduler() : Pass("post-ra-scheduler", Granularity::Function, PassKind::Optimization) {}
void *getPassID() const override { return &ID; }
bool runOnFunction(Function *F, AnalysisManager& AM) override;
void runOnMachineFunction(MachineFunction* mfunc);
};
} // namespace sysy
#endif // POST_RA_SCHEDULER_H

View File

@ -0,0 +1,30 @@
#ifndef PRE_RA_SCHEDULER_H
#define PRE_RA_SCHEDULER_H
#include "RISCv64LLIR.h"
#include "Pass.h"
namespace sysy {
/**
* @class PreRA_Scheduler
* @brief 寄存器分配前的指令调度器
* * 在虚拟寄存器上进行操作,此时调度自由度最大,
* 主要目标是隐藏指令延迟,提高流水线效率。
*/
class PreRA_Scheduler : public Pass {
public:
static char ID;
PreRA_Scheduler() : Pass("pre-ra-scheduler", Granularity::Function, PassKind::Optimization) {}
void *getPassID() const override { return &ID; }
bool runOnFunction(Function *F, AnalysisManager& AM) override;
void runOnMachineFunction(MachineFunction* mfunc);
};
} // namespace sysy
#endif // PRE_RA_SCHEDULER_H

View File

@ -4,27 +4,33 @@
#include "RISCv64LLIR.h"
#include <iostream>
extern int DEBUG;
extern int DEEPDEBUG;
namespace sysy {
class RISCv64AsmPrinter {
public:
RISCv64AsmPrinter(MachineFunction* mfunc);
// 主入口
void run(std::ostream& os);
void run(std::ostream& os, bool debug = false);
void printInstruction(MachineInstr* instr, bool debug = false);
// 辅助函数
void setStream(std::ostream& os) { OS = &os; }
// 辅助函数
std::string regToString(PhysicalReg reg);
std::string formatInstr(const MachineInstr *instr);
private:
// 打印各个部分
void printPrologue();
void printEpilogue();
void printBasicBlock(MachineBasicBlock* mbb);
void printInstruction(MachineInstr* instr);
void printBasicBlock(MachineBasicBlock* mbb, bool debug = false);
// 辅助函数
std::string regToString(PhysicalReg reg);
void printOperand(MachineOperand* op);
MachineFunction* MFunc;
std::ostream* OS;
std::ostream* OS = nullptr;
};
} // namespace sysy

View File

@ -4,6 +4,9 @@
#include "IR.h"
#include <string>
extern int DEBUG;
extern int DEEPDEBUG;
namespace sysy {
// RISCv64CodeGen 现在是一个高层驱动器
@ -19,6 +22,9 @@ private:
// 函数级代码生成 (实现新的流水线)
std::string function_gen(Function* func);
// 私有辅助函数,用于根据类型计算其占用的字节数。
unsigned getTypeSizeInBytes(Type* type);
Module* module;
};

View File

@ -3,6 +3,15 @@
#include "RISCv64LLIR.h"
// Forward declarations
namespace sysy {
class GlobalValue;
class Value;
}
extern int DEBUG;
extern int DEEPDEBUG;
namespace sysy {
class RISCv64ISel {
@ -14,6 +23,12 @@ public:
// 公开接口以便后续模块如RegAlloc可以查询或创建vreg
unsigned getVReg(Value* val);
unsigned getNewVReg() { return vreg_counter++; }
unsigned getNewVReg(Type* type);
unsigned getVRegCounter() const;
// 获取 vreg_map 的公共接口
const std::map<Value*, unsigned>& getVRegMap() const { return vreg_map; }
const std::map<unsigned, Value*>& getVRegValueMap() const { return vreg_to_value_map; }
const std::map<unsigned, Type*>& getVRegTypeMap() const { return vreg_type_map; }
private:
// DAG节点定义作为ISel的内部实现细节
@ -30,6 +45,11 @@ private:
std::vector<std::unique_ptr<DAGNode>> build_dag(BasicBlock* bb);
DAGNode* get_operand_node(Value* val_ir, std::map<Value*, DAGNode*>&, std::vector<std::unique_ptr<DAGNode>>&);
DAGNode* create_node(int kind, Value* val, std::map<Value*, DAGNode*>&, std::vector<std::unique_ptr<DAGNode>>&);
// 用于计算类型大小的辅助函数
unsigned getTypeSizeInBytes(Type* type);
// 打印DAG图以供调试
void print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, const std::string& bb_name);
// 状态
Function* F; // 当前处理的高层IR函数
@ -38,6 +58,8 @@ private:
// 映射关系
std::map<Value*, unsigned> vreg_map;
std::map<unsigned, Value*> vreg_to_value_map;
std::map<unsigned, Type*> vreg_type_map;
std::map<const BasicBlock*, MachineBasicBlock*> bb_map;
unsigned vreg_counter;

View File

@ -3,6 +3,7 @@
#include "IR.h" // 确保包含了您自己的IR头文件
#include <string>
#include <iostream>
#include <vector>
#include <memory>
#include <cstdint>
@ -18,14 +19,34 @@ namespace sysy {
// 物理寄存器定义
enum class PhysicalReg {
ZERO, RA, SP, GP, TP, T0, T1, T2, S0, S1, A0, A1, A2, A3, A4, A5, A6, A7, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, T3, T4, T5, T6,
F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15,F16, F17, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31
// --- 特殊功能寄存器 ---
ZERO, RA, SP, GP, TP,
// --- 整数寄存器 (按调用约定分组) ---
// 临时寄存器 (调用者保存)
T0, T1, T2, T3, T4, T5, T6,
// 保存寄存器 (被调用者保存)
S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11,
// 参数/返回值寄存器 (调用者保存)
A0, A1, A2, A3, A4, A5, A6, A7,
// --- 浮点寄存器 ---
F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11,
F12, F13, F14, F15, F16, F17, F18, F19, F20, F21,
F22, F23, F24, F25, F26, F27, F28, F29, F30, F31,
// 用于内部表示物理寄存器在干扰图中的节点ID一个简单的特殊ID确保不与vreg_counter冲突
// 假设 vreg_counter 不会达到这么大的值
PHYS_REG_START_ID = 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,
// 移位指令
@ -43,11 +64,99 @@ enum class RVOpcodes {
CALL,
// 特殊标记,非指令
LABEL,
// 新增伪指令,用于解耦栈帧处理
FRAME_LOAD, // 从栈帧加载 (AllocaInst)
FRAME_STORE, // 保存到栈帧 (AllocaInst)
// 浮点指令 (RISC-V 'F' 扩展)
// 浮点加载与存储
FLW, // flw rd, offset(rs1)
FSW, // fsw rs2, offset(rs1)
FLD, // fld rd, offset(rs1)
FSD, // fsd rs2, offset(rs1)
// 浮点算术运算 (单精度)
FADD_S, // fadd.s rd, rs1, rs2
FSUB_S, // fsub.s rd, rs1, rs2
FMUL_S, // fmul.s rd, rs1, rs2
FDIV_S, // fdiv.s rd, rs1, rs2
// 浮点比较 (单精度)
FEQ_S, // feq.s rd, rs1, rs2 (结果写入整数寄存器rd)
FLT_S, // flt.s rd, rs1, rs2 (less than)
FLE_S, // fle.s rd, rs1, rs2 (less than or equal)
// 浮点转换
FCVT_S_W, // fcvt.s.w rd, rs1 (有符号整数 -> 单精度浮点)
FCVT_W_S, // fcvt.w.s rd, rs1 (单精度浮点 -> 有符号整数)
// 浮点传送/移动
FMV_S, // fmv.s rd, rs1 (浮点寄存器之间)
FMV_W_X, // fmv.w.x rd, rs1 (整数寄存器位模式 -> 浮点寄存器)
FMV_X_W, // fmv.x.w rd, rs1 (浮点寄存器位模式 -> 整数寄存器)
FNEG_S, // fneg.s rd, rs (浮点取负)
// 伪指令
FRAME_LOAD_W, // 从栈帧加载 32位 Word (对应 lw)
FRAME_LOAD_D, // 从栈帧加载 64位 Doubleword (对应 ld)
FRAME_STORE_W, // 保存 32位 Word 到栈帧 (对应 sw)
FRAME_STORE_D, // 保存 64位 Doubleword 到栈帧 (对应 sd)
FRAME_LOAD_F, // 从栈帧加载单精度浮点数
FRAME_STORE_F, // 将单精度浮点数存入栈帧
FRAME_ADDR, // 获取栈帧变量的地址
PSEUDO_KEEPALIVE, // 保持寄存器活跃,防止优化器删除
};
inline bool isGPR(PhysicalReg reg) {
return reg >= PhysicalReg::ZERO && reg <= PhysicalReg::T6;
}
// 判断一个物理寄存器是否是浮点寄存器 (FPR)
inline bool isFPR(PhysicalReg reg) {
return reg >= PhysicalReg::F0 && reg <= PhysicalReg::F31;
}
// 获取所有调用者保存的整数寄存器 (t0-t6, a0-a7)
inline const std::vector<PhysicalReg>& getCallerSavedIntRegs() {
static const std::vector<PhysicalReg> regs = {
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3,
PhysicalReg::T4, PhysicalReg::T5, PhysicalReg::T6,
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3,
PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7
};
return regs;
}
// 获取所有被调用者保存的整数寄存器 (s0-s11)
inline const std::vector<PhysicalReg>& getCalleeSavedIntRegs() {
static const std::vector<PhysicalReg> regs = {
PhysicalReg::S0, PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3,
PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11
};
return regs;
}
// 获取所有调用者保存的浮点寄存器 (ft0-ft11, fa0-fa7)
inline const std::vector<PhysicalReg>& getCallerSavedFpRegs() {
static const std::vector<PhysicalReg> regs = {
PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3,
PhysicalReg::F4, PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7,
PhysicalReg::F8, PhysicalReg::F9, PhysicalReg::F10, PhysicalReg::F11, // ft0-ft11 和 fa0-fa7 在标准ABI中重叠
PhysicalReg::F12, PhysicalReg::F13, PhysicalReg::F14, PhysicalReg::F15,
PhysicalReg::F16, PhysicalReg::F17
};
return regs;
}
// 获取所有被调用者保存的浮点寄存器 (fs0-fs11)
inline const std::vector<PhysicalReg>& getCalleeSavedFpRegs() {
static const std::vector<PhysicalReg> regs = {
PhysicalReg::F18, PhysicalReg::F19, PhysicalReg::F20, PhysicalReg::F21,
PhysicalReg::F22, PhysicalReg::F23, PhysicalReg::F24, PhysicalReg::F25,
PhysicalReg::F26, PhysicalReg::F27, PhysicalReg::F28, PhysicalReg::F29,
PhysicalReg::F30, PhysicalReg::F31
};
return regs;
}
class MachineOperand;
class RegOperand;
class ImmOperand;
@ -87,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;
@ -166,10 +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; // RegAlloc最终的分配结果
std::vector<PhysicalReg> callee_saved_regs_to_store; // 已排序的、需要存取的被调用者保存寄存器
};
// 机器函数
@ -183,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

@ -0,0 +1,20 @@
#ifndef RISCV64_PASSES_H
#define RISCV64_PASSES_H
#include "RISCv64LLIR.h"
#include "Peephole.h"
#include "PreRA_Scheduler.h"
#include "PostRA_Scheduler.h"
#include "CalleeSavedHandler.h"
#include "LegalizeImmediates.h"
#include "PrologueEpilogueInsertion.h"
#include "EliminateFrameIndices.h"
#include "Pass.h"
#include "DivStrengthReduction.h"
namespace sysy {
} // namespace sysy
#endif // RISCV64_PASSES_H

View File

@ -0,0 +1,122 @@
#ifndef RISCV64_REGALLOC_H
#define RISCV64_REGALLOC_H
#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 {
class RISCv64RegAlloc {
public:
RISCv64RegAlloc(MachineFunction* mfunc);
// 模块主入口
void run();
private:
// 类型定义与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 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();
MachineFunction* MFunc;
RISCv64ISel* ISel;
// --- 算法数据结构 ---
// 寄存器池
std::vector<PhysicalReg> allocable_int_regs;
std::vector<PhysicalReg> allocable_fp_regs;
int K_int; // 整数寄存器数量
int K_fp; // 浮点寄存器数量
// 节点集合
VRegSet precolored; // 预着色的节点 (物理寄存器)
VRegSet initial; // 初始的、所有待处理的虚拟寄存器节点
VRegSet simplifyWorklist;
VRegSet freezeWorklist;
VRegSet spillWorklist;
VRegSet spilledNodes;
VRegSet coalescedNodes;
VRegSet coloredNodes;
VRegStack selectStack;
// 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
#endif // RISCV64_REGALLOC_H

File diff suppressed because it is too large Load Diff

View File

@ -126,7 +126,7 @@ class IRBuilder {
UnaryInst * createFNotInst(Value *operand, const std::string &name = "") {
return createUnaryInst(Instruction::kFNot, Type::getIntType(), operand, name);
} ///< 创建浮点取非指令
UnaryInst * createIToFInst(Value *operand, const std::string &name = "") {
UnaryInst * createItoFInst(Value *operand, const std::string &name = "") {
return createUnaryInst(Instruction::kItoF, Type::getFloatType(), operand, name);
} ///< 创建整型转浮点指令
UnaryInst * createBitItoFInst(Value *operand, const std::string &name = "") {
@ -217,6 +217,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,12 +286,50 @@ 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;
} ///< 创建load指令
LaInst * createLaInst(Value *pointer, const std::vector<Value *> &indices = {}, const std::string &name = "") {
MemsetInst * createMemsetInst(Value *pointer, Value *begin, Value *size, Value *value, const std::string &name = "") {
auto inst = new MemsetInst(pointer, begin, size, value, block, name);
assert(inst);
block->getInstructions().emplace(position, inst);
return inst;
} ///< 创建memset指令
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;
} ///< 创建store指令
PhiInst * createPhiInst(Type *type, const std::vector<Value*> &vals = {}, const std::vector<BasicBlock*> &blks = {}, 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 PhiInst(type, vals, blks, block, newName);
assert(inst);
block->getInstructions().emplace(block->begin(), inst);
return inst;
} ///< 创建Phi指令
/**
* @brief LLVM GEP
*
*/
GetElementPtrInst *createGetElementPtrInst(Value *basePointer, const std::vector<Value *> &indices,
const std::string &name = "") {
Type *ResultElementType = getIndexedType(basePointer->getType(), indices);
if (!ResultElementType) {
assert(false && "Invalid GEP indexing!");
return nullptr;
}
Type *ResultType = PointerType::get(ResultElementType);
std::string newName;
if (name.empty()) {
std::stringstream ss;
@ -291,55 +340,50 @@ class IRBuilder {
newName = name;
}
auto inst = new LaInst(pointer, indices, block, newName);
auto inst = new GetElementPtrInst(ResultType, basePointer, indices, block, newName);
assert(inst);
block->getInstructions().emplace(position, inst);
return inst;
} ///< 创建la指令
GetSubArrayInst * createGetSubArray(LVal *fatherArray, const std::vector<Value *> &indices, const std::string &name = "") {
assert(fatherArray->getLValNumDims() > indices.size());
std::vector<Value *> subDims;
auto dims = fatherArray->getLValDims();
auto iter = std::next(dims.begin(), indices.size());
while (iter != dims.end()) {
subDims.emplace_back(*iter);
iter++;
}
static Type *getIndexedType(Type *pointerType, const std::vector<Value *> &indices) {
assert(pointerType->isPointer() && "base must be a pointer type!");
// GEP 的类型推断从基指针所指向的类型开始。
// 例如:
// - 如果 pointerType 是 `[20 x [10 x i32]]*``currentWalkType` 初始为 `[20 x [10 x i32]]`。
// - 如果 pointerType 是 `i32*``currentWalkType` 初始为 `i32`。
// - 如果 pointerType 是 `i32**``currentWalkType` 初始为 `i32*`。
Type *currentWalkType = pointerType->as<PointerType>()->getBaseType();
// 遍历所有索引来深入类型层次结构。
// 重要:第一个索引总是用于"解引用"指针,后续索引才用于数组/结构体的索引
for (int i = 0; i < indices.size(); ++i) {
if (i == 0) {
// 第一个索引:总是用于"解引用"基指针不改变currentWalkType
// 例如:对于 `[4 x i32]* ptr, i32 0`第一个0只是说"访问ptr指向的对象"
// currentWalkType 保持为 `[4 x i32]`
continue;
} else {
// 后续索引:用于实际的数组/结构体索引
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;
}
}
}
}
std::string childArrayName;
std::stringstream ss;
ss << "A"
<< "%" << tmpIndex;
childArrayName = ss.str();
tmpIndex++;
auto fatherArrayValue = dynamic_cast<Value *>(fatherArray);
auto childArray = new AllocaInst(fatherArrayValue->getType(), subDims, block, childArrayName);
auto inst = new GetSubArrayInst(fatherArray, childArray, indices, block, childArrayName);
assert(inst);
block->getInstructions().emplace(position, inst);
return inst;
} ///< 创建获取部分数组指令
MemsetInst * createMemsetInst(Value *pointer, Value *begin, Value *size, Value *value, const std::string &name = "") {
auto inst = new MemsetInst(pointer, begin, size, value, block, name);
assert(inst);
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);
assert(inst);
block->getInstructions().emplace(position, inst);
return inst;
} ///< 创建store指令
PhiInst * createPhiInst(Type *type, const std::vector<Value*> &vals = {}, const std::vector<BasicBlock*> &blks = {}, const std::string &name = "") {
auto predNum = block->getNumPredecessors();
auto inst = new PhiInst(type, vals, blks, block, name);
assert(inst);
block->getInstructions().emplace(block->begin(), inst);
return inst;
} ///< 创建Phi指令
// 所有索引处理完毕后,`currentWalkType` 就是 GEP 指令最终计算出的地址所指向的元素的类型。
return currentWalkType;
}
};
} // namespace sysy

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

@ -0,0 +1,107 @@
#pragma once
#include "Pass.h" // 包含 Pass 框架
#include "IR.h" // 包含 IR 定义
#include <map>
#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;
// 获取指定基本块的即时支配者 (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);
// 计算所有基本块的即时支配者(内部使用 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; // 支配树中每个基本块的子节点
// ==========================================================
// 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);
};
// 支配树分析遍
class DominatorTreeAnalysisPass : public AnalysisPass {
public:
// 唯一的 Pass ID
static void *ID;
DominatorTreeAnalysisPass() : AnalysisPass("DominatorTreeAnalysis", Pass::Granularity::Function) {}
// 实现 getPassID
void* getPassID() const override { return &ID; }
bool runOnFunction(Function* F, AnalysisManager &AM) override;
std::unique_ptr<AnalysisResultBase> getResult() override;
private:
std::unique_ptr<DominatorTree> CurrentDominatorTree;
};
} // namespace sysy

View File

@ -0,0 +1,72 @@
#pragma once
#include "IR.h" // 包含 IR 定义
#include "Pass.h" // 包含 Pass 框架
#include <algorithm> // for std::set_union, std::set_difference
#include <map>
#include <set>
#include <vector>
namespace sysy {
// 前向声明
class Function;
class BasicBlock;
class Value;
class Instruction;
// 活跃变量分析结果类
// 它将包含 LiveIn 和 LiveOut 集合
class LivenessAnalysisResult : public AnalysisResultBase {
public:
LivenessAnalysisResult(Function *F) : AssociatedFunction(F) {}
// 获取给定基本块的 LiveIn 集合
const std::set<Value *> *getLiveIn(BasicBlock *BB) const;
// 获取给定基本块的 LiveOut 集合
const std::set<Value *> *getLiveOut(BasicBlock *BB) const;
// 暴露内部数据结构,如果需要更直接的访问
const std::map<BasicBlock *, std::set<Value *>> &getLiveInSets() const { return liveInSets; }
const std::map<BasicBlock *, std::set<Value *>> &getLiveOutSets() const { return liveOutSets; }
// 核心计算方法,由 LivenessAnalysisPass 调用
void computeLiveness(Function *F);
private:
Function *AssociatedFunction; // 这个活跃变量分析是为哪个函数计算的
std::map<BasicBlock *, std::set<Value *>> liveInSets;
std::map<BasicBlock *, std::set<Value *>> liveOutSets;
// 辅助函数:计算基本块的 Def 和 Use 集合
// Def: 块内定义,且定义在所有使用之前的值
// Use: 块内使用,且使用在所有定义之前的值
void computeDefUse(BasicBlock *BB, std::set<Value *> &def, std::set<Value *> &use);
};
// 活跃变量分析遍
class LivenessAnalysisPass : public AnalysisPass {
public:
// 唯一的 Pass ID
static void *ID; // LLVM 风格的唯一 ID
LivenessAnalysisPass() : AnalysisPass("LivenessAnalysis", Pass::Granularity::Function) {}
// 实现 getPassID
void *getPassID() const override { return &ID; }
// 运行分析并返回结果。现在接受 AnalysisManager& AM 参数
bool runOnFunction(Function *F, AnalysisManager &AM) override;
// 获取分析结果的指针。
// 注意AnalysisManager 将会调用此方法来获取结果并进行缓存。
std::unique_ptr<AnalysisResultBase> getResult() override;
private:
// 存储当前分析计算出的 LivenessAnalysisResult 实例
// runOnFunction 每次调用都会创建新的 LivenessAnalysisResult 对象
std::unique_ptr<LivenessAnalysisResult> CurrentLivenessResult;
};
} // namespace sysy

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,360 @@
#pragma once
#include "Dom.h" // 支配树分析依赖
#include "Loop.h" // 循环分析依赖
#include "Liveness.h" // 活跃性分析依赖
#include "AliasAnalysis.h" // 别名分析依赖
#include "SideEffectAnalysis.h" // 副作用分析依赖
#include "CallGraphAnalysis.h" // 调用图分析依赖
#include "IR.h" // IR定义
#include "Pass.h" // Pass框架
#include <algorithm>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <vector>
namespace sysy {
// 前向声明
class LoopCharacteristicsResult;
enum IVKind {
kBasic, // 基本归纳变量
kLinear, // 线性归纳变量
kCmplx // 复杂派生归纳变量
} ; // 归纳变量类型
struct InductionVarInfo {
Value* div; // 派生归纳变量的指令
Value* base = nullptr; // 其根phi或BIV或DIV
std::pair<Value*, Value*> Multibase = {nullptr, nullptr}; // 多个BIV
Instruction::Kind Instkind; // 操作类型
int factor = 1; // 系数如i*2+3的2
int offset = 0; // 常量偏移
bool valid; // 是否线性可归约
IVKind ivkind; // 归纳变量类型
static std::unique_ptr<InductionVarInfo> createBasicBIV(Value* v, Instruction::Kind kind, Value* base = nullptr, int factor = 1, int offset = 0) {
return std::make_unique<InductionVarInfo>(
InductionVarInfo{v, base, {nullptr, nullptr}, kind, factor, offset, true, IVKind::kBasic}
);
}
static std::unique_ptr<InductionVarInfo> createSingleDIV(Value* v, Instruction::Kind kind, Value* base = nullptr, int factor = 1, int offset = 0) {
return std::make_unique<InductionVarInfo>(
InductionVarInfo{v, base, {nullptr, nullptr}, kind, factor, offset, true, IVKind::kLinear}
);
}
static std::unique_ptr<InductionVarInfo> createDoubleDIV(Value* v, Instruction::Kind kind, Value* base1 = nullptr, Value* base2 = nullptr, int factor = 1, int offset = 0) {
return std::make_unique<InductionVarInfo>(
InductionVarInfo{v, nullptr, {base1, base2}, kind, factor, offset, false, IVKind::kCmplx}
);
}
};
/**
* @brief 循环特征信息结构 - 基础循环分析阶段
* 存储循环的基本特征信息,为后续精确分析提供基础
*/
struct LoopCharacteristics {
Loop* loop; // 关联的循环对象
// ========== 基础循环形式分析 ==========
bool isCountingLoop; // 是否为计数循环 (for i=0; i<n; i++)
bool isSimpleForLoop; // 是否为简单for循环
bool hasComplexControlFlow; // 是否有复杂控制流 (break, continue)
bool isInnermost; // 是否为最内层循环
// ========== 归纳变量分析 ==========
// ========== 基础循环不变量分析 ==========
std::unordered_set<Value*> loopInvariants; // 循环不变量
std::unordered_set<Instruction*> invariantInsts; // 可提升的不变指令
std::vector<std::unique_ptr<InductionVarInfo>> InductionVars; // 归纳变量
// ========== 基础边界分析 ==========
std::optional<int> staticTripCount; // 静态循环次数(如果可确定)
bool hasKnownBounds; // 是否有已知边界
// ========== 基础纯度和副作用分析 ==========
bool isPure; // 是否为纯循环(无副作用)
bool accessesOnlyLocalMemory; // 是否只访问局部内存
bool hasNoMemoryAliasConflicts; // 是否无内存别名冲突
// ========== 基础内存访问模式分析 ==========
struct MemoryAccessPattern {
std::vector<Instruction*> loadInsts; // load指令列表
std::vector<Instruction*> storeInsts; // store指令列表
bool isArrayParameter; // 是否为数组参数访问
bool isGlobalArray; // 是否为全局数组访问
bool hasConstantIndices; // 是否使用常量索引
};
std::map<Value*, MemoryAccessPattern> memoryPatterns; // 内存访问模式
// ========== 基础性能特征 ==========
size_t instructionCount; // 循环体指令数
size_t memoryOperationCount; // 内存操作数
size_t arithmeticOperationCount; // 算术操作数
double computeToMemoryRatio; // 计算与内存操作比率
// ========== 基础优化提示 ==========
bool benefitsFromUnrolling; // 是否适合循环展开
int suggestedUnrollFactor; // 建议的展开因子
// 构造函数 - 简化的基础分析初始化
LoopCharacteristics(Loop* l) : loop(l),
isCountingLoop(false), isSimpleForLoop(false), hasComplexControlFlow(false),
isInnermost(false), hasKnownBounds(false), isPure(false),
accessesOnlyLocalMemory(false), hasNoMemoryAliasConflicts(false),
benefitsFromUnrolling(false), suggestedUnrollFactor(1),
instructionCount(0), memoryOperationCount(0),
arithmeticOperationCount(0), computeToMemoryRatio(0.0) {}
};
/**
* @brief 循环特征分析结果类
* 包含函数中所有循环的特征信息,并提供查询接口
*/
class LoopCharacteristicsResult : public AnalysisResultBase {
public:
LoopCharacteristicsResult(Function *F) : AssociatedFunction(F) {}
~LoopCharacteristicsResult() override = default;
// ========== 基础接口 ==========
/**
* 添加循环特征信息
*/
void addLoopCharacteristics(std::unique_ptr<LoopCharacteristics> characteristics) {
auto* loop = characteristics->loop;
CharacteristicsMap[loop] = std::move(characteristics);
}
/**
* 获取指定循环的特征信息
*/
const LoopCharacteristics* getCharacteristics(Loop* loop) const {
auto it = CharacteristicsMap.find(loop);
return (it != CharacteristicsMap.end()) ? it->second.get() : nullptr;
}
/**
* 获取所有循环特征信息
*/
const std::map<Loop*, std::unique_ptr<LoopCharacteristics>>& getAllCharacteristics() const {
return CharacteristicsMap;
}
// ========== 核心查询接口 ==========
/**
* 获取所有计数循环
*/
std::vector<Loop*> getCountingLoops() const {
std::vector<Loop*> result;
for (const auto& [loop, chars] : CharacteristicsMap) {
if (chars->isCountingLoop) {
result.push_back(loop);
}
}
return result;
}
/**
* 获取所有纯循环(无副作用)
*/
std::vector<Loop*> getPureLoops() const {
std::vector<Loop*> result;
for (const auto& [loop, chars] : CharacteristicsMap) {
if (chars->isPure) {
result.push_back(loop);
}
}
return result;
}
/**
* 获取所有只访问局部内存的循环
*/
std::vector<Loop*> getLocalMemoryOnlyLoops() const {
std::vector<Loop*> result;
for (const auto& [loop, chars] : CharacteristicsMap) {
if (chars->accessesOnlyLocalMemory) {
result.push_back(loop);
}
}
return result;
}
/**
* 获取所有无内存别名冲突的循环
*/
std::vector<Loop*> getNoAliasConflictLoops() const {
std::vector<Loop*> result;
for (const auto& [loop, chars] : CharacteristicsMap) {
if (chars->hasNoMemoryAliasConflicts) {
result.push_back(loop);
}
}
return result;
}
/**
* 获取所有适合展开的循环
*/
std::vector<Loop*> getUnrollingCandidates() const {
std::vector<Loop*> result;
for (const auto& [loop, chars] : CharacteristicsMap) {
if (chars->benefitsFromUnrolling) {
result.push_back(loop);
}
}
return result;
}
/**
* 根据热度排序循环 (用于优化优先级)
*/
std::vector<Loop*> getLoopsByHotness() const {
std::vector<Loop*> result;
for (const auto& [loop, chars] : CharacteristicsMap) {
result.push_back(loop);
}
// 按循环热度排序 (嵌套深度 + 循环次数 + 指令数)
std::sort(result.begin(), result.end(), [](Loop* a, Loop* b) {
double hotnessA = a->getLoopHotness();
double hotnessB = b->getLoopHotness();
return hotnessA > hotnessB; // 降序排列
});
return result;
}
// ========== 基础统计接口 ==========
/**
* 获取基础优化统计信息
*/
struct BasicOptimizationStats {
size_t totalLoops;
size_t countingLoops;
size_t unrollingCandidates;
size_t pureLoops;
size_t localMemoryOnlyLoops;
size_t noAliasConflictLoops;
double avgInstructionCount;
double avgComputeMemoryRatio;
};
BasicOptimizationStats getOptimizationStats() const {
BasicOptimizationStats stats = {};
stats.totalLoops = CharacteristicsMap.size();
size_t totalInstructions = 0;
double totalComputeMemoryRatio = 0.0;
for (const auto& [loop, chars] : CharacteristicsMap) {
if (chars->isCountingLoop) stats.countingLoops++;
if (chars->benefitsFromUnrolling) stats.unrollingCandidates++;
if (chars->isPure) stats.pureLoops++;
if (chars->accessesOnlyLocalMemory) stats.localMemoryOnlyLoops++;
if (chars->hasNoMemoryAliasConflicts) stats.noAliasConflictLoops++;
totalInstructions += chars->instructionCount;
totalComputeMemoryRatio += chars->computeToMemoryRatio;
}
if (stats.totalLoops > 0) {
stats.avgInstructionCount = static_cast<double>(totalInstructions) / stats.totalLoops;
stats.avgComputeMemoryRatio = totalComputeMemoryRatio / stats.totalLoops;
}
return stats;
}
// 打印分析结果
void print() const;
private:
Function *AssociatedFunction; // 关联的函数
std::map<Loop*, std::unique_ptr<LoopCharacteristics>> CharacteristicsMap; // 循环特征映射
};
/**
* @brief 基础循环特征分析遍
* 在循环规范化前执行,进行基础的循环特征分析,为后续精确分析提供基础
*/
class LoopCharacteristicsPass : public AnalysisPass {
public:
// 唯一的 Pass ID
static void *ID;
LoopCharacteristicsPass() : AnalysisPass("LoopCharacteristics", Pass::Granularity::Function) {}
// 实现 getPassID
void *getPassID() const override { return &ID; }
// 核心运行方法
bool runOnFunction(Function *F, AnalysisManager &AM) override;
// 获取分析结果
std::unique_ptr<AnalysisResultBase> getResult() override { return std::move(CurrentResult); }
private:
std::unique_ptr<LoopCharacteristicsResult> CurrentResult;
// ========== 缓存的分析结果 ==========
LoopAnalysisResult* loopAnalysis; // 循环结构分析结果
AliasAnalysisResult* aliasAnalysis; // 别名分析结果
SideEffectAnalysisResult* sideEffectAnalysis; // 副作用分析结果
// ========== 核心分析方法 ==========
void analyzeLoop(Loop* loop, LoopCharacteristics* characteristics);
// 基础循环形式分析
void analyzeLoopForm(Loop* loop, LoopCharacteristics* characteristics);
// 基础性能指标计算
void computePerformanceMetrics(Loop* loop, LoopCharacteristics* characteristics);
// 基础纯度和副作用分析
void analyzePurityAndSideEffects(Loop* loop, LoopCharacteristics* characteristics);
// 基础归纳变量识别
void identifyBasicInductionVariables(Loop* loop, LoopCharacteristics* characteristics);
// 循环不变量识别
void identifyBasicLoopInvariants(Loop* loop, LoopCharacteristics* characteristics);
// 基础边界分析
void analyzeBasicLoopBounds(Loop* loop, LoopCharacteristics* characteristics);
// 基础内存访问模式分析
void analyzeBasicMemoryAccessPatterns(Loop* loop, LoopCharacteristics* characteristics);
// 基础优化评估
void evaluateBasicOptimizationOpportunities(Loop* loop, LoopCharacteristics* characteristics);
// ========== 辅助方法 ==========
bool isClassicLoopInvariant(Value* val, Loop* loop, const std::unordered_set<Value*>& invariants);
void findDerivedInductionVars(Value* root,
Value* base, // 只传单一BIV base
Loop* loop,
std::vector<std::unique_ptr<InductionVarInfo>>& ivs,
std::set<Value*>& visited
);
bool isBasicInductionVariable(Value* val, Loop* loop);
// ========== 循环不变量分析辅助方法 ==========
bool isInvariantOperands(Instruction* inst, Loop* loop, const std::unordered_set<Value*>& invariants);
bool isMemoryLocationModifiedInLoop(Value* ptr, Loop* loop);
bool isMemoryLocationLoadedInLoop(Value* ptr, Loop* loop, Instruction* excludeInst = nullptr);
bool isPureFunction(Function* calledFunc);
};
} // namespace sysy

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

@ -0,0 +1,72 @@
#pragma once
#include "Pass.h"
#include "IR.h"
#include "SysYIROptUtils.h"
#include "Dom.h"
#include "AliasAnalysis.h"
#include "SideEffectAnalysis.h"
#include <unordered_set>
#include <queue>
namespace sysy {
// 前向声明分析结果类,确保在需要时可以引用
// class DominatorTreeAnalysisResult; // Pass.h 中已包含,这里不再需要
class SideEffectInfoAnalysisResult; // 假设有副作用分析结果类
// DCEContext 类用于封装DCE的内部逻辑和状态
// 这样可以避免静态变量在多线程或多次运行时的冲突,并保持代码的模块化
class DCEContext {
public:
// 运行DCE的主要方法
// func: 当前要优化的函数
// tp: 分析管理器,用于获取其他分析结果(如果需要)
void run(Function* func, AnalysisManager* AM, bool &changed);
private:
// 存储活跃指令的集合
std::unordered_set<Instruction*> alive_insts;
// 别名分析结果
AliasAnalysisResult* aliasAnalysis = nullptr;
// 副作用分析结果
SideEffectAnalysisResult* sideEffectAnalysis = nullptr;
// 判断指令是否是"天然活跃"的(即总是保留的)
// inst: 要检查的指令
// 返回值: 如果指令是天然活跃的则为true否则为false
bool isAlive(Instruction* inst);
// 递归地将活跃指令及其依赖加入到 alive_insts 集合中
// inst: 要标记为活跃的指令
void addAlive(Instruction* inst);
// 检查Store指令是否可能有副作用通过别名分析
bool mayHaveSideEffect(StoreInst* store);
};
// DCE 优化遍类,继承自 OptimizationPass
class DCE : public OptimizationPass {
public:
// 构造函数
DCE() : OptimizationPass("DCE", Granularity::Function) {}
// 静态成员作为该遍的唯一ID
static void *ID;
// 运行在函数上的优化逻辑
// F: 当前要优化的函数
// AM: 分析管理器,用于获取或使分析结果失效
// 返回值: 如果IR被修改则为true否则为false
bool runOnFunction(Function *F, AnalysisManager& AM) override;
// 声明该遍的分析依赖和失效信息
// analysisDependencies: 该遍运行前需要哪些分析结果
// analysisInvalidations: 该遍运行后会使哪些分析结果失效
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override;
// Pass 基类中的纯虚函数,必须实现
void *getPassID() const override { return &ID; }
};
} // namespace sysy

View File

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

View File

@ -0,0 +1,252 @@
#pragma once
#include "Pass.h"
#include "IR.h"
#include "LoopCharacteristics.h"
#include "Loop.h"
#include "Dom.h"
#include "SideEffectAnalysis.h"
#include "AliasAnalysis.h"
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <memory>
namespace sysy {
// 前向声明
class LoopCharacteristicsResult;
class LoopAnalysisResult;
/**
* @brief 死归纳变量信息
* 记录一个可以被消除的归纳变量
*/
struct DeadInductionVariable {
PhiInst* phiInst; // phi 指令
std::vector<Instruction*> relatedInsts; // 相关的递增/递减指令
Loop* containingLoop; // 所在循环
bool canEliminate; // 是否可以安全消除
DeadInductionVariable(PhiInst* phi, Loop* loop)
: phiInst(phi), containingLoop(loop), canEliminate(false) {}
};
/**
* @brief 归纳变量消除上下文类
* 封装归纳变量消除优化的核心逻辑和状态
*/
class InductionVariableEliminationContext {
public:
InductionVariableEliminationContext() {}
/**
* 运行归纳变量消除优化
* @param F 目标函数
* @param AM 分析管理器
* @return 是否修改了IR
*/
bool run(Function* F, AnalysisManager& AM);
private:
// 分析结果缓存
LoopAnalysisResult* loopAnalysis = nullptr;
LoopCharacteristicsResult* loopCharacteristics = nullptr;
DominatorTree* dominatorTree = nullptr;
SideEffectAnalysisResult* sideEffectAnalysis = nullptr;
AliasAnalysisResult* aliasAnalysis = nullptr;
// 死归纳变量存储
std::vector<std::unique_ptr<DeadInductionVariable>> deadIVs;
std::unordered_map<Loop*, std::vector<DeadInductionVariable*>> loopToDeadIVs;
// ========== 核心分析和优化阶段 ==========
/**
* 阶段1识别死归纳变量
* 找出没有被有效使用的归纳变量
*/
void identifyDeadInductionVariables(Function* F);
/**
* 阶段2分析消除的安全性
* 确保消除操作不会破坏程序语义
*/
void analyzeSafetyForElimination();
/**
* 阶段3执行归纳变量消除
* 删除死归纳变量及其相关指令
*/
bool performInductionVariableElimination();
// ========== 辅助方法 ==========
/**
* 检查归纳变量是否为死归纳变量
* @param iv 归纳变量信息
* @param loop 所在循环
* @return 如果是死归纳变量返回相关信息否则返回nullptr
*/
std::unique_ptr<DeadInductionVariable>
isDeadInductionVariable(const InductionVarInfo* iv, Loop* loop);
/**
* 递归分析phi指令及其使用链是否都是死代码
* @param phiInst phi指令
* @param loop 所在循环
* @return phi指令是否可以安全删除
*/
bool isPhiInstructionDeadRecursively(PhiInst* phiInst, Loop* loop);
/**
* 递归分析指令的使用链是否都是死代码
* @param inst 要分析的指令
* @param loop 所在循环
* @param visited 已访问的指令集合(避免无限递归)
* @param currentPath 当前递归路径(检测循环依赖)
* @return 指令的使用链是否都是死代码
*/
bool isInstructionUseChainDeadRecursively(Instruction* inst, Loop* loop,
std::set<Instruction*>& visited,
std::set<Instruction*>& currentPath);
/**
* 检查循环是否有副作用
* @param loop 要检查的循环
* @return 循环是否有副作用
*/
bool loopHasSideEffects(Loop* loop);
/**
* 检查指令是否被用于循环退出条件
* @param inst 要检查的指令
* @param loop 所在循环
* @return 是否被用于循环退出条件
*/
bool isUsedInLoopExitCondition(Instruction* inst, Loop* loop);
/**
* 检查指令的结果是否未被有效使用
* @param inst 要检查的指令
* @param loop 所在循环
* @return 指令结果是否未被有效使用
*/
bool isInstructionResultUnused(Instruction* inst, Loop* loop);
/**
* 检查store指令是否存储到死地址利用别名分析
* @param store store指令
* @param loop 所在循环
* @return 是否存储到死地址
*/
bool isStoreToDeadLocation(StoreInst* store, Loop* loop);
/**
* 检查指令是否为死代码或只在循环内部使用
* @param inst 要检查的指令
* @param loop 所在循环
* @return 是否为死代码或只在循环内部使用
*/
bool isInstructionDeadOrInternalOnly(Instruction* inst, Loop* loop);
/**
* 检查指令是否有效地为死代码(带递归深度限制)
* @param inst 要检查的指令
* @param loop 所在循环
* @param maxDepth 最大递归深度
* @return 指令是否有效地为死代码
*/
bool isInstructionEffectivelyDead(Instruction* inst, Loop* loop, int maxDepth);
/**
* 检查store指令是否有后续的load操作
* @param store store指令
* @param loop 所在循环
* @return 是否有后续的load操作
*/
bool hasSubsequentLoad(StoreInst* store, Loop* loop);
/**
* 检查指令是否在循环外有使用
* @param inst 要检查的指令
* @param loop 所在循环
* @return 是否在循环外有使用
*/
bool hasUsageOutsideLoop(Instruction* inst, Loop* loop);
/**
* 检查store指令是否在循环外有后续的load操作
* @param store store指令
* @param loop 所在循环
* @return 是否在循环外有后续的load操作
*/
bool hasSubsequentLoadOutsideLoop(StoreInst* store, Loop* loop);
/**
* 递归检查基本块子树中是否有对指定位置的load操作
* @param bb 基本块
* @param ptr 指针
* @param visited 已访问的基本块集合
* @return 是否有load操作
*/
bool hasLoadInSubtree(BasicBlock* bb, Value* ptr, std::set<BasicBlock*>& visited);
/**
* 收集与归纳变量相关的所有指令
* @param phiInst phi指令
* @param loop 所在循环
* @return 相关指令列表
*/
std::vector<Instruction*> collectRelatedInstructions(PhiInst* phiInst, Loop* loop);
/**
* 检查消除归纳变量的安全性
* @param deadIV 死归纳变量
* @return 是否可以安全消除
*/
bool isSafeToEliminate(const DeadInductionVariable* deadIV);
/**
* 消除单个死归纳变量
* @param deadIV 死归纳变量
* @return 是否成功消除
*/
bool eliminateDeadInductionVariable(DeadInductionVariable* deadIV);
/**
* 打印调试信息
*/
void printDebugInfo();
};
/**
* @brief 归纳变量消除优化遍
* 消除循环中无用的归纳变量,减少寄存器压力
*/
class InductionVariableElimination : public OptimizationPass {
public:
// 唯一的 Pass ID
static void *ID;
InductionVariableElimination()
: OptimizationPass("InductionVariableElimination", Granularity::Function) {}
/**
* 在函数上运行归纳变量消除优化
* @param F 目标函数
* @param AM 分析管理器
* @return 是否修改了IR
*/
bool runOnFunction(Function* F, AnalysisManager& AM) override;
/**
* 声明分析依赖和失效信息
*/
void getAnalysisUsage(std::set<void*>& analysisDependencies,
std::set<void*>& analysisInvalidations) const override;
void* getPassID() const override { return &ID; }
};
} // namespace sysy

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

@ -0,0 +1,114 @@
#pragma once
#include "Pass.h" // 包含Pass的基类定义
#include "IR.h" // 包含IR相关的定义如Instruction, Function, BasicBlock, AllocaInst, LoadInst, StoreInst, PhiInst等
#include "Dom.h" // 假设支配树分析的头文件,提供 DominatorTreeAnalysisResult
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <queue>
#include <stack> // 用于变量重命名阶段的SSA值栈
namespace sysy {
// 前向声明分析结果类,确保在需要时可以引用
class DominatorTree;
// Mem2RegContext 类,封装 mem2reg 遍的核心逻辑和状态
// 这样可以避免静态变量在多线程或多次运行时的冲突,并保持代码的模块化
class Mem2RegContext {
public:
Mem2RegContext(IRBuilder *builder) : builder(builder) {}
// 运行 mem2reg 优化的主要方法
// func: 当前要优化的函数
// tp: 分析管理器,用于获取支配树等分析结果
void run(Function* func, AnalysisManager* tp);
private:
IRBuilder *builder; // IR 构建器,用于插入指令
// 存储所有需要被提升的 AllocaInst
std::vector<AllocaInst*> promotableAllocas;
// 存储每个 AllocaInst 对应的 Phi 指令列表
// 键是 AllocaInst值是该 AllocaInst 在各个基本块中插入的 Phi 指令的列表
// (实际上,一个 AllocaInst 在一个基本块中只会有一个 Phi)
std::unordered_map<AllocaInst*, std::unordered_map<BasicBlock*, PhiInst*>> allocaToPhiMap;
// 存储每个 AllocaInst 对应的当前活跃 SSA 值栈
// 用于在变量重命名阶段追踪每个 AllocaInst 在不同控制流路径上的最新值
std::unordered_map<AllocaInst*, std::stack<Value*>> allocaToValueStackMap;
// 辅助映射,存储每个 AllocaInst 的所有 store 指令
std::unordered_map<AllocaInst*, std::unordered_set<StoreInst*>> allocaToStoresMap;
// 辅助映射,存储每个 AllocaInst 对应的定义基本块(包含 store 指令的块)
std::unordered_map<AllocaInst*, std::unordered_set<BasicBlock*>> allocaToDefBlocksMap;
// 支配树分析结果,用于 Phi 插入和变量重命名
DominatorTree* dt;
// --------------------------------------------------------------------
// 阶段1: 识别可提升的 AllocaInst
// --------------------------------------------------------------------
// 判断一个 AllocaInst 是否可以被提升到寄存器
// alloca: 要检查的 AllocaInst
// 返回值: 如果可以提升,则为 true否则为 false
bool isPromotableAlloca(AllocaInst* alloca);
// 收集所有对给定 AllocaInst 进行存储的 StoreInst
// alloca: 目标 AllocaInst
void collectStores(AllocaInst* alloca);
// --------------------------------------------------------------------
// 阶段2: 插入 Phi 指令 (Phi Insertion)
// --------------------------------------------------------------------
// 为给定的 AllocaInst 插入必要的 Phi 指令
// alloca: 目标 AllocaInst
// defBlocks: 包含对该 AllocaInst 进行 store 操作的基本块集合
void insertPhis(AllocaInst* alloca, const std::unordered_set<BasicBlock*>& defBlocks);
// --------------------------------------------------------------------
// 阶段3: 变量重命名 (Variable Renaming)
// --------------------------------------------------------------------
// 对支配树进行深度优先遍历,重命名变量并替换 load/store 指令
void renameVariables(BasicBlock* currentBB);
// --------------------------------------------------------------------
// 阶段4: 清理
// --------------------------------------------------------------------
// 删除所有原始的 AllocaInst、LoadInst 和 StoreInst
void cleanup();
};
// Mem2Reg 优化遍类,继承自 OptimizationPass
// 粒度为 Function表示它在每个函数上独立运行
class Mem2Reg : public OptimizationPass {
private:
IRBuilder *builder;
public:
// 构造函数
Mem2Reg(IRBuilder *builder) : OptimizationPass("Mem2Reg", Granularity::Function), builder(builder) {}
// 静态成员作为该遍的唯一ID
static void *ID;
// 运行在函数上的优化逻辑
// F: 当前要优化的函数
// AM: 分析管理器,用于获取支配树等分析结果,或使分析结果失效
// 返回值: 如果IR被修改则为true否则为false
bool runOnFunction(Function *F, AnalysisManager& AM) override;
// 声明该遍的分析依赖和失效信息
// analysisDependencies: 该遍运行前需要哪些分析结果
// analysisInvalidations: 该遍运行后会使哪些分析结果失效
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,59 @@
#pragma once
#include "IR.h"
#include "IRBuilder.h" // 你的 IR Builder
#include "Liveness.h"
#include "Dom.h"
#include "Pass.h" // 你的 Pass 框架基类
#include <iostream> // 调试用
#include <map> // 用于 Value 到 AllocaInst 的映射
#include <set> // 可能用于其他辅助集合
#include <string>
#include <vector>
namespace sysy {
class Reg2MemContext {
public:
Reg2MemContext(IRBuilder *b) : builder(b) {}
// 运行 Reg2Mem 优化
void run(Function *func);
private:
IRBuilder *builder; // IR 构建器
// 存储 SSA Value 到对应的 AllocaInst 的映射
// 只有那些需要被"溢出"到内存的 SSA 值才会被记录在这里
std::map<Value *, AllocaInst *> valueToAllocaMap;
// 辅助函数:
// 1. 识别并为 SSA Value 分配 AllocaInst
void allocateMemoryForSSAValues(Function *func);
// 2. 将 SSA 值的使用替换为 Load/Store
void insertLoadsAndStores(Function *func);
// 3. 处理 Phi 指令,将其转换为 Load/Store
void rewritePhis(Function *func);
// 4. 清理 (例如,可能删除不再需要的 Phi 指令)
void cleanup(Function *func);
// 判断一个 Value 是否是 AllocaInst 可以为其分配内存的目标
// 通常指非指针类型的Instruction结果和Argument
bool isPromotableToMemory(Value *val);
};
class Reg2Mem : public OptimizationPass {
private:
IRBuilder *builder; ///< IR构建器用于插入指令
public:
static void *ID; ///< Pass的唯一标识符
Reg2Mem(IRBuilder* builder) : OptimizationPass("Reg2Mem", Pass::Granularity::Function), builder(builder) {}
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; } ///< 获取 Pass ID
};
} // namespace sysy

View File

@ -0,0 +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 {
// 定义三值格 (Three-valued Lattice) 的状态
enum class LatticeVal {
Top, // (未知 / 未初始化)
Constant, // c (常量)
Bottom // ⊥ (不确定 / 变化 / 未定义)
};
// 新增枚举来区分常量的实际类型
enum class ValueType {
Integer,
Float,
Unknown // 用于 Top 和 Bottom 状态
};
// 用于表示 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:
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:
SCCPContext(IRBuilder *builder) : builder(builder), aliasAnalysis(nullptr), sideEffectAnalysis(nullptr) {}
// 设置别名分析结果
void setAliasAnalysis(AliasAnalysisResult *aa) { aliasAnalysis = aa; }
// 设置副作用分析结果
void setSideEffectAnalysis(SideEffectAnalysisResult *sea) { sideEffectAnalysis = sea; }
// 运行 SCCP 优化
void run(Function *func, AnalysisManager &AM);
};
// 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

@ -0,0 +1,101 @@
#pragma once
#include "IR.h"
#include "IRBuilder.h"
#include "Pass.h"
namespace sysy {
// 优化前对SysY IR的预处理也可以视作部分CFG优化
// 主要包括删除无用指令、合并基本块、删除空块等
// 这些操作可以在SysY IR生成时就完成但为了简化IR生成过程
// 这里将其放在SysY IR生成后进行预处理
// 同时兼容phi节点的处理可以再mem2reg后再次调用优化
//TODO: 可增加的CFG优化和方法
// - 检查基本块跳转关系正确性
// - 简化条件分支Branch Simplification如条件恒真/恒假转为直接跳转
// - 合并连续的跳转指令Jump Threading在合并不可达块中似乎已经实现了
// - 基本块重排序Block Reordering提升局部性
// 辅助工具类包含实际的CFG优化逻辑
// 这些方法可以被独立的Pass调用
class SysYCFGOptUtils {
public:
static bool SysYDelInstAfterBr(Function *func); // 删除br后面的指令
static bool SysYDelEmptyBlock(Function *func, IRBuilder* pBuilder); // 空块删除
static bool SysYDelNoPreBLock(Function *func); // 删除无前驱块(不可达块)
static bool SysYBlockMerge(Function *func); // 合并基本块
static bool SysYAddReturn(Function *func, IRBuilder* pBuilder); // 添加return指令
static bool SysYCondBr2Br(Function *func, IRBuilder* pBuilder); // 条件分支转换为无条件分支
};
// ======================================================================
// 独立的CFG优化遍
// ======================================================================
class SysYDelInstAfterBrPass : public OptimizationPass {
public:
static void *ID; // 唯一ID
SysYDelInstAfterBrPass() : OptimizationPass("SysYDelInstAfterBrPass", Granularity::Function) {}
bool runOnFunction(Function *F, AnalysisManager& AM) override;
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override {
// 这个优化可能改变CFG结构使一些CFG相关的分析失效
// 可以在这里指定哪些分析会失效,例如支配树、活跃变量等
// analysisInvalidations.insert(DominatorTreeAnalysisPass::ID); // 示例
}
void *getPassID() const override { return &ID; }
};
class SysYDelEmptyBlockPass : public OptimizationPass {
private:
IRBuilder *pBuilder;
public:
static void *ID;
SysYDelEmptyBlockPass(IRBuilder *builder) : OptimizationPass("SysYDelEmptyBlockPass", Granularity::Function), pBuilder(builder) {}
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; }
};
class SysYDelNoPreBLockPass : public OptimizationPass {
public:
static void *ID;
SysYDelNoPreBLockPass() : OptimizationPass("SysYDelNoPreBLockPass", 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; }
};
class SysYBlockMergePass : public OptimizationPass {
public:
static void *ID;
SysYBlockMergePass() : OptimizationPass("SysYBlockMergePass", 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; }
};
class SysYAddReturnPass : public OptimizationPass {
private:
IRBuilder *pBuilder;
public:
static void *ID;
SysYAddReturnPass(IRBuilder *builder) : OptimizationPass("SysYAddReturnPass", Granularity::Function), pBuilder(builder) {}
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; }
};
class SysYCondBr2BrPass : public OptimizationPass {
private:
IRBuilder *pBuilder;
public:
static void *ID;
SysYCondBr2BrPass(IRBuilder *builder) : OptimizationPass("SysYCondBr2BrPass", Granularity::Function), pBuilder(builder) {}
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,112 @@
#pragma once
#include "IR.h"
extern int DEBUG;
namespace sysy {
// 优化工具类,包含一些通用的优化方法
// 这些方法可以在不同的优化 pass 中复用
// 例如删除use关系,判断是否是全局变量等
class SysYIROptUtils{
public:
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);
}
// 判断是否是全局变量
static bool isGlobal(Value *val) {
auto gval = dynamic_cast<GlobalValue *>(val);
return gval != nullptr;
}
// 判断是否是数组
static bool isArr(Value *val) {
auto aval = dynamic_cast<AllocaInst *>(val);
// 如果是 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());
}
};
}// namespace sysy

View File

@ -0,0 +1,344 @@
#pragma once
#include <functional> // For std::function
#include <map>
#include <memory>
#include <set>
#include <string>
#include <typeindex> // For std::type_index (although void* ID is more common in LLVM)
#include <vector>
#include <type_traits>
#include "IR.h"
#include "IRBuilder.h"
extern int DEBUG; // 全局调试标志
namespace sysy {
//前向声明
class PassManager;
class AnalysisManager;
// 抽象基类:分析结果
class AnalysisResultBase {
public:
virtual ~AnalysisResultBase() = default;
};
// 抽象基类Pass
class Pass {
public:
enum class Granularity { Module, Function, BasicBlock };
enum class PassKind { Analysis, Optimization };
Pass(const std::string &name, Granularity g, PassKind k) : Name(name), G(g), K(k) {}
virtual ~Pass() = default;
const std::string &getName() const { return Name; }
Granularity getGranularity() const { return G; }
PassKind getPassKind() const { return K; }
virtual bool runOnModule(Module *M, AnalysisManager& AM) { return false; }
virtual bool runOnFunction(Function *F, AnalysisManager& AM) { return false; }
virtual bool runOnBasicBlock(BasicBlock *BB, AnalysisManager& AM) { return false; }
// 所有 Pass 都必须提供一个唯一的 ID
// 这通常是一个静态成员,并在 Pass 类外部定义
virtual void *getPassID() const = 0;
protected:
std::string Name;
Granularity G;
PassKind K;
};
// 抽象基类:分析遍
class AnalysisPass : public Pass {
public:
AnalysisPass(const std::string &name, Granularity g) : Pass(name, g, PassKind::Analysis) {}
virtual std::unique_ptr<AnalysisResultBase> getResult() = 0;
};
// 抽象基类:优化遍
class OptimizationPass : public Pass {
public:
OptimizationPass(const std::string &name, Granularity g) : Pass(name, g, PassKind::Optimization) {}
virtual void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
// 默认不依赖也不修改任何分析
}
};
// ======================================================================
// PassRegistry: 全局 Pass 注册表 (单例)
// ======================================================================
class PassRegistry {
public:
// Pass 工厂函数类型:返回 Pass 的唯一指针
using PassFactory = std::function<std::unique_ptr<Pass>()>;
// 获取 PassRegistry 实例 (单例模式)
static PassRegistry &getPassRegistry() {
static PassRegistry instance;
return instance;
}
// 注册一个 Pass
// passID 是 Pass 类的唯一静态 ID (例如 MyPass::ID 的地址)
// factory 是一个 lambda 或函数指针,用于创建该 Pass 的实例
void registerPass(void *passID, PassFactory factory) {
if (factories.count(passID)) {
// Error: Pass with this ID already registered
// You might want to throw an exception or log an error
return;
}
factories[passID] = std::move(factory);
}
// 通过 Pass ID 创建一个 Pass 实例
std::unique_ptr<Pass> createPass(void *passID) {
auto it = factories.find(passID);
if (it == factories.end()) {
// Error: Pass with this ID not registered
return nullptr;
}
return it->second(); // 调用工厂函数创建实例
}
private:
PassRegistry() = default; // 私有构造函数,实现单例
~PassRegistry() = default;
PassRegistry(const PassRegistry &) = delete; // 禁用拷贝构造
PassRegistry &operator=(const PassRegistry &) = delete; // 禁用赋值操作
std::map<void *, PassFactory> factories;
};
// ======================================================================
// AnalysisManager: 负责管理和提供分析结果
// ======================================================================
class AnalysisManager {
private:
Module *pModuleRef; // 指向被分析的Module
// 缓存不同粒度的分析结果
std::map<void *, std::unique_ptr<AnalysisResultBase>> moduleCachedResults;
std::map<std::pair<Function *, void *>, std::unique_ptr<AnalysisResultBase>> functionCachedResults;
std::map<std::pair<BasicBlock *, void *>, std::unique_ptr<AnalysisResultBase>> basicBlockCachedResults;
public:
// 构造函数接收 Module 指针
AnalysisManager(Module *M) : pModuleRef(M) {}
AnalysisManager() = delete; // 禁止无参构造
~AnalysisManager() = default;
// 获取分析结果的通用模板函数
// T 是 AnalysisResult 的具体类型E 是 AnalysisPass 的具体类型
// F 和 BB 参数用于提供上下文,根据分析遍的粒度来使用
template <typename T, typename E> T *getAnalysisResult(Function *F = nullptr, BasicBlock *BB = nullptr) {
void *analysisID = E::ID; // 获取分析遍的唯一 ID
// 尝试从注册表创建分析遍实例
std::unique_ptr<Pass> basePass = PassRegistry::getPassRegistry().createPass(analysisID);
if (!basePass) {
// Error: Analysis pass not registered
std::cerr << "Error: Analysis pass with ID " << analysisID << " not registered.\n";
return nullptr;
}
AnalysisPass *analysisPass = static_cast<AnalysisPass *>(basePass.get());
// 根据分析遍的粒度处理
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";
return nullptr;
}
analysisPass->runOnModule(pModuleRef, *this);
// 获取结果并缓存
std::unique_ptr<AnalysisResultBase> result = analysisPass->getResult();
T *specificResult = static_cast<T *>(result.get());
moduleCachedResults[analysisID] = std::move(result); // 缓存结果
return specificResult;
}
case Pass::Granularity::Function: {
// 检查请求的上下文是否正确
if (!F) {
std::cerr << "Error: Function context required for Function-level Analysis Pass.\n";
return nullptr;
}
// 检查是否已存在有效结果
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);
// 获取结果并缓存
std::unique_ptr<AnalysisResultBase> result = analysisPass->getResult();
T *specificResult = static_cast<T *>(result.get());
functionCachedResults[{F, analysisID}] = std::move(result); // 缓存结果
return specificResult;
}
case Pass::Granularity::BasicBlock: {
// 检查请求的上下文是否正确
if (!BB) {
std::cerr << "Error: BasicBlock context required for BasicBlock-level Analysis Pass.\n";
return nullptr;
}
// 检查是否已存在有效结果
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);
// 获取结果并缓存
std::unique_ptr<AnalysisResultBase> result = analysisPass->getResult();
T *specificResult = static_cast<T *>(result.get());
basicBlockCachedResults[{BB, analysisID}] = std::move(result); // 缓存结果
return specificResult;
}
}
return nullptr; // 不会到达这里
}
// 使所有分析结果失效 (当 IR 被修改时调用)
void invalidateAllAnalyses() {
moduleCachedResults.clear();
functionCachedResults.clear();
basicBlockCachedResults.clear();
}
// 使特定分析结果失效
// void *analysisID: 要失效的分析的ID
// Function *F: 如果是函数级分析指定函数如果是模块级或基本块级则为nullptr (取决于调用方式)
// BasicBlock *BB: 如果是基本块级分析指定基本块否则为nullptr
void invalidateAnalysis(void *analysisID, Function *F = nullptr, BasicBlock *BB = nullptr) {
if (BB) {
// 使特定基本块的特定分析结果失效
basicBlockCachedResults.erase({BB, analysisID});
} else if (F) {
// 使特定函数的特定分析结果失效 (也可能包含聚合的BasicBlock结果)
functionCachedResults.erase({F, analysisID});
// 遍历所有属于F的基本块使其BasicBlockCache失效 (如果该分析是BasicBlock粒度的)
// 这需要遍历F的所有基本块效率较低更推荐在BasicBlockPass的invalidateAnalysisUsage中精确指定
// 或者在Function级别的invalidate时清空该Function的所有BasicBlock分析
// 这里的实现简单地清空该Function下所有该ID的BasicBlock缓存
for (auto it = basicBlockCachedResults.begin(); it != basicBlockCachedResults.end(); ) {
// 假设BasicBlock::getParent()方法存在可以获取所属Function
if (it->first.second == analysisID /* && it->first.first->getParent() == F */) { // 需要BasicBlock能获取其父函数
it = basicBlockCachedResults.erase(it);
} else {
++it;
}
}
} else {
// 使所有函数的特定分析结果失效 (Module级和所有Function/BasicBlock级)
moduleCachedResults.erase(analysisID);
for (auto it = functionCachedResults.begin(); it != functionCachedResults.end(); ) {
if (it->first.second == analysisID) {
it = functionCachedResults.erase(it);
} else {
++it;
}
}
for (auto it = basicBlockCachedResults.begin(); it != basicBlockCachedResults.end(); ) {
if (it->first.second == analysisID) {
it = basicBlockCachedResults.erase(it);
} else {
++it;
}
}
}
}
};
// ======================================================================
// PassManager遍管理器
// ======================================================================
class PassManager {
private:
std::vector<std::unique_ptr<Pass>> passes;
AnalysisManager analysisManager;
Module *pmodule;
IRBuilder *pBuilder;
public:
PassManager() = delete;
~PassManager() = default;
PassManager(Module *module, IRBuilder *builder) : pmodule(module) ,pBuilder(builder), analysisManager(module) {}
// 运行所有注册的遍
bool run();
// 运行优化管道主要负责注册和运行优化遍
// 这里可以根据 optLevel 和 DEBUG 控制不同的优化遍
void runOptimizationPipeline(Module* moduleIR, IRBuilder* builder, int optLevel);
// 添加遍:现在接受 Pass 的 ID而不是直接的 unique_ptr
void addPass(void *passID);
AnalysisManager &getAnalysisManager() { return analysisManager; }
void clearPasses();
// 输出pass列表并打印IR信息供观察优化遍效果
void printPasses() const;
};
// ======================================================================
// 辅助宏或函数,用于简化 Pass 的注册
// ======================================================================
// 用于分析遍的注册
template <typename AnalysisPassType> void registerAnalysisPass();
// (1) 针对需要 IRBuilder 参数的优化遍的重载
// 这个模板只在 OptimizationPassType 可以通过 IRBuilder* 构造时才有效
template <typename OptimizationPassType, typename std::enable_if<
std::is_constructible<OptimizationPassType, IRBuilder*>::value, int>::type = 0>
void registerOptimizationPass(IRBuilder* builder);
// (2) 针对不需要 IRBuilder 参数的所有其他优化遍的重载
// 这个模板只在 OptimizationPassType 不能通过 IRBuilder* 构造时才有效
template <typename OptimizationPassType, typename std::enable_if<
!std::is_constructible<OptimizationPassType, IRBuilder*>::value, int>::type = 0>
void registerOptimizationPass();
} // namespace sysy

View File

@ -59,15 +59,96 @@ private:
std::unique_ptr<Module> module;
IRBuilder builder;
using ValueOrOperator = std::variant<Value*, int>;
std::vector<ValueOrOperator> BinaryExpStack; ///< 用于存储二元表达式的中缀表达式
std::vector<int> BinaryExpLenStack; ///< 用于存储该层次的二元表达式的长度
// 下面是用于后缀表达式的计算的数据结构
std::vector<ValueOrOperator> BinaryRPNStack; ///< 用于存储二元表达式的后缀表达式
std::vector<int> BinaryOpStack; ///< 用于存储二元表达式中缀表达式转换到后缀表达式的操作符栈
std::vector<Value *> BinaryValueStack; ///< 用于存储后缀表达式计算的操作数栈
// 约定操作符:
// 1: 'ADD', 2: 'SUB', 3: 'MUL', 4: 'DIV', 5: '%', 6: 'PLUS', 7: 'NEG', 8: 'NOT', 9: 'LPAREN', 10: 'RPAREN'
// 这里的操作符是为了方便后缀表达式的计算而设计
// 其中,'ADD', 'SUB', 'MUL', 'DIV', '%'
// 分别对应加法、减法、乘法、除法和取模
// 'PLUS' 和 'NEG' 分别对应一元加法和一元减法
// 'NOT' 对应逻辑非
// 'LPAREN' 和 'RPAREN' 分别对应左括号和右括号
enum BinaryOp {
ADD = 1, SUB = 2, MUL = 3, DIV = 4, MOD = 5, PLUS = 6, NEG = 7, NOT = 8, LPAREN = 9, RPAREN = 10,
};
int getOperatorPrecedence(int op) {
switch (op) {
case MUL: case DIV: case MOD: return 2;
case ADD: case SUB: return 1;
case PLUS: case NEG: case NOT: return 3;
case LPAREN: case RPAREN: return 0; // Parentheses have lowest precedence for stack logic
default: return -1; // Unknown operator
}
};
struct ExpKey {
BinaryOp op; ///< 操作符
Value *left; ///< 左操作数
Value *right; ///< 右操作数
ExpKey(BinaryOp op, Value *left, Value *right) : op(op), left(left), right(right) {}
bool operator<(const ExpKey &other) const {
if (op != other.op)
return op < other.op; ///< 比较操作符
if (left != other.left)
return left < other.left; ///< 比较左操作
return right < other.right; ///< 比较右操作数
} ///< 重载小于运算符用于比较ExpKey
};
struct UnExpKey {
BinaryOp op; ///< 一元操作符
Value *operand; ///< 操作数
UnExpKey(BinaryOp op, Value *operand) : op(op), operand(operand) {}
bool operator<(const UnExpKey &other) const {
if (op != other.op)
return op < other.op; ///< 比较操作符
return operand < other.operand; ///< 比较操作数
} ///< 重载小于运算符用于比较UnExpKey
};
struct GEPKey {
Value *basePointer;
std::vector<Value *> indices;
// 为 std::map 定义比较运算符,使得 GEPKey 可以作为键
bool operator<(const GEPKey &other) const {
if (basePointer != other.basePointer) {
return basePointer < other.basePointer;
}
// 逐个比较索引,确保顺序一致
if (indices.size() != other.indices.size()) {
return indices.size() < other.indices.size();
}
for (size_t i = 0; i < indices.size(); ++i) {
if (indices[i] != other.indices[i]) {
return indices[i] < other.indices[i];
}
}
return false; // 如果 basePointer 和所有索引都相同,则认为相等
}
};
std::map<GEPKey, Value*> availableGEPs; ///< 用于存储 GEP 的缓存
std::map<ExpKey, Value*> availableBinaryExpressions;
std::map<UnExpKey, Value*> availableUnaryExpressions;
std::map<Value*, Value*> availableLoads;
public:
SysYIRGenerator() = default;
bool HasReturnInst;
public:
Module *get() const { return module.get(); }
IRBuilder *getBuilder(){ return &builder; }
public:
std::any visitCompUnit(SysYParser::CompUnitContext *ctx) override;
std::any visitGlobalConstDecl(SysYParser::GlobalConstDeclContext *ctx) override;
@ -98,7 +179,7 @@ public:
std::any visitBlockStmt(SysYParser::BlockStmtContext* ctx) override;
// std::any visitStmt(SysYParser::StmtContext *ctx) override;
std::any visitAssignStmt(SysYParser::AssignStmtContext *ctx) override;
// std::any visitExpStmt(SysYParser::ExpStmtContext *ctx) override;
std::any visitExpStmt(SysYParser::ExpStmtContext *ctx) override;
// std::any visitBlkStmt(SysYParser::BlkStmtContext *ctx) override;
std::any visitIfStmt(SysYParser::IfStmtContext *ctx) override;
std::any visitWhileStmt(SysYParser::WhileStmtContext *ctx) override;
@ -132,7 +213,29 @@ public:
std::any visitLAndExp(SysYParser::LAndExpContext *ctx) override;
std::any visitLOrExp(SysYParser::LOrExpContext *ctx) override;
// std::any visitConstExp(SysYParser::ConstExpContext *ctx) override;
std::any visitConstExp(SysYParser::ConstExpContext *ctx) override;
bool isRightAssociative(int op);
Value* promoteType(Value* value, Type* targetType);
Value* computeExp(SysYParser::ExpContext *ctx, Type* targetType = nullptr);
Value* computeAddExp(SysYParser::AddExpContext *ctx, Type* targetType = nullptr);
void compute();
// 参数是发生 store 操作的目标地址/变量的 Value*
void invalidateExpressionsOnStore(Value* storedAddress);
// 清除因函数调用而失效的表达式缓存(保守策略)
void invalidateExpressionsOnCall();
// 在进入新的基本块时清空所有表达式缓存
void enterNewBasicBlock();
public:
// 获取GEP指令的地址
Value* getGEPAddressInst(Value* basePointer, const std::vector<Value*>& indices);
// 构建数组类型
Type* buildArrayType(Type* baseType, const std::vector<Value*>& dims);
unsigned countArrayDimensions(Type* type);
}; // class SysYIRGenerator

View File

@ -15,6 +15,7 @@ public:
public:
void printIR();
void printGlobalVariable();
void printGlobalConstant();
public:
@ -22,6 +23,8 @@ public:
static void printInst(Instruction *pInst);
static void printType(Type *type);
static void printValue(Value *value);
static void printBlock(BasicBlock *block);
static std::string getBlockName(BasicBlock *block);
static std::string getOperandName(Value *operand);
static std::string getTypeString(Type *type);
static std::string getValueName(Value *value);

37
src/midend/CMakeLists.txt Normal file
View File

@ -0,0 +1,37 @@
# src/midend/CMakeLists.txt
add_library(midend_lib STATIC
IR.cpp
SysYIRGenerator.cpp
SysYIRPrinter.cpp
Pass/Pass.cpp
Pass/Analysis/Dom.cpp
Pass/Analysis/Liveness.cpp
Pass/Analysis/Loop.cpp
Pass/Analysis/LoopCharacteristics.cpp
Pass/Analysis/LoopVectorization.cpp
Pass/Analysis/AliasAnalysis.cpp
Pass/Analysis/SideEffectAnalysis.cpp
Pass/Analysis/CallGraphAnalysis.cpp
Pass/Optimize/DCE.cpp
Pass/Optimize/Mem2Reg.cpp
Pass/Optimize/Reg2Mem.cpp
Pass/Optimize/GVN.cpp
Pass/Optimize/SysYIRCFGOpt.cpp
Pass/Optimize/SCCP.cpp
Pass/Optimize/LoopNormalization.cpp
Pass/Optimize/LICM.cpp
Pass/Optimize/LoopStrengthReduction.cpp
Pass/Optimize/InductionVariableElimination.cpp
Pass/Optimize/BuildCFG.cpp
Pass/Optimize/LargeArrayToGlobal.cpp
)
# 包含中端模块所需的头文件路径
target_include_directories(midend_lib PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../include/midend # 中端顶层头文件
${CMAKE_CURRENT_SOURCE_DIR}/../include/midend/Pass # 增加 Pass 头文件路径
${CMAKE_CURRENT_SOURCE_DIR}/../include/midend/Pass/Analysis # 增加 Pass/Analysis 头文件路径
${CMAKE_CURRENT_SOURCE_DIR}/../include/midend/Pass/Optimize # 增加 Pass/Optimize 头文件路径
${CMAKE_CURRENT_SOURCE_DIR}/../include/frontend # 增加 frontend 头文件路径 (已存在)
${ANTLR_RUNTIME}/runtime/src # ANTLR运行时库头文件
)

1443
src/midend/IR.cpp Normal file

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

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