[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);
|
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);
|
||||||
|
@@ -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(); }
|
||||||
|
@@ -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_;
|
||||||
|
@@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -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++)
|
||||||
|
@@ -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
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user