[ast] laying down the ground work for on-the-fly phi-node simplification
This commit is contained in:
@@ -23,7 +23,7 @@ void test(fp32 *A, fp32 *B, fp32 *C, int32 i){\
|
||||
int32 j = 1;\
|
||||
int32 k;\
|
||||
i = i + j;\
|
||||
for(k = 0; k < 10; k = k+1){\
|
||||
for(k = 0; k < 10; k = k+5){\
|
||||
int32 u = 1;\
|
||||
u = u + i;\
|
||||
if(k == 0)\
|
||||
|
@@ -187,7 +187,9 @@ void lowering(ir::module &src, Module &dst){
|
||||
for(unsigned i = 0; i < phi->get_num_incoming(); i++){
|
||||
ir::value *inc_val = phi->get_incoming_value(i);
|
||||
ir::basic_block *inc_block = phi->get_incoming_block(i);
|
||||
dst_phi->addIncoming(vmap[inc_val], bmap[inc_block]);
|
||||
Value *llvm_inc_val = llvm_value(inc_val, dst_ctx, vmap, bmap);
|
||||
BasicBlock *llvm_block = bmap[inc_block];
|
||||
dst_phi->addIncoming(llvm_inc_val, llvm_block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -30,6 +30,7 @@ public:
|
||||
|
||||
private:
|
||||
phi_node *make_phi(type *ty, unsigned num_values, basic_block *block);
|
||||
value *try_remove_trivial_phis(ir::phi_node *&phi);
|
||||
value *add_phi_operands(const std::string& name, phi_node *&phi);
|
||||
value *get_value_recursive(const std::string& name, basic_block *block);
|
||||
void push_function(function *fn) { functions_.push_back(fn); }
|
||||
|
@@ -10,6 +10,7 @@ namespace ir{
|
||||
|
||||
class type;
|
||||
class use;
|
||||
class user;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// value class
|
||||
@@ -21,7 +22,9 @@ public:
|
||||
value(type *ty, const std::string &name = "");
|
||||
virtual ~value(){ }
|
||||
// uses
|
||||
void add_use(use *arg);
|
||||
void add_use(use arg);
|
||||
const std::vector<use> &get_uses() { return uses_; }
|
||||
virtual void replace_all_uses_with(value *target);
|
||||
// name
|
||||
void set_name(const std::string &name);
|
||||
const std::string &get_name() const { return name_; }
|
||||
@@ -30,6 +33,9 @@ public:
|
||||
private:
|
||||
type *ty_;
|
||||
std::string name_;
|
||||
|
||||
protected:
|
||||
std::vector<use> uses_;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -78,6 +84,9 @@ public:
|
||||
value *get_operand(unsigned i);
|
||||
unsigned get_num_operands() const ;
|
||||
|
||||
// Utils
|
||||
void replace_all_uses_with(value *target);
|
||||
|
||||
private:
|
||||
std::vector<use> ops_;
|
||||
};
|
||||
|
@@ -105,7 +105,6 @@ ir::value* function_definition::codegen(ir::module *mod) const{
|
||||
mod->seal_block(entry);
|
||||
mod->get_builder().set_insert_point(entry);
|
||||
body_->codegen(mod);
|
||||
std::cout << mod->get_builder().get_insert_block()->get_name() << std::endl;
|
||||
mod->get_builder().create_ret_void();
|
||||
return nullptr;
|
||||
}
|
||||
|
@@ -26,7 +26,9 @@ instruction::instruction(type *ty, unsigned num_ops, const std::string &name, in
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
phi_node::phi_node(type *ty, unsigned num_reserved, std::string const &name, instruction *next)
|
||||
: instruction(ty, num_reserved, name, next), blocks_(num_reserved){ }
|
||||
: instruction(ty, 0, name, next) {
|
||||
blocks_.reserve(num_reserved);
|
||||
}
|
||||
|
||||
// Set incoming value
|
||||
void phi_node::set_incoming_value(unsigned i, value *v){
|
||||
@@ -44,11 +46,8 @@ void phi_node::set_incoming_block(unsigned i, basic_block *block){
|
||||
|
||||
// Add incoming
|
||||
void phi_node::add_incoming(value *v, basic_block *block){
|
||||
if(get_num_operands()==num_reserved_){
|
||||
num_reserved_++;
|
||||
resize_ops(num_reserved_);
|
||||
blocks_.resize(num_reserved_);
|
||||
}
|
||||
resize_ops(get_num_operands() + 1);
|
||||
blocks_.resize(get_num_operands() + 1);
|
||||
set_incoming_value(get_num_operands() - 1, v);
|
||||
set_incoming_block(get_num_operands() - 1, block);
|
||||
}
|
||||
|
@@ -39,13 +39,34 @@ ir::phi_node* module::make_phi(ir::type *ty, unsigned num_values, ir::basic_bloc
|
||||
return res;
|
||||
}
|
||||
|
||||
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();
|
||||
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);
|
||||
return same;
|
||||
}
|
||||
|
||||
ir::value *module::add_phi_operands(const std::string& name, ir::phi_node *&phi){
|
||||
ir::basic_block *block = phi->get_parent();
|
||||
for(ir::basic_block *pred: block->get_predecessors()){
|
||||
ir::value *value = get_value(name, pred);
|
||||
phi->add_incoming(value, pred);
|
||||
}
|
||||
return phi;
|
||||
return try_remove_trivial_phis(phi);
|
||||
}
|
||||
|
||||
ir::value *module::get_value_recursive(const std::string& name, ir::basic_block *block) {
|
||||
|
@@ -14,17 +14,26 @@ value::value(type *ty, const std::string &name): ty_(ty){
|
||||
set_name(name);
|
||||
}
|
||||
|
||||
void value::add_use(use arg) {
|
||||
uses_.push_back(arg);
|
||||
}
|
||||
|
||||
// TODO: automatic naming scheme + update symbol table
|
||||
void value::set_name(const std::string &name){
|
||||
name_ = name;
|
||||
}
|
||||
|
||||
void value::replace_all_uses_with(value *target){
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// use class
|
||||
//===----------------------------------------------------------------------===//
|
||||
void use::set(value *val){
|
||||
val_ = val;
|
||||
val_->add_use(*this);
|
||||
}
|
||||
|
||||
value *use::operator=(value *rhs){
|
||||
@@ -40,19 +49,25 @@ const use &use::operator=(const use &rhs){
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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!");
|
||||
ops_[i] = x;
|
||||
}
|
||||
|
||||
value* user::get_operand(unsigned i){
|
||||
value* user::get_operand(unsigned i) {
|
||||
assert(i < ops_.size() && "get_operand() out of range!");
|
||||
return ops_[i];
|
||||
}
|
||||
|
||||
unsigned user::get_num_operands() const{
|
||||
unsigned user::get_num_operands() const {
|
||||
return ops_.size();
|
||||
}
|
||||
|
||||
void user::replace_all_uses_with(value *target) {
|
||||
for(use &u: uses_){
|
||||
u.set(target);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user