[syntax tree] trivial phi-node elimination

This commit is contained in:
Philippe Tillet
2019-01-06 22:43:18 -05:00
parent 0dd4a52ce5
commit ce1c0a62c0
8 changed files with 49 additions and 72 deletions

View File

@@ -139,8 +139,8 @@ Value* llvm_value(ir::value *v, LLVMContext &ctx,
return vmap.at(v); return vmap.at(v);
// create operands // create operands
if(auto *uu = dynamic_cast<ir::user*>(v)) if(auto *uu = dynamic_cast<ir::user*>(v))
for(ir::use u: uu->ops()){ for(ir::value* u: uu->ops()){
vmap[u.get()] = llvm_value(u, ctx, vmap, bmap); vmap[u] = llvm_value(u, ctx, vmap, bmap);
} }
if(auto *cc = dynamic_cast<ir::constant*>(v)) if(auto *cc = dynamic_cast<ir::constant*>(v))
return llvm_constant(cc, ctx); return llvm_constant(cc, ctx);

View File

@@ -36,6 +36,7 @@ public:
// get instruction list // get instruction list
inst_list_t &get_inst_list() { return inst_list_; } inst_list_t &get_inst_list() { return inst_list_; }
void erase(instruction *i) { inst_list_.remove(i); }
// instruction iterator functions // instruction iterator functions
inline iterator begin() { return inst_list_.begin(); } inline iterator begin() { return inst_list_.begin(); }

View File

@@ -21,11 +21,11 @@ protected:
instruction(type *ty, unsigned num_ops, const std::string &name = "", instruction *next = nullptr); instruction(type *ty, unsigned num_ops, const std::string &name = "", instruction *next = nullptr);
public: public:
// parent // parent
void set_parent(basic_block *block) { parent_ = block; } void set_parent(basic_block *block) { parent_ = block; }
const basic_block *get_parent() const { return parent_; } const basic_block *get_parent() const { return parent_; }
basic_block *get_parent() { return parent_; } basic_block *get_parent() { return parent_; }
void erase_from_parent();
private: private:
basic_block *parent_; basic_block *parent_;

View File

@@ -4,6 +4,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <set>
namespace tdl{ namespace tdl{
namespace ir{ namespace ir{
@@ -22,8 +23,9 @@ public:
value(type *ty, const std::string &name = ""); value(type *ty, const std::string &name = "");
virtual ~value(){ } virtual ~value(){ }
// uses // uses
void add_use(use arg); void add_use(user* arg);
const std::vector<use> &get_uses() { return uses_; } unsigned erase_use(user* arg);
const std::set<user*> &get_users() { return users_; }
virtual void replace_all_uses_with(value *target); virtual void replace_all_uses_with(value *target);
// name // name
void set_name(const std::string &name); void set_name(const std::string &name);
@@ -35,27 +37,7 @@ private:
std::string name_; std::string name_;
protected: protected:
std::vector<use> uses_; std::set<user*> users_;
};
//===----------------------------------------------------------------------===//
// use class
//===----------------------------------------------------------------------===//
class use {
public:
// Implicit conversions to/from value
friend class value;
operator value *() const { return val_; }
value *get() const { return val_; }
value *operator->() { return val_; }
const value *operator->() const { return val_; }
inline void set(value *val);
inline value *operator=(value *rhs);
inline const use &operator=(const use &rhs);
private:
value *val_;
}; };
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@@ -64,7 +46,7 @@ private:
class user: public value{ class user: public value{
public: public:
typedef std::vector<use> ops_t; typedef std::vector<value*> ops_t;
typedef ops_t::iterator op_iterator; typedef ops_t::iterator op_iterator;
typedef ops_t::const_iterator const_op_iterator; typedef ops_t::const_iterator const_op_iterator;
@@ -77,7 +59,7 @@ public:
: value(ty, name), ops_(num_ops){ } : value(ty, name), ops_(num_ops){ }
// Operands // Operands
const std::vector<use>& ops() { return ops_; } const ops_t& ops() { return ops_; }
op_iterator op_begin() { return ops_.begin(); } op_iterator op_begin() { return ops_.begin(); }
op_iterator op_end() { return ops_.end(); } op_iterator op_end() { return ops_.end(); }
void set_operand(unsigned i, value *x); void set_operand(unsigned i, value *x);
@@ -89,7 +71,7 @@ public:
void replace_uses_of_with(value *before, value *after); void replace_uses_of_with(value *before, value *after);
private: private:
std::vector<use> ops_; ops_t ops_;
}; };
} }

View File

@@ -23,6 +23,8 @@ void basic_block::add_predecessor(basic_block *pred) {
preds_.push_back(pred); preds_.push_back(pred);
} }
basic_block::iterator basic_block::get_first_non_phi(){ basic_block::iterator basic_block::get_first_non_phi(){
auto it = begin(); auto it = begin();
for(; it != end(); it++) for(; it != end(); it++)

View File

@@ -21,6 +21,11 @@ instruction::instruction(type *ty, unsigned num_ops, const std::string &name, in
} }
} }
void instruction::erase_from_parent() {
parent_->erase(this);
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// phi_node classes // phi_node classes
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@@ -40,23 +40,22 @@ ir::phi_node* module::make_phi(ir::type *ty, unsigned num_values, ir::basic_bloc
} }
ir::value *module::try_remove_trivial_phis(ir::phi_node *&phi){ ir::value *module::try_remove_trivial_phis(ir::phi_node *&phi){
ir::value *same = nullptr; // find non-self references
for(ir::value *op: phi->ops()){ std::vector<ir::value*> non_self_ref;
// unique value or self-reference std::copy_if(phi->ops().begin(), phi->ops().end(), std::back_inserter(non_self_ref),
if(op == same || op == phi) [phi](ir::value* op){ return op != phi; });
continue; // non-trivial
// the phi-node merges at least two values; non-trivial if(non_self_ref.size() > 1)
if(same) return phi;
return phi; // unique value or self-reference
same = op; ir::value *same = non_self_ref[0];
} std::set<ir::user*> users = phi->get_users();
assert(same && "the phi-node is unreachable or in the start block");
std::vector<ir::use> uses = phi->get_uses();
phi->replace_all_uses_with(same); phi->replace_all_uses_with(same);
for(ir::use &u: uses) phi->erase_from_parent();
if(auto *uphi = dynamic_cast<ir::phi_node*>(u.get())) for(ir::user* u: users)
if(uphi != phi) if(auto *uphi = dynamic_cast<ir::phi_node*>(u))
try_remove_trivial_phis(uphi); if(uphi != phi)
try_remove_trivial_phis(uphi);
return same; return same;
} }

View File

@@ -1,4 +1,5 @@
#include "ir/value.h" #include "ir/value.h"
#include "ir/instructions.h"
#include <iostream> #include <iostream>
#include <cassert> #include <cassert>
@@ -15,8 +16,12 @@ value::value(type *ty, const std::string &name): ty_(ty){
set_name(name); set_name(name);
} }
void value::add_use(use arg) { void value::add_use(user *arg) {
uses_.push_back(arg); users_.insert(arg);
}
unsigned value::erase_use(user *arg){
return users_.erase(arg);
} }
// TODO: automatic naming scheme + update symbol table // TODO: automatic naming scheme + update symbol table
@@ -29,30 +34,13 @@ void value::replace_all_uses_with(value *target){
} }
//===----------------------------------------------------------------------===//
// use class
//===----------------------------------------------------------------------===//
void use::set(value *val){
val_ = val;
val_->add_use(*this);
}
value *use::operator=(value *rhs){
set(rhs);
return rhs;
}
const use &use::operator=(const use &rhs){
set(rhs.val_);
return rhs;
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// user class // user class
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
void user::set_operand(unsigned i, value *x) { void user::set_operand(unsigned i, value *x) {
assert(i < ops_.size() && "set_operand() out of range!"); assert(i < ops_.size() && "set_operand() out of range!");
ops_[i] = x; ops_[i] = x;
x->add_use(this);
} }
value* user::get_operand(unsigned i) { value* user::get_operand(unsigned i) {
@@ -65,17 +53,17 @@ unsigned user::get_num_operands() const {
} }
void user::replace_all_uses_with(value *target) { void user::replace_all_uses_with(value *target) {
for(use &u: uses_) for(auto it = users_.begin(); it != users_.end();){
if(auto *usr = dynamic_cast<user*>(u.get())){ (*it)->replace_uses_of_with(this, target);
std::cout << "replacing " << this << " by " << target << " in " << usr << std::endl; target->add_use(*it);
usr->replace_uses_of_with(this, target); erase_use(*it++);
} }
} }
void user::replace_uses_of_with(value *before, value *after) { void user::replace_uses_of_with(value *before, value *after) {
for(use &u: ops_) for(size_t i = 0; i < ops_.size(); i++)
if(u.get() == before) if(ops_[i] == before)
u.set(after); ops_[i] = after;
} }
} }