Commit efbf4233 authored by 李晓奇's avatar 李晓奇

follow update

parent f0f0bb81
...@@ -6,7 +6,7 @@ AlwaysBreakTemplateDeclarations: true ...@@ -6,7 +6,7 @@ AlwaysBreakTemplateDeclarations: true
BinPackArguments: false BinPackArguments: false
BinPackParameters: false BinPackParameters: false
BreakConstructorInitializers: BeforeComma BreakConstructorInitializers: BeforeComma
ColumnLimit: 120 ColumnLimit: 80
CommentPragmas: '^(!|NOLINT)' CommentPragmas: '^(!|NOLINT)'
ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerAllOnOneLineOrOnePerLine: true
IncludeBlocks: Regroup IncludeBlocks: Regroup
...@@ -23,4 +23,5 @@ PenaltyReturnTypeOnItsOwnLine: 200 ...@@ -23,4 +23,5 @@ PenaltyReturnTypeOnItsOwnLine: 200
SpacesBeforeTrailingComments: 1 SpacesBeforeTrailingComments: 1
TabWidth: 4 TabWidth: 4
UseTab: Never UseTab: Never
AlwaysBreakAfterReturnType: TopLevelDefinitions
... ...
# Lab4 实验文档 # Lab4 实验文档
- [Lab4 实验文档](#lab4-实验文档) - [Lab4 实验文档](#lab4-实验文档)
- [0. 前言](#0-前言) - [0. 前言](#0-前言)
- [1. GVN 基础知识](#1-gvn-基础知识) - [1. GVN 基础知识](#1-gvn-基础知识)
...@@ -25,9 +26,11 @@ ...@@ -25,9 +26,11 @@
- [4. 提交要求](#4-提交要求) - [4. 提交要求](#4-提交要求)
- [目录结构](#目录结构) - [目录结构](#目录结构)
- [提交要求和评分标准](#提交要求和评分标准) - [提交要求和评分标准](#提交要求和评分标准)
## 0. 前言
## 0. 前言
在 Lab4.1 中,我们介绍了 SSA IR,并阐明了其优势。本次实验中我们需要在 SSA IR 基础上,实现一个基于数据流分析的冗余消除的优化 Pass : Global Value Numbering(全局值编号)。 在 Lab4.1 中,我们介绍了 SSA IR,并阐明了其优势。本次实验中我们需要在 SSA IR 基础上,实现一个基于数据流分析的冗余消除的优化 Pass : Global Value Numbering(全局值编号)。
## 1. GVN 基础知识 ## 1. GVN 基础知识
### 1.1 GVN 简介 ### 1.1 GVN 简介
...@@ -110,6 +113,7 @@ bb3: ...@@ -110,6 +113,7 @@ bb3:
一个 Partition (分区)由一系列等价类组成,一个等价类是由一个值编号,和一系列成员组成。每个成员可以是:变量,常量,值表达式。同时,一个等价类可能会关联一个 value-phi-function。 一个 Partition (分区)由一系列等价类组成,一个等价类是由一个值编号,和一系列成员组成。每个成员可以是:变量,常量,值表达式。同时,一个等价类可能会关联一个 value-phi-function。
#### 7. Join 操作 #### 7. Join 操作
Join 操作检测到达此处的所有路径共有的等价项。在 SSA 格式的 IR 中,变量只会被赋值一次,当程序点 p 支配 join block 时,在 p 点成立的等价关系,在 join block 处仍然成立。通过对 join block 的前驱 Partition 取交集,可以保留所有支配 join block 的程序点的等价关系。对于在每个路径的等价的探测,我们将在[2.GVN算法](#2-gvn-算法论文中提供的伪代码)中通过伪代码进行阐述。对于表达式的等价关系与变量等价关系的检测与判定,我们会分别阐述。 Join 操作检测到达此处的所有路径共有的等价项。在 SSA 格式的 IR 中,变量只会被赋值一次,当程序点 p 支配 join block 时,在 p 点成立的等价关系,在 join block 处仍然成立。通过对 join block 的前驱 Partition 取交集,可以保留所有支配 join block 的程序点的等价关系。对于在每个路径的等价的探测,我们将在[2.GVN算法](#2-gvn-算法论文中提供的伪代码)中通过伪代码进行阐述。对于表达式的等价关系与变量等价关系的检测与判定,我们会分别阐述。
#### 8. 变量等价与表达式等价 #### 8. 变量等价与表达式等价
...@@ -263,6 +267,7 @@ valuePhiFunc(ve,P) ...@@ -263,6 +267,7 @@ valuePhiFunc(ve,P)
## 3. 实验内容 ## 3. 实验内容
在本次实验中,请仔细阅读[3.1 GVN pass 实现内容要求](#31-gvn-pass-实现内容要求),根据要求补全`src/optimization/GVN.cpp``include/optimization/GVN.h`中关于 GVN pass 数据流分析部分,同时需要在 `Reports/4-ir-opt/` 目录下撰写实验报告。**为了在评测中统一分析结果,请大家采用 lab3 的 TA-impl 分支提供的[答案](http://202.38.79.174/compiler_staff/2022fall-compiler_cminus/-/blob/TA-impl/src/cminusfc/cminusf_builder.cpp)来完成后续实验。** 在本次实验中,请仔细阅读[3.1 GVN pass 实现内容要求](#31-gvn-pass-实现内容要求),根据要求补全`src/optimization/GVN.cpp``include/optimization/GVN.h`中关于 GVN pass 数据流分析部分,同时需要在 `Reports/4-ir-opt/` 目录下撰写实验报告。**为了在评测中统一分析结果,请大家采用 lab3 的 TA-impl 分支提供的[答案](http://202.38.79.174/compiler_staff/2022fall-compiler_cminus/-/blob/TA-impl/src/cminusfc/cminusf_builder.cpp)来完成后续实验。**
### 3.1 GVN pass 实现内容要求 ### 3.1 GVN pass 实现内容要求
GVN 通过数据流分析来检测冗余的变量和计算,通过替换和死代码删除结合,实现优化效果。前述的例子中主要以二元运算语句来解释原理,且助教为大家提供了代码替换和删除的逻辑,除此之外,需要完成的方向有: GVN 通过数据流分析来检测冗余的变量和计算,通过替换和死代码删除结合,实现优化效果。前述的例子中主要以二元运算语句来解释原理,且助教为大家提供了代码替换和删除的逻辑,除此之外,需要完成的方向有:
...@@ -469,8 +474,8 @@ root@3fd22a9ed627:/labs/2022fall-compiler_cminus-taversion/tests/4-ir-opt# ...@@ -469,8 +474,8 @@ root@3fd22a9ed627:/labs/2022fall-compiler_cminus-taversion/tests/4-ir-opt#
└── 4-ir-opt └── 4-ir-opt
   ├── testcases 助教提供的测试样例    ├── testcases 助教提供的测试样例
   └── lab4_test.py 助教提供的测试脚本    └── lab4_test.py 助教提供的测试脚本
``` ```
### 提交要求和评分标准 ### 提交要求和评分标准
* 提交要求 * 提交要求
...@@ -488,6 +493,7 @@ root@3fd22a9ed627:/labs/2022fall-compiler_cminus-taversion/tests/4-ir-opt# ...@@ -488,6 +493,7 @@ root@3fd22a9ed627:/labs/2022fall-compiler_cminus-taversion/tests/4-ir-opt#
* 本次实验报告以 pdf 格式提交到希冀平台对应提交通道 * 本次实验报告以 pdf 格式提交到希冀平台对应提交通道
* 评分标准: 实验完成分(总分 60 分)组成如下: * 评分标准: 实验完成分(总分 60 分)组成如下:
* 实验报告 (5 分) * 实验报告 (5 分)
需要回答 Reports 目录下实验报告模板的思考题。 需要回答 Reports 目录下实验报告模板的思考题。
...@@ -505,10 +511,10 @@ root@3fd22a9ed627:/labs/2022fall-compiler_cminus-taversion/tests/4-ir-opt# ...@@ -505,10 +511,10 @@ root@3fd22a9ed627:/labs/2022fall-compiler_cminus-taversion/tests/4-ir-opt#
"label7": [["%op0", ], ["%op1", ], ["%op2", ], ["%op10", ], ["%op9", ], ["%op11", "%op8", ], ], "label7": [["%op0", ], ["%op1", ], ["%op2", ], ["%op10", ], ["%op9", ], ["%op11", "%op8", ], ],
"label12": [["%op0", ], ["%op1", ], ["%op2", ], ["%op13", "%op10", ], ["%op14", "%op9", ], ["%op15", "%op8", ], ],} "label12": [["%op0", ], ["%op1", ], ["%op2", ], ["%op13", "%op10", ], ["%op14", "%op9", ], ["%op15", "%op8", ], ],}
``` ```
对于分值为 x,n 个基本块的程序,每个 bb 分析结果为$`x/n`$分,某个bb的分析结果多或者少一个等价类,或有分析错误的等价类,该 bb 分析结果没有分值。
对于分值为 x,n 个基本块的程序,每个 bb 分析结果为$`x/n`$分,某个bb的分析结果多或者少一个等价类,或有分析错误的等价类,该 bb 分析结果没有分值。
* performance case(15分) * performance case(15分)
助教提供了 2 个公开case,并保留 2 个隐藏用例。以及助教实现优化后的 baseline.ll ,优化效果按照如下方式给分(执行结果不正确则此项分数为0) 助教提供了 2 个公开case,并保留 2 个隐藏用例。以及助教实现优化后的 baseline.ll ,优化效果按照如下方式给分(执行结果不正确则此项分数为0)
...@@ -519,7 +525,7 @@ root@3fd22a9ed627:/labs/2022fall-compiler_cminus-taversion/tests/4-ir-opt# ...@@ -519,7 +525,7 @@ root@3fd22a9ed627:/labs/2022fall-compiler_cminus-taversion/tests/4-ir-opt#
(before_optimization-after_optimization)/(before_optimization-baseline) > 0.2 得60%分数 (before_optimization-after_optimization)/(before_optimization-baseline) > 0.2 得60%分数
``` ```
* 禁止执行恶意代码,违者本次实验0分处理 * 禁止执行恶意代码,违者本次实验0分处理
* 迟交规定 * 迟交规定
...@@ -528,14 +534,17 @@ root@3fd22a9ed627:/labs/2022fall-compiler_cminus-taversion/tests/4-ir-opt# ...@@ -528,14 +534,17 @@ root@3fd22a9ed627:/labs/2022fall-compiler_cminus-taversion/tests/4-ir-opt#
* `Hard Deadline`: 2022/12/19 23:59:59 (北京标准时间,UTC+8) * `Hard Deadline`: 2022/12/19 23:59:59 (北京标准时间,UTC+8)
* 迟交需要邮件通知 TA : * 迟交需要邮件通知 TA :
* 邮箱: * 邮箱:
chen16614@mail.ustc.edu.cn 抄送 farmerzhang1@mail.ustc.edu.cn chen16614@mail.ustc.edu.cn 抄送 farmerzhang1@mail.ustc.edu.cn
* 邮件主题: lab4.2迟交-学号 * 邮件主题: lab4.2迟交-学号
* 内容: 包括迟交原因、最后版本commitID、迟交时间等 * 内容: 包括迟交原因、最后版本commitID、迟交时间等
* 迟交分数 * 迟交分数
* x为迟交天数(对于`Soft Deadline`而言),grade为满分 * x为迟交天数(对于`Soft Deadline`而言),grade为满分
``` bash
```bash
final_grade = grade, x = 0 final_grade = grade, x = 0
final_grade = grade * (0.9)^x, 0 < x <= 7 final_grade = grade * (0.9)^x, 0 < x <= 7
final_grade = 0, x > 7 # 这一条严格执行,请对自己负责 final_grade = 0, x > 7 # 这一条严格执行,请对自己负责
......
...@@ -56,6 +56,7 @@ class Instruction : public User, public llvm::ilist_node<Instruction> ...@@ -56,6 +56,7 @@ class Instruction : public User, public llvm::ilist_node<Instruction>
Module *get_module(); Module *get_module();
OpID get_instr_type() const { return op_id_; } OpID get_instr_type() const { return op_id_; }
// clang-format off
static std::string get_instr_op_name(OpID id) { static std::string get_instr_op_name(OpID id) {
switch (id) { switch (id) {
case ret: return "ret"; break; case ret: return "ret"; break;
...@@ -79,12 +80,10 @@ class Instruction : public User, public llvm::ilist_node<Instruction> ...@@ -79,12 +80,10 @@ class Instruction : public User, public llvm::ilist_node<Instruction>
case zext: return "zext"; break; case zext: return "zext"; break;
case fptosi: return "fptosi"; break; case fptosi: return "fptosi"; break;
case sitofp: return "sitofp"; break; case sitofp: return "sitofp"; break;
default: return ""; break;
default:
return "";
break;
} }
} }
// clang-format on
std::string get_instr_op_name() { return get_instr_op_name(op_id_); } std::string get_instr_op_name() { return get_instr_op_name(op_id_); }
bool is_void() bool is_void()
......
...@@ -159,6 +159,7 @@ class GVN : public Pass { ...@@ -159,6 +159,7 @@ class GVN : public Pass {
partitions join(const partitions &P1, const partitions &P2); partitions join(const partitions &P1, const partitions &P2);
std::shared_ptr<CongruenceClass> intersect(std::shared_ptr<CongruenceClass>, std::shared_ptr<CongruenceClass>); std::shared_ptr<CongruenceClass> intersect(std::shared_ptr<CongruenceClass>, std::shared_ptr<CongruenceClass>);
partitions transferFunction(Instruction *x, Value *e, partitions pin); partitions transferFunction(Instruction *x, Value *e, partitions pin);
partitions transferFunction(BasicBlock *bb);
std::shared_ptr<GVNExpression::PhiExpression> valuePhiFunc(std::shared_ptr<GVNExpression::Expression>, std::shared_ptr<GVNExpression::PhiExpression> valuePhiFunc(std::shared_ptr<GVNExpression::Expression>,
const partitions &); const partitions &);
std::shared_ptr<GVNExpression::Expression> valueExpr(Instruction *instr); std::shared_ptr<GVNExpression::Expression> valueExpr(Instruction *instr);
...@@ -176,6 +177,10 @@ class GVN : public Pass { ...@@ -176,6 +177,10 @@ class GVN : public Pass {
return std::make_shared<CongruenceClass>(index); return std::make_shared<CongruenceClass>(index);
} }
// self add
//
std::uint64_t new_number() { return next_value_number_++; }
private: private:
bool dump_json_; bool dump_json_;
std::uint64_t next_value_number_ = 1; std::uint64_t next_value_number_ = 1;
...@@ -184,6 +189,9 @@ class GVN : public Pass { ...@@ -184,6 +189,9 @@ class GVN : public Pass {
std::unique_ptr<FuncInfo> func_info_; std::unique_ptr<FuncInfo> func_info_;
std::unique_ptr<GVNExpression::ConstFolder> folder_; std::unique_ptr<GVNExpression::ConstFolder> folder_;
std::unique_ptr<DeadCode> dce_; std::unique_ptr<DeadCode> dce_;
// self add
std::map<Instruction*, bool> _TOP;
}; };
bool operator==(const GVN::partitions &p1, const GVN::partitions &p2); bool operator==(const GVN::partitions &p1, const GVN::partitions &p2);
...@@ -22,65 +22,112 @@ using namespace GVNExpression; ...@@ -22,65 +22,112 @@ using namespace GVNExpression;
using std::string_literals::operator""s; using std::string_literals::operator""s;
using std::shared_ptr; using std::shared_ptr;
static auto get_const_int_value = [](Value *v) { return dynamic_cast<ConstantInt *>(v)->get_value(); }; static auto get_const_int_value = [](Value *v) {
static auto get_const_fp_value = [](Value *v) { return dynamic_cast<ConstantFP *>(v)->get_value(); }; return dynamic_cast<ConstantInt *>(v)->get_value();
};
static auto get_const_fp_value = [](Value *v) {
return dynamic_cast<ConstantFP *>(v)->get_value();
};
// Constant Propagation helper, folders are done for you // Constant Propagation helper, folders are done for you
Constant *ConstFolder::compute(Instruction *instr, Constant *value1, Constant *value2) { Constant *
ConstFolder::compute(Instruction *instr, Constant *value1, Constant *value2) {
auto op = instr->get_instr_type(); auto op = instr->get_instr_type();
switch (op) { switch (op) {
case Instruction::add: case Instruction::add:
return ConstantInt::get(get_const_int_value(value1) + get_const_int_value(value2), module_); return ConstantInt::get(get_const_int_value(value1) +
get_const_int_value(value2),
module_);
case Instruction::sub: case Instruction::sub:
return ConstantInt::get(get_const_int_value(value1) - get_const_int_value(value2), module_); return ConstantInt::get(get_const_int_value(value1) -
get_const_int_value(value2),
module_);
case Instruction::mul: case Instruction::mul:
return ConstantInt::get(get_const_int_value(value1) * get_const_int_value(value2), module_); return ConstantInt::get(get_const_int_value(value1) *
get_const_int_value(value2),
module_);
case Instruction::sdiv: case Instruction::sdiv:
return ConstantInt::get(get_const_int_value(value1) / get_const_int_value(value2), module_); return ConstantInt::get(get_const_int_value(value1) /
get_const_int_value(value2),
module_);
case Instruction::fadd: case Instruction::fadd:
return ConstantFP::get(get_const_fp_value(value1) + get_const_fp_value(value2), module_); return ConstantFP::get(get_const_fp_value(value1) +
get_const_fp_value(value2),
module_);
case Instruction::fsub: case Instruction::fsub:
return ConstantFP::get(get_const_fp_value(value1) - get_const_fp_value(value2), module_); return ConstantFP::get(get_const_fp_value(value1) -
get_const_fp_value(value2),
module_);
case Instruction::fmul: case Instruction::fmul:
return ConstantFP::get(get_const_fp_value(value1) * get_const_fp_value(value2), module_); return ConstantFP::get(get_const_fp_value(value1) *
get_const_fp_value(value2),
module_);
case Instruction::fdiv: case Instruction::fdiv:
return ConstantFP::get(get_const_fp_value(value1) / get_const_fp_value(value2), module_); return ConstantFP::get(get_const_fp_value(value1) /
get_const_fp_value(value2),
module_);
case Instruction::cmp: case Instruction::cmp:
switch (dynamic_cast<CmpInst *>(instr)->get_cmp_op()) { switch (dynamic_cast<CmpInst *>(instr)->get_cmp_op()) {
case CmpInst::EQ: case CmpInst::EQ:
return ConstantInt::get(get_const_int_value(value1) == get_const_int_value(value2), module_); return ConstantInt::get(get_const_int_value(value1) ==
get_const_int_value(value2),
module_);
case CmpInst::NE: case CmpInst::NE:
return ConstantInt::get(get_const_int_value(value1) != get_const_int_value(value2), module_); return ConstantInt::get(get_const_int_value(value1) !=
get_const_int_value(value2),
module_);
case CmpInst::GT: case CmpInst::GT:
return ConstantInt::get(get_const_int_value(value1) > get_const_int_value(value2), module_); return ConstantInt::get(get_const_int_value(value1) >
get_const_int_value(value2),
module_);
case CmpInst::GE: case CmpInst::GE:
return ConstantInt::get(get_const_int_value(value1) >= get_const_int_value(value2), module_); return ConstantInt::get(get_const_int_value(value1) >=
get_const_int_value(value2),
module_);
case CmpInst::LT: case CmpInst::LT:
return ConstantInt::get(get_const_int_value(value1) < get_const_int_value(value2), module_); return ConstantInt::get(get_const_int_value(value1) <
get_const_int_value(value2),
module_);
case CmpInst::LE: case CmpInst::LE:
return ConstantInt::get(get_const_int_value(value1) <= get_const_int_value(value2), module_); return ConstantInt::get(get_const_int_value(value1) <=
get_const_int_value(value2),
module_);
} }
case Instruction::fcmp: case Instruction::fcmp:
switch (dynamic_cast<FCmpInst *>(instr)->get_cmp_op()) { switch (dynamic_cast<FCmpInst *>(instr)->get_cmp_op()) {
case FCmpInst::EQ: case FCmpInst::EQ:
return ConstantInt::get(get_const_fp_value(value1) == get_const_fp_value(value2), module_); return ConstantInt::get(get_const_fp_value(value1) ==
get_const_fp_value(value2),
module_);
case FCmpInst::NE: case FCmpInst::NE:
return ConstantInt::get(get_const_fp_value(value1) != get_const_fp_value(value2), module_); return ConstantInt::get(get_const_fp_value(value1) !=
get_const_fp_value(value2),
module_);
case FCmpInst::GT: case FCmpInst::GT:
return ConstantInt::get(get_const_fp_value(value1) > get_const_fp_value(value2), module_); return ConstantInt::get(get_const_fp_value(value1) >
get_const_fp_value(value2),
module_);
case FCmpInst::GE: case FCmpInst::GE:
return ConstantInt::get(get_const_fp_value(value1) >= get_const_fp_value(value2), module_); return ConstantInt::get(get_const_fp_value(value1) >=
get_const_fp_value(value2),
module_);
case FCmpInst::LT: case FCmpInst::LT:
return ConstantInt::get(get_const_fp_value(value1) < get_const_fp_value(value2), module_); return ConstantInt::get(get_const_fp_value(value1) <
get_const_fp_value(value2),
module_);
case FCmpInst::LE: case FCmpInst::LE:
return ConstantInt::get(get_const_fp_value(value1) <= get_const_fp_value(value2), module_); return ConstantInt::get(get_const_fp_value(value1) <=
get_const_fp_value(value2),
module_);
} }
default: default:
return nullptr; return nullptr;
} }
} }
Constant *ConstFolder::compute(Instruction *instr, Constant *value1) { Constant *
ConstFolder::compute(Instruction *instr, Constant *value1) {
auto op = instr->get_instr_type(); auto op = instr->get_instr_type();
switch (op) { switch (op) {
case Instruction::sitofp: case Instruction::sitofp:
...@@ -95,22 +142,27 @@ Constant *ConstFolder::compute(Instruction *instr, Constant *value1) { ...@@ -95,22 +142,27 @@ Constant *ConstFolder::compute(Instruction *instr, Constant *value1) {
} }
namespace utils { namespace utils {
static std::string print_congruence_class(const CongruenceClass &cc) { static std::string
print_congruence_class(const CongruenceClass &cc) {
std::stringstream ss; std::stringstream ss;
if (cc.index_ == 0) { if (cc.index_ == 0) {
ss << "top class\n"; ss << "top class\n";
return ss.str(); return ss.str();
} }
ss << "\nindex: " << cc.index_ << "\nleader: " << cc.leader_->print() ss << "\nindex: " << cc.index_ << "\nleader: " << cc.leader_->print()
<< "\nvalue phi: " << (cc.value_phi_ ? cc.value_phi_->print() : "nullptr"s) << "\nvalue phi: "
<< "\nvalue expr: " << (cc.value_expr_ ? cc.value_expr_->print() : "nullptr"s) << "\nmembers: {"; << (cc.value_phi_ ? cc.value_phi_->print() : "nullptr"s)
<< "\nvalue expr: "
<< (cc.value_expr_ ? cc.value_expr_->print() : "nullptr"s)
<< "\nmembers: {";
for (auto &member : cc.members_) for (auto &member : cc.members_)
ss << member->print() << "; "; ss << member->print() << "; ";
ss << "}\n"; ss << "}\n";
return ss.str(); return ss.str();
} }
static std::string dump_cc_json(const CongruenceClass &cc) { static std::string
dump_cc_json(const CongruenceClass &cc) {
std::string json; std::string json;
json += "["; json += "[";
for (auto member : cc.members_) { for (auto member : cc.members_) {
...@@ -123,7 +175,8 @@ static std::string dump_cc_json(const CongruenceClass &cc) { ...@@ -123,7 +175,8 @@ static std::string dump_cc_json(const CongruenceClass &cc) {
return json; return json;
} }
static std::string dump_partition_json(const GVN::partitions &p) { static std::string
dump_partition_json(const GVN::partitions &p) {
std::string json; std::string json;
json += "["; json += "[";
for (auto cc : p) for (auto cc : p)
...@@ -132,7 +185,8 @@ static std::string dump_partition_json(const GVN::partitions &p) { ...@@ -132,7 +185,8 @@ static std::string dump_partition_json(const GVN::partitions &p) {
return json; return json;
} }
static std::string dump_bb2partition(const std::map<BasicBlock *, GVN::partitions> &map) { static std::string
dump_bb2partition(const std::map<BasicBlock *, GVN::partitions> &map) {
std::string json; std::string json;
json += "{"; json += "{";
for (auto [bb, p] : map) for (auto [bb, p] : map)
...@@ -142,7 +196,8 @@ static std::string dump_bb2partition(const std::map<BasicBlock *, GVN::partition ...@@ -142,7 +196,8 @@ static std::string dump_bb2partition(const std::map<BasicBlock *, GVN::partition
} }
// logging utility for you // logging utility for you
static void print_partitions(const GVN::partitions &p) { static void
print_partitions(const GVN::partitions &p) {
if (p.empty()) { if (p.empty()) {
LOG_DEBUG << "empty partitions\n"; LOG_DEBUG << "empty partitions\n";
return; return;
...@@ -154,53 +209,166 @@ static void print_partitions(const GVN::partitions &p) { ...@@ -154,53 +209,166 @@ static void print_partitions(const GVN::partitions &p) {
} }
} // namespace utils } // namespace utils
GVN::partitions GVN::join(const partitions &P1, const partitions &P2) { GVN::partitions
GVN::join(const partitions &P1, const partitions &P2) {
// TODO: do intersection pair-wise // TODO: do intersection pair-wise
return {}; partitions P{};
for (auto c1 : P1)
for (auto c2 : P2) {
auto c = intersect(c1, c2);
if (c->members_.empty())
continue;
P.insert(c);
}
return P;
} }
std::shared_ptr<CongruenceClass> GVN::intersect(std::shared_ptr<CongruenceClass> Ci, std::shared_ptr<CongruenceClass>
std::shared_ptr<CongruenceClass> Cj) { GVN::intersect(std::shared_ptr<CongruenceClass> ci,
std::shared_ptr<CongruenceClass> cj) {
// TODO // TODO
return {}; // If no common members, return null
auto c = createCongruenceClass();
std::set<Value *> intersection;
std::set_intersection(ci->members_.begin(),
ci->members_.end(),
cj->members_.begin(),
cj->members_.end(),
std::inserter(intersection, intersection.begin()));
c->members_ = intersection;
if (ci->index_ == cj->index_)
c->index_ = ci->index_;
if (ci->leader_ == cj->leader_)
c->leader_ = cj->leader_;
/* if (*ci == *cj)
* return ci; */
return c;
} }
void GVN::detectEquivalences() { void
bool changed = false; GVN::detectEquivalences() {
bool changed;
// initialize pout with top // initialize pout with top
for (auto &bb : func_->get_basic_blocks()) {
// pin_[&bb].clear();
// pout_[&bb].clear();
for (auto &instr : bb.get_instructions())
_TOP[&instr] = true;
}
// modify entry block
auto Entry = func_->get_entry_block();
_TOP[&*Entry->get_instructions().begin()] = false;
pin_[Entry].clear();
pout_[Entry].clear(); // pout_[Entry] = transferFunction(Entry);
// iterate until converge // iterate until converge
do { do {
changed = false;
// see the pseudo code in documentation // see the pseudo code in documentation
for (auto &bb : func_->get_basic_blocks()) { // you might need to visit the blocks in depth-first order for (auto &_bb :
func_->get_basic_blocks()) { // you might need to visit the
// blocks in depth-first order
auto bb = &_bb;
// get PIN of bb by predecessor(s) // get PIN of bb by predecessor(s)
auto pre_bbs_ = bb->get_pre_basic_blocks();
if (bb != Entry) {
// only update PIN for blocks that are not Entry
// that is: the PIN for entry is always empty
switch (pre_bbs_.size()) {
case 2: {
auto pre_1 = *pre_bbs_.begin();
auto pre_2 = *(++pre_bbs_.begin());
pin_[bb] = join(pin_[pre_1], pin_[pre_2]);
break;
}
case 1: {
auto pre = *(pre_bbs_.begin());
pin_[bb] = clone(pin_[pre]);
break;
}
default:
LOG_ERROR << "block has count of predecessors: "
<< pre_bbs_.size();
abort();
}
}
auto part = pin_[bb];
// iterate through all instructions in the block // iterate through all instructions in the block
for (auto &instr : bb->get_instructions()) {
// ??
if (not instr.is_phi())
part = transferFunction(&instr, instr.get_operand(1), part);
}
// and the phi instruction in all the successors // and the phi instruction in all the successors
for (auto succ : bb->get_succ_basic_blocks()) {
for (auto &instr : succ->get_instructions())
if (instr.is_phi()) {
Instruction *pretend;
// ??
part = transferFunction(
pretend, instr.get_operand(1), part);
}
}
// check changes in pout // check changes in pout
changed |= not(part == pout_[bb]);
pout_[bb] = part;
} }
} while (changed); } while (changed);
} }
shared_ptr<Expression> GVN::valueExpr(Instruction *instr) { shared_ptr<Expression>
GVN::valueExpr(Instruction *instr) {
// TODO // TODO
return {}; return {};
} }
// instruction of the form `x = e`, mostly x is just e (SSA), but for copy stmt x is a phi instruction in the // instruction of the form `x = e`, mostly x is just e (SSA),
// successor. Phi values (not copy stmt) should be handled in detectEquiv // but for copy stmt x is a phi instruction in the successor.
// Phi values (not copy stmt) should be handled in detectEquiv
/// \param bb basic block in which the transfer function is called /// \param bb basic block in which the transfer function is called
GVN::partitions GVN::transferFunction(Instruction *x, Value *e, partitions pin) { GVN::partitions
GVN::transferFunction(Instruction *x, Value *e, partitions pin) {
partitions pout = clone(pin); partitions pout = clone(pin);
// TODO: get different ValueExpr by Instruction::OpID, modify pout // TODO: get different ValueExpr by Instruction::OpID, modify pout
std::set<Value *>::iterator iter;
for (auto c : pout) {
if ((iter = std::find(c->members_.begin(), c->members_.end(), x)) !=
c->members_.end()) {
// static_cast<Value *>(x))) != c->members_.end()) {
c->members_.erase(iter);
}
}
auto ve = valueExpr(x);
auto vpf = valuePhiFunc(ve, pin);
/* pout.insert({});
* auto c = CongruenceClass(new_number());
* c.leader_ = e; */
return pout; return pout;
} }
shared_ptr<PhiExpression> GVN::valuePhiFunc(shared_ptr<Expression> ve, const partitions &P) { GVN::partitions
GVN::transferFunction(BasicBlock *bb) {
partitions pout = clone(pin_[bb]);
// ??
return pout;
}
shared_ptr<PhiExpression>
GVN::valuePhiFunc(shared_ptr<Expression> ve, const partitions &P) {
// TODO // TODO
return {}; return {};
} }
shared_ptr<Expression> GVN::getVN(const partitions &pout, shared_ptr<Expression> ve) { shared_ptr<Expression>
GVN::getVN(const partitions &pout, shared_ptr<Expression> ve) {
// TODO: return what? // TODO: return what?
for (auto it = pout.begin(); it != pout.end(); it++) for (auto it = pout.begin(); it != pout.end(); it++)
if ((*it)->value_expr_ and *(*it)->value_expr_ == *ve) if ((*it)->value_expr_ and *(*it)->value_expr_ == *ve)
...@@ -208,30 +376,40 @@ shared_ptr<Expression> GVN::getVN(const partitions &pout, shared_ptr<Expression> ...@@ -208,30 +376,40 @@ shared_ptr<Expression> GVN::getVN(const partitions &pout, shared_ptr<Expression>
return nullptr; return nullptr;
} }
void GVN::initPerFunction() { void
GVN::initPerFunction() {
next_value_number_ = 1; next_value_number_ = 1;
pin_.clear(); pin_.clear();
pout_.clear(); pout_.clear();
} }
void GVN::replace_cc_members() { void
GVN::replace_cc_members() {
for (auto &[_bb, part] : pout_) { for (auto &[_bb, part] : pout_) {
auto bb = _bb; // workaround: structured bindings can't be captured in C++17 auto bb =
_bb; // workaround: structured bindings can't be captured in C++17
for (auto &cc : part) { for (auto &cc : part) {
if (cc->index_ == 0) if (cc->index_ == 0)
continue; continue;
// if you are planning to do constant propagation, leaders should be set to constant at some point // if you are planning to do constant propagation, leaders should be
// set to constant at some point
for (auto &member : cc->members_) { for (auto &member : cc->members_) {
bool member_is_phi = dynamic_cast<PhiInst *>(member); bool member_is_phi = dynamic_cast<PhiInst *>(member);
bool value_phi = cc->value_phi_ != nullptr; bool value_phi = cc->value_phi_ != nullptr;
if (member != cc->leader_ and (value_phi or !member_is_phi)) { if (member != cc->leader_ and (value_phi or !member_is_phi)) {
// only replace the members if users are in the same block as bb // only replace the members if users are in the same block
member->replace_use_with_when(cc->leader_, [bb](User *user) { // as bb
if (auto instr = dynamic_cast<Instruction *>(user)) { member->replace_use_with_when(
cc->leader_, [bb](User *user) {
if (auto instr =
dynamic_cast<Instruction *>(user)) {
auto parent = instr->get_parent(); auto parent = instr->get_parent();
auto &bb_pre = parent->get_pre_basic_blocks(); auto &bb_pre = parent->get_pre_basic_blocks();
if (instr->is_phi()) // as copy stmt, the phi belongs to this block if (instr->is_phi()) // as copy stmt, the phi
return std::find(bb_pre.begin(), bb_pre.end(), bb) != bb_pre.end(); // belongs to this block
return std::find(bb_pre.begin(),
bb_pre.end(),
bb) != bb_pre.end();
else else
return parent == bb; return parent == bb;
} }
...@@ -245,7 +423,8 @@ void GVN::replace_cc_members() { ...@@ -245,7 +423,8 @@ void GVN::replace_cc_members() {
} }
// top-level function, done for you // top-level function, done for you
void GVN::run() { void
GVN::run() {
std::ofstream gvn_json; std::ofstream gvn_json;
if (dump_json_) { if (dump_json_) {
gvn_json.open("gvn.json", std::ios::out); gvn_json.open("gvn.json", std::ios::out);
...@@ -267,13 +446,15 @@ void GVN::run() { ...@@ -267,13 +446,15 @@ void GVN::run() {
detectEquivalences(); detectEquivalences();
LOG_INFO << "===============pin=========================\n"; LOG_INFO << "===============pin=========================\n";
for (auto &[bb, part] : pin_) { for (auto &[bb, part] : pin_) {
LOG_INFO << "\n===============bb: " << bb->get_name() << "=========================\npartitionIn: "; LOG_INFO << "\n===============bb: " << bb->get_name()
<< "=========================\npartitionIn: ";
for (auto &cc : part) for (auto &cc : part)
LOG_INFO << utils::print_congruence_class(*cc); LOG_INFO << utils::print_congruence_class(*cc);
} }
LOG_INFO << "\n===============pout=========================\n"; LOG_INFO << "\n===============pout=========================\n";
for (auto &[bb, part] : pout_) { for (auto &[bb, part] : pout_) {
LOG_INFO << "\n=====bb: " << bb->get_name() << "=====\npartitionOut: "; LOG_INFO << "\n=====bb: " << bb->get_name()
<< "=====\npartitionOut: ";
for (auto &cc : part) for (auto &cc : part)
LOG_INFO << utils::print_congruence_class(*cc); LOG_INFO << utils::print_congruence_class(*cc);
} }
...@@ -291,12 +472,15 @@ void GVN::run() { ...@@ -291,12 +472,15 @@ void GVN::run() {
} }
template <typename T> template <typename T>
static bool equiv_as(const Expression &lhs, const Expression &rhs) { static bool
// we use static_cast because we are very sure that both operands are actually T, not other types. equiv_as(const Expression &lhs, const Expression &rhs) {
// we use static_cast because we are very sure that both operands are
// actually T, not other types.
return static_cast<const T *>(&lhs)->equiv(static_cast<const T *>(&rhs)); return static_cast<const T *>(&lhs)->equiv(static_cast<const T *>(&rhs));
} }
bool GVNExpression::operator==(const Expression &lhs, const Expression &rhs) { bool
GVNExpression::operator==(const Expression &lhs, const Expression &rhs) {
if (lhs.get_expr_type() != rhs.get_expr_type()) if (lhs.get_expr_type() != rhs.get_expr_type())
return false; return false;
switch (lhs.get_expr_type()) { switch (lhs.get_expr_type()) {
...@@ -309,13 +493,17 @@ bool GVNExpression::operator==(const Expression &lhs, const Expression &rhs) { ...@@ -309,13 +493,17 @@ bool GVNExpression::operator==(const Expression &lhs, const Expression &rhs) {
} }
} }
bool GVNExpression::operator==(const shared_ptr<Expression> &lhs, const shared_ptr<Expression> &rhs) { bool
if (lhs == nullptr and rhs == nullptr) // is the nullptr check necessary here? GVNExpression::operator==(const shared_ptr<Expression> &lhs,
const shared_ptr<Expression> &rhs) {
if (lhs == nullptr and
rhs == nullptr) // is the nullptr check necessary here?
return true; return true;
return lhs and rhs and *lhs == *rhs; return lhs and rhs and *lhs == *rhs;
} }
GVN::partitions GVN::clone(const partitions &p) { GVN::partitions
GVN::clone(const partitions &p) {
partitions data; partitions data;
for (auto &cc : p) { for (auto &cc : p) {
data.insert(std::make_shared<CongruenceClass>(*cc)); data.insert(std::make_shared<CongruenceClass>(*cc));
...@@ -323,12 +511,18 @@ GVN::partitions GVN::clone(const partitions &p) { ...@@ -323,12 +511,18 @@ GVN::partitions GVN::clone(const partitions &p) {
return data; return data;
} }
bool operator==(const GVN::partitions &p1, const GVN::partitions &p2) { bool
operator==(const GVN::partitions &p1, const GVN::partitions &p2) {
// TODO: how to compare partitions? // TODO: how to compare partitions?
// cannot direct compare???
if (p1.size() != p2.size())
return false; return false;
return std::equal(p1.begin(), p1.end(), p2.begin(), p2.end());
} }
bool CongruenceClass::operator==(const CongruenceClass &other) const { // only compare index
bool
CongruenceClass::operator==(const CongruenceClass &other) const {
// TODO: which fields need to be compared? // TODO: which fields need to be compared?
return false; return index_ == other.index_;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment