diff --git a/include/optimization/GVN.h b/include/optimization/GVN.h index 9e0a82caf4ed5090557914e790a7165df3c46fc1..f4872d33136a450725eb8a3cb9e2d02630336826 100644 --- a/include/optimization/GVN.h +++ b/include/optimization/GVN.h @@ -69,6 +69,8 @@ class ConstantExpression : public Expression { } ConstantExpression(Constant *c) : Expression(e_constant), c_(c) {} + Constant *get_val() { return c_; } + private: Constant *c_; }; @@ -199,20 +201,24 @@ class GEPExpression : public Expression { // unique expression: not equal to any one else class UniqueExpression : public Expression { public: - static std::shared_ptr create(Instruction *instr) { - return std::make_shared(instr); + static std::shared_ptr create(Instruction *instr, + size_t index) { + return std::make_shared(instr, index); } - virtual std::string print() { return "(UNIQUE " + instr_->print() + ")"; } + // virtual std::string print() { return "(UNIQUE " + instr_->print() + ")"; + // } + virtual std::string print() { return "v" + std::to_string(index_); } bool equiv(const UniqueExpression *other) const { return instr_ == other->instr_; } - UniqueExpression(Instruction *instr) - : Expression(e_unique), instr_(instr) {} + UniqueExpression(Instruction *instr, size_t index) + : Expression(e_unique), instr_(instr), index_(index) {} private: Instruction *instr_; + size_t index_; }; } // namespace GVNExpression @@ -276,7 +282,8 @@ class GVN : public Pass { partitions transferFunction(BasicBlock *bb); std::shared_ptr valuePhiFunc( std::shared_ptr, - BasicBlock *bb); + BasicBlock *bb, + Instruction *instr); std::shared_ptr valueExpr( Instruction *instr, const partitions &part); @@ -308,6 +315,7 @@ class GVN : public Pass { std::map _TOP; partitions join_helper(BasicBlock *pre1, BasicBlock *pre2); BasicBlock *curr_bb; + std::map, size_t> start_idx_; // // self add function // @@ -317,11 +325,17 @@ class GVN : public Pass { Value *v, const partitions &part); - std::vector> core_( + std::vector> valueExpr_core_( Instruction *instr, const partitions &part, - size_t count, + const size_t count, bool fold_ = true); + Constant *constFold_core(const size_t count, + const partitions &part, + Instruction *instr, + const std::vector &operands); + void assign_start_idx_(); + void dump_tmp(Function &); }; bool operator==(const GVN::partitions &p1, const GVN::partitions &p2); diff --git a/src/optimization/GVN.cpp b/src/optimization/GVN.cpp index aee69a63ca5cbdc5e1521cfc1dd7734ecc010cc1..d53b95ff05d93f19c452524641138ff7de8d1ff0 100644 --- a/src/optimization/GVN.cpp +++ b/src/optimization/GVN.cpp @@ -199,6 +199,8 @@ dump_bb2partition(const std::map &map) { static void print_partitions(const GVN::partitions &p) { if (p.empty()) { + // to del + // std::cout << "empty partitions\n"; LOG_DEBUG << "empty partitions\n"; return; } @@ -206,13 +208,14 @@ print_partitions(const GVN::partitions &p) { for (auto &cc : p) log += print_congruence_class(*cc); LOG_DEBUG << log; // please don't use std::cout + // to del + // std::cout << log; } } // namespace utils GVN::partitions GVN::join_helper(BasicBlock *pre1, BasicBlock *pre2) { assert(not _TOP[pre1] or not _TOP[pre2] && "should flow here, not jump"); - if (_TOP[pre1]) return pout_[pre2]; else if (_TOP[pre2]) @@ -260,25 +263,70 @@ GVN::intersect(shared_ptr ci, shared_ptr cj) { if (c->members_.size()) // not empty { if (c->index_ == 0) { - c->index_ = new_number(); + // it must be a phi instruction + // and be separated to 2 copy statement + // we should use the copy-stmt int the previous block + auto instr = static_cast(*c->members_.begin()); + auto instr_phi = dynamic_cast(instr); + int exact_idx; + // trick here: use the exact value number + if (instr_phi) { + auto exact_pre_bb = + *(instr_phi->get_parent()->get_pre_basic_blocks().begin()); + auto e = instr_phi->get_operand( + pretend_copy_stmt(instr_phi, exact_pre_bb)); + exact_idx = start_idx_.at(std::make_pair(instr_phi, e)); + } else { + exact_idx = start_idx_.at(std::make_pair(instr, nullptr)); + } + c->index_ = exact_idx; c->value_expr_ = c->value_phi_ = PhiExpression::create(ci->value_expr_, cj->value_expr_); } + // ?? c->leader_ = *c->members_.begin(); } return c; } +// assign start index for each instruction, including copy statement +// ther logic here: +// - use the same traver order as main run +// - assign an incremental number for each instruction +void +GVN::assign_start_idx_() { + int res; + for (auto &bb : func_->get_basic_blocks()) { + for (auto &instr : bb.get_instructions()) { + if (not instr.is_phi() and not instr.is_void()) + start_idx_[std::make_pair(&instr, nullptr)] = new_number(); + } + // 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()) { + if ((res = pretend_copy_stmt(&instr, &bb)) == -1) + continue; + start_idx_[std::make_pair(&instr, instr.get_operand(res))] = + new_number(); + } + } + } + } + next_value_number_ = 1; +} + void GVN::detectEquivalences() { + int times = 0; bool changed; std::cout << "all the instruction address:" << std::endl; for (auto &bb : func_->get_basic_blocks()) { for (auto &instr : bb.get_instructions()) std::cout << &instr << "\t" << instr.print() << std::endl; } - + assign_start_idx_(); // initialize pout with top for (auto &bb : func_->get_basic_blocks()) { _TOP[&bb] = true; @@ -293,6 +341,7 @@ GVN::detectEquivalences() { // iterate until converge do { changed = false; + std::cout << ++times << "th iteration" << std::endl; for (auto &_bb : func_->get_basic_blocks()) { auto bb = &_bb; if (bb == Entry) @@ -306,12 +355,12 @@ GVN::detectEquivalences() { case 2: { auto pre_1 = *pre_bbs_.begin(); auto pre_2 = *(++pre_bbs_.begin()); - pin_[bb] = join_helper(pre_1, pre_2); + pin_[bb] = clone(join_helper(pre_1, pre_2)); break; } case 1: { auto pre = *(pre_bbs_.begin()); - pin_[bb] = pout_[pre]; + pin_[bb] = clone(pout_[pre]); break; } default: @@ -324,9 +373,15 @@ GVN::detectEquivalences() { // check changes in pout changed |= not(part == pout_[bb]); - pout_[bb] = part; + pout_[bb] = clone(part); _TOP[bb] = false; + + /* std::cout << "//-------\n" + * << "//after transferFunction(basic-block=" + * << bb->get_name() << "), all pout:" << std::endl; */ + // dump_tmp(*func_); } + // reset value number } while (changed); } @@ -343,12 +398,52 @@ GVN::search_ve(Value *v, const GVN::partitions &part) { return nullptr; } +// try constant fold for `count` operands +// the related instr is `instr` +Constant * +GVN::constFold_core(const size_t count, + const partitions &part, + Instruction *instr, + const std::vector &operands) { + assert(count == 1 or count == 2); + Constant *res = nullptr; + + // the first operand + auto op0_const_value = dynamic_cast(operands[0]); + auto op0_search_ = search_ve(operands[0], part); + auto op0_const_expr = + op0_search_ ? dynamic_cast(op0_search_.get()) + : nullptr; + if ((op0_const_value or op0_const_expr)) { + auto op0_const = + op0_const_value ? op0_const_value : op0_const_expr->get_val(); + // by now: the type cast instruction can do constant fold + if (count == 1) + res = folder_->compute(instr, op0_const); + if (count == 2) { + // the second operand + auto op1_const_value = dynamic_cast(operands[1]); + auto op1_search_ = search_ve(operands[1], part); + auto op1_const_expr = + op1_search_ + ? dynamic_cast(op1_search_.get()) + : nullptr; + if (op1_const_value or op1_const_expr) { + auto op1_const = op1_const_value ? op1_const_value + : op1_const_expr->get_val(); + res = folder_->compute(instr, op0_const, op1_const); + } + } + } + return res; +} + // for each op, try to find the std::vector> -GVN::core_(Instruction *instr, - const partitions &part, - size_t count, - bool fold_) { +GVN::valueExpr_core_(Instruction *instr, + const partitions &part, + const size_t count, + bool fold_) { assert(not(fold_ and count > 2)); Value *v; @@ -357,22 +452,12 @@ GVN::core_(Instruction *instr, std::vector> ret; // if able to fold, then fold - fold_ &= bool(dynamic_cast(operands[0])); - if (count == 2) - fold_ &= bool(dynamic_cast(operands[1])); if (fold_) { - Constant *res; - if (count == 1) { - res = - folder_->compute(instr, dynamic_cast(operands[0])); - } else { - // count == 2 - res = folder_->compute(instr, - dynamic_cast(operands[0]), - dynamic_cast(operands[1])); + Constant *res = nullptr; + if ((res = constFold_core(count, part, instr, operands))) { + ret.push_back(ConstantExpression::create(res)); + return ret; } - ret.push_back(ConstantExpression::create(res)); - return ret; } // normal case: @@ -405,7 +490,7 @@ GVN::valueExpr(Instruction *instr, const partitions &part) { return tmp; if (instr->isBinary() or instr->is_cmp() or instr->is_fcmp()) { - res = core_(instr, part, 2); + res = valueExpr_core_(instr, part, 2); if (res.size() == 1) // constant fold return res[0]; else @@ -414,7 +499,7 @@ GVN::valueExpr(Instruction *instr, const partitions &part) { } else if (instr->is_phi()) { err = "phi"; } else if (instr->is_fp2si() or instr->is_si2fp() or instr->is_zext()) { - res = core_(instr, part, 1); + res = valueExpr_core_(instr, part, 1); if (res[0]->get_expr_type() == Expression::e_constant) return res[0]; Type *dest_type; @@ -439,12 +524,16 @@ GVN::valueExpr(Instruction *instr, const partitions &part) { instr->get_instr_type(), res[0], dest_type); } } else if (instr->is_gep()) { - res = core_(instr, part, instr->get_operands().size(), false); + res = valueExpr_core_(instr, part, instr->get_operands().size(), false); auto ptr = res[0]; res.erase(res.begin()); return GEPExpression::create(ptr, res); } else if (instr->is_load() or instr->is_alloca() or instr->is_call()) { - return UniqueExpression::create(instr); + auto ret = search_ve(instr, part); + if (ret) + return ret; + else + return UniqueExpression::create(instr, next_value_number_); } std::cerr << "Undefined case: " << err << std::endl; @@ -459,8 +548,10 @@ GVN::valueExpr(Instruction *instr, const partitions &part) { // /// \param bb basic block in which the transfer function is called GVN::partitions -GVN::transferFunction(Instruction *x, Value *e, partitions pin) { - partitions pout = pin; +GVN::transferFunction(Instruction *instr, Value *e, partitions pin) { + next_value_number_ = start_idx_[std::make_pair(instr, e)]; + + partitions pout = clone(pin); // TODO: deal with copy-stmt case // ?? deal with copy statement auto e_instr = dynamic_cast(e); @@ -469,10 +560,13 @@ GVN::transferFunction(Instruction *x, Value *e, partitions pin) { "A value must be from an instruction or constant"); // erase the old record for x std::set::iterator it; - for (auto c : pin) - if ((it = std::find(c->members_.begin(), c->members_.end(), x)) != + for (auto c : pout) + if ((it = std::find(c->members_.begin(), c->members_.end(), instr)) != c->members_.end()) { c->members_.erase(it); + if (c->members_.empty()) + pout.erase(c); + break; } // TODO: get different ValueExpr by Instruction::OpID, modify pout @@ -483,25 +577,29 @@ GVN::transferFunction(Instruction *x, Value *e, partitions pin) { if (e_const) ve = ConstantExpression::create(e_const); else - ve = valueExpr(e_instr, pin); + ve = valueExpr(e_instr, pout); } else - ve = valueExpr(x, pin); - auto vpf = valuePhiFunc(ve, curr_bb); + ve = valueExpr(instr, pout); + auto vpf = valuePhiFunc(ve, curr_bb, instr); // TODO: set leader for (auto c : pout) { if (ve == c->value_expr_ or (vpf and c->value_phi_ and *vpf == *c->value_phi_)) { - c->value_expr_ = ve; - c->members_.insert(x); + // c->value_expr_ = ve; + c->members_.insert(instr); return pout; } } auto c = createCongruenceClass(new_number()); - c->members_.insert(x); - c->leader_ = x; + c->members_.insert(instr); c->value_expr_ = ve; c->value_phi_ = vpf; + if (c->value_expr_->get_expr_type() == Expression::e_constant) + c->leader_ = + static_cast(c->value_expr_.get())->get_val(); + else + c->leader_ = instr; pout.insert(c); return pout; } @@ -520,8 +618,6 @@ GVN::transferFunction(BasicBlock *bb) { * utils::print_partitions(pin_[bb]); * LOG_INFO << "pout before:\n"; * utils::print_partitions(pout_[bb]); */ - std::cout << "for basic block " << bb->get_name() << ", pin:" << std::endl; - utils::print_partitions(pin_[bb]); // iterate through all instructions in the block for (auto &instr : bb->get_instructions()) { @@ -539,39 +635,88 @@ GVN::transferFunction(BasicBlock *bb) { } } } - /* LOG_INFO << "pout after:\n"; - * utils::print_partitions(part); - * std::cout << std::endl; */ + std::cout << "-------\n" + << "for basic block " << bb->get_name() << ", pout:" << std::endl; + utils::print_partitions(part); return part; } +// NOTE: only instruction op matter shared_ptr -GVN::valuePhiFunc(shared_ptr ve, BasicBlock *bb) { +GVN::valuePhiFunc(shared_ptr ve, + BasicBlock *bb, + Instruction *instr) { // TODO + // get 2 predecessors + auto pre_bbs_ = bb->get_pre_basic_blocks(); + if (pre_bbs_.size() == 1) + return nullptr; + auto pre_1 = *pre_bbs_.begin(); + auto pre_2 = *(++pre_bbs_.begin()); + + // check expression form if (ve->get_expr_type() != Expression::e_bin) return nullptr; auto ve_bin = static_cast(ve.get()); - if (ve_bin->lhs_->get_expr_type() != Expression::e_phi or + if (ve_bin->lhs_->get_expr_type() != Expression::e_phi and ve_bin->rhs_->get_expr_type() != Expression::e_phi) return nullptr; + shared_ptr vi{}, vj{}; + shared_ptr vl_merge{}, vr_merge{}; + shared_ptr vl_merge_E{}, vr_merge_E{}; // get 2 phi expressions - auto lhs = static_cast(ve_bin->lhs_.get()); - auto rhs = static_cast(ve_bin->rhs_.get()); - // get 2 predecessors - auto pre_bbs_ = bb->get_pre_basic_blocks(); - auto pre_1 = *pre_bbs_.begin(); - auto pre_2 = *(++pre_bbs_.begin()); + auto lhs_phi = dynamic_cast(ve_bin->lhs_.get()); + auto rhs_phi = dynamic_cast(ve_bin->rhs_.get()); + + // set vl_merge and vr_merge + if (ve_bin->lhs_->get_expr_type() == Expression::e_phi and + ve_bin->rhs_->get_expr_type() == Expression::e_phi) { + // try to get the merged value expression + vl_merge = + BinaryExpression::create(ve_bin->op_, lhs_phi->lhs_, rhs_phi->lhs_); + vr_merge = + BinaryExpression::create(ve_bin->op_, lhs_phi->rhs_, rhs_phi->rhs_); + } else if (ve_bin->lhs_->get_expr_type() == Expression::e_phi) { + vl_merge = + BinaryExpression::create(ve_bin->op_, lhs_phi->lhs_, ve_bin->rhs_); + vr_merge = + BinaryExpression::create(ve_bin->op_, lhs_phi->rhs_, ve_bin->rhs_); + } else { + vl_merge = + BinaryExpression::create(ve_bin->op_, ve_bin->lhs_, rhs_phi->lhs_); + vr_merge = + BinaryExpression::create(ve_bin->op_, ve_bin->lhs_, rhs_phi->rhs_); + } + + // constant fold + if (vl_merge->lhs_->get_expr_type() == Expression::e_constant and + vl_merge->rhs_->get_expr_type() == Expression::e_constant) { + auto vl_merge_l = + dynamic_cast(vl_merge->lhs_.get()); + auto vl_merge_r = + dynamic_cast(vl_merge->rhs_.get()); + vl_merge_E = ConstantExpression::create(folder_->compute( + instr, vl_merge_l->get_val(), vl_merge_r->get_val())); + } else + vl_merge_E = vl_merge; + if (vr_merge->lhs_->get_expr_type() == Expression::e_constant and + vr_merge->rhs_->get_expr_type() == Expression::e_constant) { + auto vr_merge_l = + dynamic_cast(vr_merge->lhs_.get()); + auto vr_merge_r = + dynamic_cast(vr_merge->rhs_.get()); + vr_merge_E = ConstantExpression::create(folder_->compute( + instr, vr_merge_l->get_val(), vr_merge_r->get_val())); + } else + vr_merge_E = vr_merge; - // try to get the merged value expression - auto vl_merge = BinaryExpression::create(ve_bin->op_, lhs->lhs_, rhs->lhs_); - auto vr_merge = BinaryExpression::create(ve_bin->op_, lhs->rhs_, rhs->rhs_); - auto vi = getVN(pout_[pre_1], vl_merge); - auto vj = getVN(pout_[pre_2], vr_merge); + vi = getVN(pout_[pre_1], vl_merge_E); + vj = getVN(pout_[pre_2], vr_merge_E); if (vi == nullptr) - vi = valuePhiFunc(vl_merge, pre_1); + vi = valuePhiFunc(vl_merge_E, pre_1, instr); if (vj == nullptr) - vj = valuePhiFunc(vr_merge, pre_2); + vj = valuePhiFunc(vr_merge_E, pre_2, instr); if (vi and vj) return PhiExpression::create(vi, vj); @@ -688,6 +833,19 @@ GVN::run() { gvn_json << "]"; } +void +GVN::dump_tmp(Function &f) { + std::string gvn_json; + if (dump_json_) { + gvn_json += "{\n\"function\": "; + gvn_json += "\"" + f.get_name() + "\", "; + gvn_json += "\n\"pout\": " + utils::dump_bb2partition(pout_); + gvn_json += "},"; + } + gvn_json += "]"; + std::cout << gvn_json << std::endl; +} + template static bool equiv_as(const Expression &lhs, const Expression &rhs) { @@ -729,6 +887,7 @@ GVN::partitions GVN::clone(const partitions &p) { partitions data; for (auto &cc : p) { + assert(not cc->members_.empty()); data.insert(std::make_shared(*cc)); } return data; diff --git a/tests/4-ir-opt/testcases/GVN/functional/.gitignore b/tests/4-ir-opt/testcases/GVN/functional/.gitignore index fd645655007deecf92e33c8371dd762c0251d69a..f6bb428e4bd7d8c3b7cfa32afd694d7f2754c818 100644 --- a/tests/4-ir-opt/testcases/GVN/functional/.gitignore +++ b/tests/4-ir-opt/testcases/GVN/functional/.gitignore @@ -1 +1,4 @@ *.ll +*th +tmp* +gvn.json diff --git a/tests/4-ir-opt/testcases/GVN/functional/clear.sh b/tests/4-ir-opt/testcases/GVN/functional/clear.sh index ddad120f63075b1c150ebe7fbe5425d96a901420..b3835ba9ab44c6b4611c5b3376767fe09c377ee8 100755 --- a/tests/4-ir-opt/testcases/GVN/functional/clear.sh +++ b/tests/4-ir-opt/testcases/GVN/functional/clear.sh @@ -1,4 +1,5 @@ rm -rf *.ll rm -rf gvn.json rm -rf `ls | grep -v "\."` +rm -rf tmp*