/***************************************************************************** Copyright (C) 2009-2011 University of Utah All Rights Reserved. Purpose: CHiLL's SUIF interface. Notes: Array supports mixed pointer and array type in a single declaration. History: 02/23/2009 Created by Chun Chen. *****************************************************************************/ #include #include #include "ir_suif.hh" #include "ir_suif_utils.hh" #include "chill_error.hh" // ---------------------------------------------------------------------------- // Class: IR_suifScalarSymbol // ---------------------------------------------------------------------------- std::string IR_suifScalarSymbol::name() const { return vs_->name(); } int IR_suifScalarSymbol::size() const { return vs_->type()->size(); } bool IR_suifScalarSymbol::operator==(const IR_Symbol &that) const { if (typeid(*this) != typeid(that)) return false; const IR_suifScalarSymbol *l_that = static_cast(&that); return this->vs_ == l_that->vs_; } IR_Symbol *IR_suifScalarSymbol::clone() const { return new IR_suifScalarSymbol(ir_, vs_); } // ---------------------------------------------------------------------------- // Class: IR_suifArraySymbol // ---------------------------------------------------------------------------- std::string IR_suifArraySymbol::name() const { return vs_->name(); } int IR_suifArraySymbol::elem_size() const { type_node *tn = vs_->type(); if (tn->is_modifier()) tn = static_cast(tn)->base(); while (tn->is_array()) tn = static_cast(tn)->elem_type(); return tn->size(); } int IR_suifArraySymbol::n_dim() const { type_node *tn = vs_->type(); if (tn->is_modifier()) tn = static_cast(tn)->base(); int n = 0; while (true) { if (tn->is_array()) { n++; tn = static_cast(tn)->elem_type(); } else if (tn->is_ptr()) { n++; tn = static_cast(tn)->ref_type(); } else break; } return n - indirect_; } omega::CG_outputRepr *IR_suifArraySymbol::size(int dim) const { type_node *tn = vs_->type(); if (tn->is_modifier()) tn = static_cast(tn)->base(); for (int i = 0; i < dim; i++) { if (tn->is_array()) tn = static_cast(tn)->elem_type(); else if (tn->is_ptr()) tn = static_cast(tn)->ref_type(); else throw ir_error("array parsing error"); } if (tn->is_ptr()) return new omega::CG_suifRepr(operand()); else if (!tn->is_array()) throw ir_error("array parsing error"); array_bound ub = static_cast(tn)->upper_bound(); int c = 1; omega::CG_outputRepr *ub_repr = NULL; if (ub.is_constant()) c += ub.constant(); else if (ub.is_variable()) { var_sym *vs = ub.variable(); if (static_cast(ir_)->init_code_ != NULL) { tree_node_list *tnl = static_cast(static_cast(ir_)->init_code_)->GetCode(); tree_node_list_iter iter(tnl); while(!iter.is_empty()) { tree_node *tn = iter.step(); if (tn->is_instr()) { instruction *ins = static_cast(tn)->instr(); operand dst = ins->dst_op(); if (dst.is_symbol() && dst.symbol() == vs) { operand op; if (ins->opcode() == io_cpy) op = ins->src_op(0).clone(); else op = operand(ins->clone()); ub_repr = new omega::CG_suifRepr(op); break; } } } } if (ub_repr == NULL) ub_repr = new omega::CG_suifRepr(operand(vs)); } else throw ir_error("array parsing error"); array_bound lb = static_cast(tn)->lower_bound(); omega::CG_outputRepr *lb_repr = NULL; if (lb.is_constant()) c -= lb.constant(); else if (lb.is_variable()) { var_sym *vs = ub.variable(); tree_node_list *tnl = static_cast(static_cast(ir_)->init_code_)->GetCode(); tree_node_list_iter iter(tnl); while(!iter.is_empty()) { tree_node *tn = iter.step(); if (tn->is_instr()) { instruction *ins = static_cast(tn)->instr(); operand dst = ins->dst_op(); if (dst.is_symbol() && dst.symbol() == vs) { operand op; if (ins->opcode() == io_cpy) op = ins->src_op(0).clone(); else op = operand(ins->clone()); lb_repr = new omega::CG_suifRepr(op); break; } } } if (lb_repr == NULL) lb_repr = new omega::CG_suifRepr(operand(vs)); } else throw ir_error("array parsing error"); omega::CG_outputRepr *repr = ir_->builder()->CreateMinus(ub_repr, lb_repr); if (c != 0) repr = ir_->builder()->CreatePlus(repr, ir_->builder()->CreateInt(c)); return repr; } IR_ARRAY_LAYOUT_TYPE IR_suifArraySymbol::layout_type() const { if (static_cast(ir_)->is_fortran_) return IR_ARRAY_LAYOUT_COLUMN_MAJOR; else return IR_ARRAY_LAYOUT_ROW_MAJOR; } bool IR_suifArraySymbol::operator==(const IR_Symbol &that) const { if (typeid(*this) != typeid(that)) return false; const IR_suifArraySymbol *l_that = static_cast(&that); return this->vs_ == l_that->vs_ && this->offset_ == l_that->offset_; } IR_Symbol *IR_suifArraySymbol::clone() const { return new IR_suifArraySymbol(ir_, vs_, indirect_, offset_); } // ---------------------------------------------------------------------------- // Class: IR_suifConstantRef // ---------------------------------------------------------------------------- bool IR_suifConstantRef::operator==(const IR_Ref &that) const { if (typeid(*this) != typeid(that)) return false; const IR_suifConstantRef *l_that = static_cast(&that); if (this->type_ != l_that->type_) return false; if (this->type_ == IR_CONSTANT_INT) return this->i_ == l_that->i_; else return this->f_ == l_that->f_; } omega::CG_outputRepr *IR_suifConstantRef::convert() { if (type_ == IR_CONSTANT_INT) { omega::CG_suifRepr *result = new omega::CG_suifRepr(operand(static_cast(i_), type_s32)); delete this; return result; } else throw ir_error("constant type not supported"); } IR_Ref *IR_suifConstantRef::clone() const { if (type_ == IR_CONSTANT_INT) return new IR_suifConstantRef(ir_, i_); else if (type_ == IR_CONSTANT_FLOAT) return new IR_suifConstantRef(ir_, f_); else throw ir_error("constant type not supported"); } // ---------------------------------------------------------------------------- // Class: IR_suifScalarRef // ---------------------------------------------------------------------------- bool IR_suifScalarRef::is_write() const { if (ins_pos_ != NULL && op_pos_ == -1) return true; else return false; } IR_ScalarSymbol *IR_suifScalarRef::symbol() const { return new IR_suifScalarSymbol(ir_, vs_); } bool IR_suifScalarRef::operator==(const IR_Ref &that) const { if (typeid(*this) != typeid(that)) return false; const IR_suifScalarRef *l_that = static_cast(&that); if (this->ins_pos_ == NULL) return this->vs_ == l_that->vs_; else return this->ins_pos_ == l_that->ins_pos_ && this->op_pos_ == l_that->op_pos_; } omega::CG_outputRepr *IR_suifScalarRef::convert() { omega::CG_suifRepr *result = new omega::CG_suifRepr(operand(vs_)); delete this; return result; } IR_Ref * IR_suifScalarRef::clone() const { if (ins_pos_ == NULL) return new IR_suifScalarRef(ir_, vs_); else return new IR_suifScalarRef(ir_, ins_pos_, op_pos_); } // ---------------------------------------------------------------------------- // Class: IR_suifArrayRef // ---------------------------------------------------------------------------- bool IR_suifArrayRef::is_write() const { return ::is_lhs(const_cast(ia_)); } omega::CG_outputRepr *IR_suifArrayRef::index(int dim) const { operand op = find_array_index(ia_, n_dim(), dim, static_cast(ir_)->is_fortran_); return new omega::CG_suifRepr(op.clone()); } IR_ArraySymbol *IR_suifArrayRef::symbol() const { in_array *current = ia_; // find the indirectness of the symbol, i.e., if it is (**A)[i,j] int indirect = 0; if (!static_cast(ir_)->is_fortran_) { operand op = ia_->base_op(); while (op.is_instr()) { instruction *ins = op.instr(); if (ins->opcode() == io_lod) { indirect++; op = ins->src_op(0); } else break; } if (op.is_symbol()) indirect++; } while (true) { operand op = current->base_op(); if (op.is_symbol()) { return new IR_suifArraySymbol(ir_, op.symbol(), indirect); } else if (op.is_instr()) { instruction *ins = op.instr(); if (ins->opcode() == io_ldc) { immed value = static_cast(ins)->value(); if (value.is_symbol()) { sym_node *the_sym = value.symbol(); if (the_sym->is_var()) return new IR_suifArraySymbol(ir_, static_cast(the_sym), indirect); else break; } else break; } else if (ins->opcode() == io_cvt) { operand op = static_cast(ins)->src_op(); if (op.is_symbol()) { return new IR_suifArraySymbol(ir_, op.symbol(), indirect); } else if (op.is_instr()) { instruction *ins = op.instr(); if (ins->opcode() == io_lod) { operand op = static_cast(ins)->src_op(); if (op.is_symbol()) { return new IR_suifArraySymbol(ir_, op.symbol(), indirect); } else if (op.is_instr()) { instruction *ins = op.instr(); if (ins->opcode() == io_array) { current = static_cast(ins); continue; } else if (ins->opcode() == io_add) { operand op1 = ins->src_op(0); operand op2 = ins->src_op(1); if (!op1.is_symbol() || !op2.is_immed()) throw ir_error("can't recognize array reference format"); immed im = op2.immediate(); if (!im.is_integer()) throw ir_error("can't recognize array reference format"); return new IR_suifArraySymbol(ir_, op1.symbol(), indirect, im.integer()); } else break; } else break; } else break; } else break; } else { while (ins->opcode() == io_lod) { operand op = ins->src_op(0); if (op.is_instr()) ins = op.instr(); else if (op.is_symbol()) return new IR_suifArraySymbol(ir_, op.symbol(), indirect); else break; } break; } } else break; } fprintf(stderr, "Warning: null array symbol found, dependence graph bloated!\n"); return new IR_suifArraySymbol(ir_, NULL); } bool IR_suifArrayRef::operator==(const IR_Ref &that) const { if (typeid(*this) != typeid(that)) return false; const IR_suifArrayRef *l_that = static_cast(&that); return this->ia_ == l_that ->ia_; } omega::CG_outputRepr *IR_suifArrayRef::convert() { omega::CG_suifRepr *result = new omega::CG_suifRepr(operand(this->ia_->clone())); delete this; return result; } IR_Ref *IR_suifArrayRef::clone() const { return new IR_suifArrayRef(ir_, ia_); } // ---------------------------------------------------------------------------- // Class: IR_suifLoop // ---------------------------------------------------------------------------- IR_ScalarSymbol *IR_suifLoop::index() const { var_sym *vs = tf_->index(); return new IR_suifScalarSymbol(ir_, vs); } omega::CG_outputRepr *IR_suifLoop::lower_bound() const { tree_node_list *tnl = tf_->lb_list(); tree_node_list_iter iter(tnl); if (iter.is_empty()) return new omega::CG_suifRepr(operand()); tree_node *tn = iter.step(); if (!iter.is_empty()) throw ir_error("cannot handle lower bound"); if (tn->kind() != TREE_INSTR) throw ir_error("cannot handle lower bound"); instruction *ins = static_cast(tn)->instr(); return new omega::CG_suifRepr(operand(ins)); } omega::CG_outputRepr *IR_suifLoop::upper_bound() const { tree_node_list *tnl = tf_->ub_list(); tree_node_list_iter iter(tnl); if (iter.is_empty()) return new omega::CG_suifRepr(operand()); tree_node *tn = iter.step(); if (!iter.is_empty()) throw ir_error("cannot handle lower bound"); if (tn->kind() != TREE_INSTR) throw ir_error("cannot handle lower bound"); instruction *ins = static_cast(tn)->instr(); return new omega::CG_suifRepr(operand(ins)); } IR_CONDITION_TYPE IR_suifLoop::stop_cond() const { if (tf_->test() == FOR_SLT || tf_->test() == FOR_ULT) return IR_COND_LT; else if (tf_->test() == FOR_SLTE || tf_->test() == FOR_ULTE) return IR_COND_LE; else if (tf_->test() == FOR_SGT || tf_->test() == FOR_UGT) return IR_COND_GT; else if (tf_->test() == FOR_SGTE || tf_->test() == FOR_UGTE) return IR_COND_GE; else throw ir_error("loop stop condition unsupported"); } IR_Block *IR_suifLoop::body() const { tree_node_list *tnl = tf_->body(); return new IR_suifBlock(ir_, tnl); } int IR_suifLoop::step_size() const { operand op = tf_->step_op(); if (!op.is_null()) { if (op.is_immed()) { immed im = op.immediate(); if (im.is_integer()) return im.integer(); else throw ir_error("cannot handle non-integer stride"); } else throw ir_error("cannot handle non-constant stride"); } else return 1; } IR_Block *IR_suifLoop::convert() { const IR_Code *ir = ir_; tree_node_list *tnl = tf_->parent(); tree_node_list_e *start, *end; start = end = tf_->list_e(); delete this; return new IR_suifBlock(ir, tnl, start, end); } IR_Control *IR_suifLoop::clone() const { return new IR_suifLoop(ir_, tf_); } // ---------------------------------------------------------------------------- // Class: IR_suifBlock // ---------------------------------------------------------------------------- omega::CG_outputRepr *IR_suifBlock::extract() const { tree_node_list *tnl = new tree_node_list; tree_node_list_iter iter(tnl_); while (!iter.is_empty()) { tree_node *tn = iter.peek(); if (tn->list_e() == start_) break; tn = iter.step(); } while (!iter.is_empty()) { tree_node *tn = iter.step(); tnl->append(tn->clone()); if (tn->list_e() == end_) break; } return new omega::CG_suifRepr(tnl); } IR_Control *IR_suifBlock::clone() const { return new IR_suifBlock(ir_, tnl_, start_, end_); } // ---------------------------------------------------------------------------- // Class: IR_suifIf // ---------------------------------------------------------------------------- omega::CG_outputRepr *IR_suifIf::condition() const { tree_node_list *tnl = ti_->header(); tree_node_list_iter iter(tnl); if (iter.is_empty()) throw ir_error("unrecognized if structure"); tree_node *tn = iter.step(); if (!iter.is_empty()) throw ir_error("unrecognized if structure"); if (!tn->is_instr()) throw ir_error("unrecognized if structure"); instruction *ins = static_cast(tn)->instr(); if (!ins->opcode() == io_bfalse) throw ir_error("unrecognized if structure"); operand op = ins->src_op(0); return new omega::CG_suifRepr(op); } IR_Block *IR_suifIf::then_body() const { tree_node_list *tnl = ti_->then_part(); if (tnl == NULL) return NULL; tree_node_list_iter iter(tnl); if (iter.is_empty()) return NULL; return new IR_suifBlock(ir_, tnl); } IR_Block *IR_suifIf::else_body() const { tree_node_list *tnl = ti_->else_part(); if (tnl == NULL) return NULL; tree_node_list_iter iter(tnl); if (iter.is_empty()) return NULL; return new IR_suifBlock(ir_, tnl); } IR_Block *IR_suifIf::convert() { const IR_Code *ir = ir_; tree_node_list *tnl = ti_->parent(); tree_node_list_e *start, *end; start = end = ti_->list_e(); delete this; return new IR_suifBlock(ir, tnl, start, end); } IR_Control *IR_suifIf::clone() const { return new IR_suifIf(ir_, ti_); } // ---------------------------------------------------------------------------- // Class: IR_suifCode_Global_Init // ---------------------------------------------------------------------------- IR_suifCode_Global_Init *IR_suifCode_Global_Init::pinstance = NULL; IR_suifCode_Global_Init *IR_suifCode_Global_Init::Instance () { if (pinstance == NULL) pinstance = new IR_suifCode_Global_Init; return pinstance; } IR_suifCode_Global_Init::IR_suifCode_Global_Init() { LIBRARY(useful, init_useful, exit_useful); LIBRARY(annotes, init_annotes, exit_annotes); int argc = 1; char *argv[1]; argv[0] = "chill"; init_suif(argc, argv); } // ---------------------------------------------------------------------------- // Class: IR_suifCode_Global_Cleanup // ---------------------------------------------------------------------------- IR_suifCode_Global_Cleanup::~IR_suifCode_Global_Cleanup() { delete IR_suifCode_Global_Init::Instance(); exit_suif1(); } namespace { IR_suifCode_Global_Cleanup suifcode_global_cleanup_instance; } // ---------------------------------------------------------------------------- // Class: IR_suifCode // ---------------------------------------------------------------------------- IR_suifCode::IR_suifCode(const char *filename, int proc_num): IR_Code() { IR_suifCode_Global_Init::Instance(); std::string new_filename(filename); int pos = new_filename.find_last_of('.'); new_filename = new_filename.substr(0, pos) + ".lxf"; fileset->add_file(const_cast(filename), const_cast(new_filename.c_str())); fileset->reset_iter(); fse_ = fileset->next_file(); fse_->reset_proc_iter(); int cur_proc = 0; while ((psym_ = fse_->next_proc()) && cur_proc < proc_num) ++cur_proc; if (cur_proc != proc_num) { throw ir_error("procedure number cannot be found"); } if (psym_->src_lang() == src_fortran) is_fortran_ = true; else is_fortran_ = false; if (!psym_->is_in_memory()) psym_->read_proc(TRUE, is_fortran_); push_clue(psym_->block()); symtab_ = psym_->block()->proc_syms(); ocg_ = new omega::CG_suifBuilder(symtab_); } IR_suifCode::~IR_suifCode() { tree_node_list *tnl = psym_->block()->body(); if (init_code_ != NULL) tnl->insert_before(static_cast(init_code_)->GetCode(), tnl->head()); if (cleanup_code_ != NULL) tnl->insert_after(static_cast(cleanup_code_)->GetCode(), tnl->tail()); pop_clue(psym_->block()); if (!psym_->is_written()) psym_->write_proc(fse_); psym_->flush_proc(); } IR_ScalarSymbol *IR_suifCode::CreateScalarSymbol(const IR_Symbol *sym, int) { if (typeid(*sym) == typeid(IR_suifScalarSymbol)) { type_node *tn = static_cast(sym)->vs_->type(); while (tn->is_modifier()) tn = static_cast(tn)->base(); var_sym *vs = symtab_->new_unique_var(tn); return new IR_suifScalarSymbol(this, vs); } else if (typeid(*sym) == typeid(IR_suifArraySymbol)) { type_node *tn = static_cast(sym)->vs_->type(); while (tn->is_modifier()) tn = static_cast(tn)->base(); while (tn->is_array() || tn->is_ptr()) { if (tn->is_array()) tn = static_cast(tn)->elem_type(); else if (tn->is_ptr()) tn = static_cast(tn)->ref_type(); } while (tn->is_modifier()) tn = static_cast(tn)->base(); var_sym *vs = symtab_->new_unique_var(tn); return new IR_suifScalarSymbol(this, vs); } else throw std::bad_typeid(); } IR_ArraySymbol *IR_suifCode::CreateArraySymbol(const IR_Symbol *sym, std::vector &size, int) { type_node *tn; if (typeid(*sym) == typeid(IR_suifScalarSymbol)) { tn = static_cast(sym)->vs_->type(); } else if (typeid(*sym) == typeid(IR_suifArraySymbol)) { tn = static_cast(sym)->vs_->type(); if (tn->is_modifier()) tn = static_cast(tn)->base(); while (tn->is_array() || tn->is_ptr()) { if (tn->is_array()) tn = static_cast(tn)->elem_type(); else if (tn->is_ptr()) tn = static_cast(tn)->ref_type(); } } else throw std::bad_typeid(); if (is_fortran_) for (int i = 0; i < size.size(); i++) { var_sym *temporary = symtab_->new_unique_var(type_s32); init_code_ = ocg_->StmtListAppend(init_code_, ocg_->CreateAssignment(0, new omega::CG_suifRepr(operand(temporary)), size[i])); tn = new array_type(tn, array_bound(1), array_bound(temporary)); symtab_->add_type(tn); } else for (int i = size.size()-1; i >= 0; i--) { var_sym *temporary = symtab_->new_unique_var(type_s32); init_code_ = ocg_->StmtListAppend(init_code_, ocg_->CreateAssignment(0, new omega::CG_suifRepr(operand(temporary)), size[i])); tn = new array_type(tn, array_bound(1), array_bound(temporary)); symtab_->add_type(tn); } static int suif_array_counter = 1; std::string s = std::string("_P") + omega::to_string(suif_array_counter++); var_sym *vs = new var_sym(tn, const_cast(s.c_str())); vs->add_to_table(symtab_); return new IR_suifArraySymbol(this, vs); } IR_ScalarRef *IR_suifCode::CreateScalarRef(const IR_ScalarSymbol *sym) { return new IR_suifScalarRef(this, static_cast(sym)->vs_); } IR_ArrayRef *IR_suifCode::CreateArrayRef(const IR_ArraySymbol *sym, std::vector &index) { if (sym->n_dim() != index.size()) throw std::invalid_argument("incorrect array symbol dimensionality"); const IR_suifArraySymbol *l_sym = static_cast(sym); var_sym *vs = l_sym->vs_; type_node *tn1 = vs->type(); if (tn1->is_modifier()) tn1 = static_cast(tn1)->base(); type_node *tn2 = tn1; while (tn2->is_array() || tn2->is_ptr()) { if (tn2->is_array()) tn2 = static_cast(tn2)->elem_type(); else if (tn2->is_ptr()) tn2 = static_cast(tn2)->ref_type(); } instruction *base_ins; if (tn1->is_ptr()) { base_symtab *cur_symtab; cur_symtab = symtab_; type_node *found_array_tn = NULL; while (cur_symtab != NULL) { type_node_list_iter iter(cur_symtab->types()); while (!iter.is_empty()) { type_node *tn = iter.step(); if (!tn->is_array()) continue; if (static_cast(tn)->elem_type() == static_cast(tn1)->ref_type()) { array_bound b = static_cast(tn)->upper_bound(); if (b.is_unknown()) { found_array_tn = tn; break; } } } if (found_array_tn == NULL) cur_symtab = cur_symtab->parent(); else break; } cur_symtab = symtab_; type_node *found_ptr_array_tn = NULL; while (cur_symtab != NULL) { type_node_list_iter iter(cur_symtab->types()); while (!iter.is_empty()) { type_node *tn = iter.step(); if (!tn->is_ptr()) continue; if (static_cast(tn)->ref_type() == found_array_tn) { found_ptr_array_tn = tn; break; } } if (found_ptr_array_tn == NULL) cur_symtab = cur_symtab->parent(); else break; } if (found_ptr_array_tn == NULL) throw ir_error("can't find the type for the to-be-created array"); base_ins = new in_rrr(io_cvt, found_ptr_array_tn, operand(), operand(vs)); } else { base_ins = new in_ldc(tn1->ptr_to(), operand(), immed(vs)); } in_array *ia = new in_array(tn2->ptr_to(), operand(), operand(base_ins), tn2->size(), l_sym->n_dim()); for (int i = 0; i < index.size(); i++) { int t; if (is_fortran_) t = index.size() - i - 1; else t = i; omega::CG_suifRepr *bound = static_cast(l_sym->size(t)); ia->set_bound(t, bound->GetExpression()); delete bound; omega::CG_suifRepr *idx = static_cast(index[i]); ia->set_index(t, idx->GetExpression()); delete idx; } return new IR_suifArrayRef(this, ia); } std::vector IR_suifCode::FindArrayRef(const omega::CG_outputRepr *repr) const { std::vector arrays; tree_node_list *tnl = static_cast(repr)->GetCode(); if (tnl != NULL) { tree_node_list_iter iter(tnl); while (!iter.is_empty()) { tree_node *tn = iter.step(); switch (tn->kind()) { case TREE_FOR: { tree_for *tnf = static_cast(tn); omega::CG_suifRepr *r = new omega::CG_suifRepr(tnf->body()); std::vector a = FindArrayRef(r); delete r; std::copy(a.begin(), a.end(), back_inserter(arrays)); break; } case TREE_IF: { tree_if *tni = static_cast(tn); omega::CG_suifRepr *r = new omega::CG_suifRepr(tni->header()); std::vector a = FindArrayRef(r); delete r; std::copy(a.begin(), a.end(), back_inserter(arrays)); r = new omega::CG_suifRepr(tni->then_part()); a = FindArrayRef(r); delete r; std::copy(a.begin(), a.end(), back_inserter(arrays)); r = new omega::CG_suifRepr(tni->else_part()); a = FindArrayRef(r); delete r; std::copy(a.begin(), a.end(), back_inserter(arrays)); break; } case TREE_BLOCK: { omega::CG_suifRepr *r = new omega::CG_suifRepr(static_cast(tn)->body()); std::vector a = FindArrayRef(r); delete r; std::copy(a.begin(), a.end(), back_inserter(arrays)); break; } case TREE_INSTR: { omega::CG_suifRepr *r = new omega::CG_suifRepr(operand(static_cast(tn)->instr())); std::vector a = FindArrayRef(r); delete r; std::copy(a.begin(), a.end(), back_inserter(arrays)); break; } default: throw ir_error("control structure not supported"); } } } else { operand op = static_cast(repr)->GetExpression(); if (op.is_instr()) { instruction *ins = op.instr(); switch (ins->opcode()) { case io_array: { IR_suifArrayRef *ref = new IR_suifArrayRef(this, static_cast(ins)); for (int i = 0; i < ref->n_dim(); i++) { omega::CG_suifRepr *r = new omega::CG_suifRepr(find_array_index(ref->ia_, ref->n_dim(), i, is_fortran_)); std::vector a = FindArrayRef(r); delete r; std::copy(a.begin(), a.end(), back_inserter(arrays)); } arrays.push_back(ref); break; } case io_str: case io_memcpy: { omega::CG_suifRepr *r1 = new omega::CG_suifRepr(ins->src_op(1)); std::vector a1 = FindArrayRef(r1); delete r1; std::copy(a1.begin(), a1.end(), back_inserter(arrays)); omega::CG_suifRepr *r2 = new omega::CG_suifRepr(ins->src_op(0)); std::vector a2 = FindArrayRef(r2); delete r2; std::copy(a2.begin(), a2.end(), back_inserter(arrays)); break; } default: for (int i = 0; i < ins->num_srcs(); i++) { omega::CG_suifRepr *r = new omega::CG_suifRepr(ins->src_op(i)); std::vector a = FindArrayRef(r); delete r; std::copy(a.begin(), a.end(), back_inserter(arrays)); } } } } return arrays; } std::vector IR_suifCode::FindScalarRef(const omega::CG_outputRepr *repr) const { std::vector scalars; tree_node_list *tnl = static_cast(repr)->GetCode(); if (tnl != NULL) { tree_node_list_iter iter(tnl); while (!iter.is_empty()) { tree_node *tn = iter.step(); switch (tn->kind()) { case TREE_FOR: { tree_for *tnf = static_cast(tn); omega::CG_suifRepr *r = new omega::CG_suifRepr(tnf->body()); std::vector a = FindScalarRef(r); delete r; std::copy(a.begin(), a.end(), back_inserter(scalars)); break; } case TREE_IF: { tree_if *tni = static_cast(tn); omega::CG_suifRepr *r = new omega::CG_suifRepr(tni->header()); std::vector a = FindScalarRef(r); delete r; std::copy(a.begin(), a.end(), back_inserter(scalars)); r = new omega::CG_suifRepr(tni->then_part()); a = FindScalarRef(r); delete r; std::copy(a.begin(), a.end(), back_inserter(scalars)); r = new omega::CG_suifRepr(tni->else_part()); a = FindScalarRef(r); delete r; std::copy(a.begin(), a.end(), back_inserter(scalars)); break; } case TREE_BLOCK: { omega::CG_suifRepr *r = new omega::CG_suifRepr(static_cast(tn)->body()); std::vector a = FindScalarRef(r); delete r; std::copy(a.begin(), a.end(), back_inserter(scalars)); break; } case TREE_INSTR: { omega::CG_suifRepr *r = new omega::CG_suifRepr(operand(static_cast(tn)->instr())); std::vector a = FindScalarRef(r); delete r; std::copy(a.begin(), a.end(), back_inserter(scalars)); break; } default: throw ir_error("control structure not supported"); } } } else { operand op = static_cast(repr)->GetExpression(); if (op.is_instr()) { instruction *ins = op.instr(); for (int i = 0; i < ins->num_srcs(); i++) { operand op = ins->src_op(i); if (op.is_symbol()) scalars.push_back(new IR_suifScalarRef(this, ins, i)); else if (op.is_instr()) { omega::CG_suifRepr *r = new omega::CG_suifRepr(op); std::vector a = FindScalarRef(r); delete r; std::copy(a.begin(), a.end(), back_inserter(scalars)); } } operand op = ins->dst_op(); if (op.is_symbol()) scalars.push_back(new IR_suifScalarRef(this, ins, -1)); } else if (op.is_symbol()) scalars.push_back(new IR_suifScalarRef(this, op.symbol())); } return scalars; } std::vector IR_suifCode::FindOneLevelControlStructure(const IR_Block *block) const { std::vector controls; IR_suifBlock *l_block = static_cast(const_cast(block)); tree_node_list_iter iter(l_block->tnl_); while(!iter.is_empty()) { tree_node *tn = iter.peek(); if (tn->list_e() == l_block->start_) break; iter.step(); } tree_node_list_e *start = NULL; tree_node_list_e *prev = NULL; while (!iter.is_empty()) { tree_node *tn = iter.step(); if (tn->kind() == TREE_FOR) { if (start != NULL) { controls.push_back(new IR_suifBlock(this, l_block->tnl_, start, prev)); start = NULL; } controls.push_back(new IR_suifLoop(this, static_cast(tn))); } else if (tn->kind() == TREE_IF) { if (start != NULL) { controls.push_back(new IR_suifBlock(this, l_block->tnl_, start, prev)); start = NULL; } controls.push_back(new IR_suifIf(this, static_cast(tn))); } else if (start == NULL && !is_null_statement(tn)) { start = tn->list_e(); } prev = tn->list_e(); if (prev == l_block->end_) break; } if (start != NULL && start != l_block->start_) controls.push_back(new IR_suifBlock(this, l_block->tnl_, start, prev)); return controls; } IR_Block *IR_suifCode::MergeNeighboringControlStructures(const std::vector &controls) const { if (controls.size() == 0) return NULL; tree_node_list *tnl = NULL; tree_node_list_e *start, *end; for (int i = 0; i < controls.size(); i++) { switch (controls[i]->type()) { case IR_CONTROL_LOOP: { tree_for *tf = static_cast(controls[i])->tf_; if (tnl == NULL) { tnl = tf->parent(); start = end = tf->list_e(); } else { if (tnl != tf->parent()) throw ir_error("controls to merge not at the same level"); end = tf->list_e(); } break; } case IR_CONTROL_BLOCK: { if (tnl == NULL) { tnl = static_cast(controls[0])->tnl_; start = static_cast(controls[0])->start_; end = static_cast(controls[0])->end_; } else { if (tnl != static_cast(controls[0])->tnl_) throw ir_error("controls to merge not at the same level"); end = static_cast(controls[0])->end_; } break; } default: throw ir_error("unrecognized control to merge"); } } return new IR_suifBlock(controls[0]->ir_, tnl, start, end); } IR_Block *IR_suifCode::GetCode() const { return new IR_suifBlock(this, psym_->block()->body()); } void IR_suifCode::ReplaceCode(IR_Control *old, omega::CG_outputRepr *repr) { tree_node_list *tnl = static_cast(repr)->GetCode(); switch (old->type()) { case IR_CONTROL_LOOP: { tree_for *tf_old = static_cast(old)->tf_; tree_node_list *tnl_old = tf_old->parent(); tnl_old->insert_before(tnl, tf_old->list_e()); tnl_old->remove(tf_old->list_e()); delete tf_old; break; } case IR_CONTROL_BLOCK: { IR_suifBlock *sb = static_cast(old); tree_node_list_iter iter(sb->tnl_); bool need_deleting = false; while (!iter.is_empty()) { tree_node *tn = iter.step(); tree_node_list_e *pos = tn->list_e(); if (pos == sb->start_) { sb->tnl_->insert_before(tnl, pos); need_deleting = true; } if (need_deleting) { sb->tnl_->remove(pos); delete tn; } if (pos == sb->end_) break; } break; } default: throw ir_error("control structure to be replaced not supported"); } delete old; delete repr; } void IR_suifCode::ReplaceExpression(IR_Ref *old, omega::CG_outputRepr *repr) { operand op = static_cast(repr)->GetExpression(); if (typeid(*old) == typeid(IR_suifArrayRef)) { in_array *ia_orig = static_cast(old)->ia_; if (op.is_instr()) { instruction *ia_repl = op.instr(); if (ia_repl->opcode() == io_array) { if (ia_orig->elem_type()->is_struct()) { static_cast(ia_repl)->set_offset(ia_orig->offset()); struct_type *tn = static_cast(ia_orig->elem_type()); int left; type_node *field_tn = tn->field_type(tn->find_field_by_offset(ia_orig->offset(), left)); static_cast(ia_repl)->set_result_type(field_tn->ptr_to()); } replace_instruction(ia_orig, ia_repl); delete ia_orig; } else { instruction *parent_instr = ia_orig->dst_op().instr(); if (parent_instr->opcode() == io_str) { throw ir_error("replace left hand arrary reference not supported yet"); } else if (parent_instr->opcode() == io_lod) { instruction *instr = parent_instr->dst_op().instr(); if (instr->dst_op() == operand(parent_instr)) { parent_instr->remove(); instr->set_dst(op); } else { for (int i = 0; i < instr->num_srcs(); i++) if (instr->src_op(i) == operand(parent_instr)) { parent_instr->remove(); instr->set_src_op(i, op); break; } } delete parent_instr; } else throw ir_error("array reference to be replaced does not appear in any instruction"); } } else if (op.is_symbol()) { var_sym *vs = op.symbol(); instruction *parent_instr = ia_orig->dst_op().instr(); if (parent_instr->opcode() == io_str) { tree_node *tn = parent_instr->parent(); operand op = parent_instr->src_op(1).clone(); instruction *new_instr = new in_rrr(io_cpy, vs->type(), operand(vs), op); tree_node_list *tnl = tn->parent(); tnl->insert_before(new tree_instr(new_instr), tn->list_e()); tnl->remove(tn->list_e()); delete tn; } else if (parent_instr->opcode() == io_lod) { instruction *instr = parent_instr->dst_op().instr(); if (instr->dst_op() == operand(parent_instr)) { parent_instr->remove(); instr->set_dst(operand(vs)); } else { for (int i = 0; i < instr->num_srcs(); i++) if (instr->src_op(i) == operand(parent_instr)) { parent_instr->remove(); instr->set_src_op(i, operand(vs)); break; } } delete parent_instr; } else throw ir_error("array reference to be replaced does not appear in any instruction"); } else throw ir_error("can't handle replacement expression"); } else throw ir_error("replacing a scalar variable not implemented"); delete old; delete repr; } IR_OPERATION_TYPE IR_suifCode::QueryExpOperation(const omega::CG_outputRepr *repr) const { operand op = static_cast(repr)->GetExpression(); if (op.is_immed()) return IR_OP_CONSTANT; else if (op.is_symbol()) return IR_OP_VARIABLE; else if (op.is_instr()) { instruction *ins = op.instr(); switch (ins->opcode()) { case io_cpy: return IR_OP_ASSIGNMENT; case io_add: return IR_OP_PLUS; case io_sub: return IR_OP_MINUS; case io_mul: return IR_OP_MULTIPLY; case io_div: return IR_OP_DIVIDE; case io_neg: return IR_OP_NEGATIVE; case io_min: return IR_OP_MIN; case io_max: return IR_OP_MAX; case io_cvt: return IR_OP_POSITIVE; default: return IR_OP_UNKNOWN; } } else if (op.is_null()) return IR_OP_NULL; else return IR_OP_UNKNOWN; } IR_CONDITION_TYPE IR_suifCode::QueryBooleanExpOperation(const omega::CG_outputRepr *repr) const { operand op = static_cast(repr)->GetExpression(); if (op.is_instr()) { instruction *ins = op.instr(); switch (ins->opcode()) { case io_seq: return IR_COND_EQ; case io_sne: return IR_COND_NE; case io_sl: return IR_COND_LT; case io_sle: return IR_COND_LE; default: return IR_COND_UNKNOWN; } } else return IR_COND_UNKNOWN; } std::vector IR_suifCode::QueryExpOperand(const omega::CG_outputRepr *repr) const { std::vector v; operand op = static_cast(repr)->GetExpression(); if (op.is_immed() || op.is_symbol()) { omega::CG_suifRepr *repr = new omega::CG_suifRepr(op); v.push_back(repr); } else if (op.is_instr()) { instruction *ins = op.instr(); omega::CG_suifRepr *repr; operand op1, op2; switch (ins->opcode()) { case io_cpy: case io_neg: case io_cvt: op1 = ins->src_op(0); repr = new omega::CG_suifRepr(op1); v.push_back(repr); break; case io_add: case io_sub: case io_mul: case io_div: case io_min: case io_max: op1 = ins->src_op(0); repr = new omega::CG_suifRepr(op1); v.push_back(repr); op2 = ins->src_op(1); repr = new omega::CG_suifRepr(op2); v.push_back(repr); break; case io_seq: case io_sne: case io_sl: case io_sle: op1 = ins->src_op(0); repr = new omega::CG_suifRepr(op1); v.push_back(repr); op2 = ins->src_op(1); repr = new omega::CG_suifRepr(op2); v.push_back(repr); break; default: throw ir_error("operation not supported"); } } else throw ir_error("operand type not supported"); return v; } // IR_Constant *IR_suifCode::QueryExpConstant(const CG_outputRepr *repr) const { // CG_suifRepr *l_repr = static_cast(const_cast(repr)); // operand op = l_repr->GetExpression(); // if (op.is_immed()) { // immed im = op.immediate(); // switch (im.kind()) { // case im_int: // return new IR_suifConstant(this, static_cast(im.integer())); // case im_extended_int: // return new IR_suifConstant(this, static_cast(im.long_int())); // case im_float: // return new IR_suifConstant(this, im.flt()); // default: // assert(-1); // } // } // else // assert(-1); // } // IR_ScalarRef *IR_suifCode::QueryExpVariable(const CG_outputRepr *repr) const { // CG_suifRepr *l_repr = static_cast(const_cast(repr)); // operand op = l_repr->GetExpression(); // if (op.is_symbol()) // return new IR_suifScalarRef(this, op.symbol()); // else // assert(-1); // } IR_Ref *IR_suifCode::Repr2Ref(const omega::CG_outputRepr *repr) const { operand op = static_cast(repr)->GetExpression(); if (op.is_immed()) { immed im = op.immediate(); switch (im.kind()) { case im_int: return new IR_suifConstantRef(this, static_cast(im.integer())); case im_extended_int: return new IR_suifConstantRef(this, static_cast(im.long_int())); case im_float: return new IR_suifConstantRef(this, im.flt()); default: throw ir_error("immediate value not integer or floatint point"); } } else if (op.is_symbol()) return new IR_suifScalarRef(this, op.symbol()); else throw ir_error("unrecognized reference type"); }