[syntax tree] trivial phi-node elimination
This commit is contained in:
@@ -139,8 +139,8 @@ Value* llvm_value(ir::value *v, LLVMContext &ctx,
|
||||
return vmap.at(v);
|
||||
// create operands
|
||||
if(auto *uu = dynamic_cast<ir::user*>(v))
|
||||
for(ir::use u: uu->ops()){
|
||||
vmap[u.get()] = llvm_value(u, ctx, vmap, bmap);
|
||||
for(ir::value* u: uu->ops()){
|
||||
vmap[u] = llvm_value(u, ctx, vmap, bmap);
|
||||
}
|
||||
if(auto *cc = dynamic_cast<ir::constant*>(v))
|
||||
return llvm_constant(cc, ctx);
|
||||
|
@@ -36,6 +36,7 @@ public:
|
||||
|
||||
// get instruction list
|
||||
inst_list_t &get_inst_list() { return inst_list_; }
|
||||
void erase(instruction *i) { inst_list_.remove(i); }
|
||||
|
||||
// instruction iterator functions
|
||||
inline iterator begin() { return inst_list_.begin(); }
|
||||
|
@@ -21,11 +21,11 @@ protected:
|
||||
instruction(type *ty, unsigned num_ops, const std::string &name = "", instruction *next = nullptr);
|
||||
|
||||
public:
|
||||
|
||||
// parent
|
||||
void set_parent(basic_block *block) { parent_ = block; }
|
||||
const basic_block *get_parent() const { return parent_; }
|
||||
basic_block *get_parent() { return parent_; }
|
||||
void erase_from_parent();
|
||||
|
||||
private:
|
||||
basic_block *parent_;
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
namespace tdl{
|
||||
namespace ir{
|
||||
@@ -22,8 +23,9 @@ public:
|
||||
value(type *ty, const std::string &name = "");
|
||||
virtual ~value(){ }
|
||||
// uses
|
||||
void add_use(use arg);
|
||||
const std::vector<use> &get_uses() { return uses_; }
|
||||
void add_use(user* arg);
|
||||
unsigned erase_use(user* arg);
|
||||
const std::set<user*> &get_users() { return users_; }
|
||||
virtual void replace_all_uses_with(value *target);
|
||||
// name
|
||||
void set_name(const std::string &name);
|
||||
@@ -35,27 +37,7 @@ private:
|
||||
std::string name_;
|
||||
|
||||
protected:
|
||||
std::vector<use> uses_;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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_;
|
||||
std::set<user*> users_;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -64,7 +46,7 @@ private:
|
||||
|
||||
class user: public value{
|
||||
public:
|
||||
typedef std::vector<use> ops_t;
|
||||
typedef std::vector<value*> ops_t;
|
||||
typedef ops_t::iterator op_iterator;
|
||||
typedef ops_t::const_iterator const_op_iterator;
|
||||
|
||||
@@ -77,7 +59,7 @@ public:
|
||||
: value(ty, name), ops_(num_ops){ }
|
||||
|
||||
// Operands
|
||||
const std::vector<use>& ops() { return ops_; }
|
||||
const ops_t& ops() { return ops_; }
|
||||
op_iterator op_begin() { return ops_.begin(); }
|
||||
op_iterator op_end() { return ops_.end(); }
|
||||
void set_operand(unsigned i, value *x);
|
||||
@@ -89,7 +71,7 @@ public:
|
||||
void replace_uses_of_with(value *before, value *after);
|
||||
|
||||
private:
|
||||
std::vector<use> ops_;
|
||||
ops_t ops_;
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -23,6 +23,8 @@ void basic_block::add_predecessor(basic_block *pred) {
|
||||
preds_.push_back(pred);
|
||||
}
|
||||
|
||||
|
||||
|
||||
basic_block::iterator basic_block::get_first_non_phi(){
|
||||
auto it = begin();
|
||||
for(; it != end(); it++)
|
||||
|
@@ -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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@@ -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 *same = nullptr;
|
||||
for(ir::value *op: phi->ops()){
|
||||
// unique value or self-reference
|
||||
if(op == same || op == phi)
|
||||
continue;
|
||||
// the phi-node merges at least two values; non-trivial
|
||||
if(same)
|
||||
return phi;
|
||||
same = op;
|
||||
}
|
||||
assert(same && "the phi-node is unreachable or in the start block");
|
||||
std::vector<ir::use> uses = phi->get_uses();
|
||||
// find non-self references
|
||||
std::vector<ir::value*> non_self_ref;
|
||||
std::copy_if(phi->ops().begin(), phi->ops().end(), std::back_inserter(non_self_ref),
|
||||
[phi](ir::value* op){ return op != phi; });
|
||||
// non-trivial
|
||||
if(non_self_ref.size() > 1)
|
||||
return phi;
|
||||
// unique value or self-reference
|
||||
ir::value *same = non_self_ref[0];
|
||||
std::set<ir::user*> users = phi->get_users();
|
||||
phi->replace_all_uses_with(same);
|
||||
for(ir::use &u: uses)
|
||||
if(auto *uphi = dynamic_cast<ir::phi_node*>(u.get()))
|
||||
if(uphi != phi)
|
||||
try_remove_trivial_phis(uphi);
|
||||
phi->erase_from_parent();
|
||||
for(ir::user* u: users)
|
||||
if(auto *uphi = dynamic_cast<ir::phi_node*>(u))
|
||||
if(uphi != phi)
|
||||
try_remove_trivial_phis(uphi);
|
||||
return same;
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#include "ir/value.h"
|
||||
#include "ir/instructions.h"
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
@@ -15,8 +16,12 @@ value::value(type *ty, const std::string &name): ty_(ty){
|
||||
set_name(name);
|
||||
}
|
||||
|
||||
void value::add_use(use arg) {
|
||||
uses_.push_back(arg);
|
||||
void value::add_use(user *arg) {
|
||||
users_.insert(arg);
|
||||
}
|
||||
|
||||
unsigned value::erase_use(user *arg){
|
||||
return users_.erase(arg);
|
||||
}
|
||||
|
||||
// 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
|
||||
//===----------------------------------------------------------------------===//
|
||||
void user::set_operand(unsigned i, value *x) {
|
||||
assert(i < ops_.size() && "set_operand() out of range!");
|
||||
ops_[i] = x;
|
||||
x->add_use(this);
|
||||
}
|
||||
|
||||
value* user::get_operand(unsigned i) {
|
||||
@@ -65,17 +53,17 @@ unsigned user::get_num_operands() const {
|
||||
}
|
||||
|
||||
void user::replace_all_uses_with(value *target) {
|
||||
for(use &u: uses_)
|
||||
if(auto *usr = dynamic_cast<user*>(u.get())){
|
||||
std::cout << "replacing " << this << " by " << target << " in " << usr << std::endl;
|
||||
usr->replace_uses_of_with(this, target);
|
||||
for(auto it = users_.begin(); it != users_.end();){
|
||||
(*it)->replace_uses_of_with(this, target);
|
||||
target->add_use(*it);
|
||||
erase_use(*it++);
|
||||
}
|
||||
}
|
||||
|
||||
void user::replace_uses_of_with(value *before, value *after) {
|
||||
for(use &u: ops_)
|
||||
if(u.get() == before)
|
||||
u.set(after);
|
||||
for(size_t i = 0; i < ops_.size(); i++)
|
||||
if(ops_[i] == before)
|
||||
ops_[i] = after;
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user