void setupMPIInit(SgSourceFile* cur_file) { //#include "mpi.h" SageInterface::insertHeader (cur_file, "mpi.h", false,true); SageInterface::insertHeader (cur_file, "libxomp_mpi.h", false, true); SgFunctionDeclaration* main_decl = findMain(cur_file); // TODO: handle multiple files, some of them don't have main() ROSE_ASSERT (main_decl != NULL); SgFunctionDefinition* main_def = main_decl->get_definition(); ROSE_ASSERT (main_def != NULL); SgBasicBlock* func_body = main_def->get_body(); ROSE_ASSERT (func_body != NULL); // Setup MPI SgStatement* decl_rank = buildStatementFromString("int _xomp_rank;", func_body); prependStatement(decl_rank, func_body); SgStatement* decl_nprocs= buildStatementFromString("int _xomp_nprocs;", func_body); prependStatement(decl_nprocs, func_body); // xomp_init_mpi (&argc, &argv, &_xomp_rank, &_xomp_nprocs); SgExprListExp * para_list = buildExprListExp (buildAddressOfOp (buildVarRefExp("argc", func_body)), buildAddressOfOp (buildVarRefExp("argv", func_body)), buildAddressOfOp (buildVarRefExp("_xomp_rank", func_body)), buildAddressOfOp (buildVarRefExp("_xomp_nprocs", func_body)) ); SgExprStatement* mpi_init_stmt = buildFunctionCallStmt ("xomp_init_mpi", buildIntType(), para_list, func_body); // SgStatement* last_decl = findLastDeclarationStatement (func_body); insertStatementAfter (decl_rank, mpi_init_stmt); }
// Create load/store = loads + iteration * load/store_count_per_iteration // lhs_exp = lhs_exp + iter_count_exp * per_iter_bytecount_exp SgExprStatement* buildByteCalculationStmt(SgVariableSymbol * lhs_sym, SgVariableSymbol* iter_count_sym, SgExpression* per_iter_bytecount_exp) { assert (lhs_sym != NULL); assert (iter_count_sym != NULL); assert (per_iter_bytecount_exp != NULL); SgExpression* lhs_exp = buildVarRefExp(lhs_sym); SgExpression* rhs_exp = buildAddOp( buildVarRefExp(lhs_sym), buildMultiplyOp (buildVarRefExp(iter_count_sym), per_iter_bytecount_exp) ); return buildAssignStatement(lhs_exp, rhs_exp); }
//! Return an expression like 8*sizeof(int)+ 3*sizeof(float) + 5*sizeof(double) for a list of variables accessed (either read or write) // For array variable, we should only count a single element access, not the entire array size // Algorithm: // Iterate on each variable in the set // group them into buckets based on types, using a map<SgType*, int> to store this // Iterate the list of buckets to generate count*sizeof(type) + .. expression SgExpression* calculateBytes (std::set<SgInitializedName*>& name_set, SgScopeStatement* scope, bool isRead) { SgExpression* result = NULL; if (name_set.size()==0) return result; // the input is essentially the loop body, a scope statement ROSE_ASSERT (scope != NULL); // We need to record the associated loop info. SgStatement* loop= NULL; SgForStatement* forloop = isSgForStatement(scope->get_scope()); SgFortranDo* doloop = isSgFortranDo(scope->get_scope()); if (forloop) loop = forloop; else if (doloop) loop = doloop; else { cerr<<"Error in CountLoadStoreBytes (): input is not loop body type:"<< scope->class_name()<<endl; assert(false); } std::map<SgType* , int> type_based_counters; // get all processed variables by inner loops std::set<SgInitializedName*> processed_var_set; getVariablesProcessedByInnerLoops (scope, isRead, processed_var_set); // fill in the type-based counters std::set<SgInitializedName*>::iterator set_iter; for (set_iter = name_set.begin(); set_iter != name_set.end(); set_iter++) { SgInitializedName* init_name = *set_iter; // skip visited variable when processing inner loops // some global variables may be visited by another function // But we should count it when processing the current function! // // We group all references to a same variable into one reference for now // if a variable is considered when processing inner loops, the variable // will be skipped when processing outer loops. if (isRead) { // if inner loops already processed it, skip it if (processed_var_set.find(init_name) != processed_var_set.end()) continue; else LoopLoadVariables[loop].insert(init_name); } else { if (processed_var_set.find(init_name) != processed_var_set.end()) continue; else LoopStoreVariables[loop].insert(init_name); } // It is tricky here, TODO consider pointer, typedefs, reference, modifier types SgType* stripped_type = (*set_iter)->get_type()->stripTypedefsAndModifiers(); SgType* base_type = NULL; if (isScalarType(stripped_type)) base_type = stripped_type; else if (isSgArrayType(stripped_type)) { // we may have multi-dimensional arrays like int a[][][]; base_type = stripped_type; do { base_type = isSgArrayType(base_type)->get_base_type(); } while (isSgArrayType (base_type)); } else { cerr<<"Error in calculateBytes(). Unhandled stripped type:"<<stripped_type->class_name()<<endl; assert (false); } type_based_counters[base_type] ++; } // end for // use the type-based counters for byte calculation std::map<SgType* , int>::iterator citer; //It is possible now to have zero after filtering out redundant variables //assert (type_based_counters.size()>0); for (citer = type_based_counters.begin(); citer !=type_based_counters.end(); citer ++) { SgType* t = (*citer).first; // at this point, we should not have array types any more ROSE_ASSERT (isSgArrayType (t) == false); int count = (*citer).second; assert (t != NULL); assert (count>0); SgExpression* sizeof_exp = NULL; if (is_Fortran_language()) { #if 0 // this does not work. cannot find func symbol for sizeof() // In Fortran sizeof() is a function call, not SgSizeOfOp. // type name is a variable in the AST, // Too much trouble to build assert (scope !=NULL); // This does not work //SgFunctionSymbol* func_sym = lookupFunctionSymbolInParentScopes(SgName("sizeof"), scope); SgGlobal* gscope = getGlobalScope (scope); assert (gscope !=NULL); SgFunctionSymbol* func_sym = gscope->lookup_function_symbol(SgName("sizeof")); assert (func_sym!=NULL); SgVarRefExp* type_var = buildVarRefExp( t->unparseToString(), scope ); assert (type_var !=NULL); sizeof_exp = buildFunctionCallExp (func_sym, buildExprListExp(type_var)); #else // sizeof is not an operator in Fortran, there is no unparsing support for this // sizeof_exp = buildSizeOfOp(t); // Directly obtain an integer size value sizeof_exp = buildIntVal(getSizeOf(t)); #endif } else if (is_C_language() || is_C99_language() || is_Cxx_language()) { sizeof_exp = buildSizeOfOp(t); } else { cerr<<"Error in calculateBytes(). Unsupported programming language other than C/Cxx and Fortran. "<<endl; assert (false); } SgExpression* mop = buildMultiplyOp(buildIntVal(count), sizeof_exp); if (result == NULL) result = mop; else result = buildAddOp(result, mop); } return result; }
//! Translate generated Pragma Attributes one by one void translatePragmas (std::vector <MPI_PragmaAttribute*>& Attribute_List) { std::vector<MPI_PragmaAttribute*>::iterator iter; for (iter = Attribute_List.begin(); iter!=Attribute_List.end(); iter ++) { MPI_PragmaAttribute* cur_attr = *iter; cout<<"Translating ..." << cur_attr->toString() <<endl; SgScopeStatement* scope = cur_attr->pragma_node ->get_scope(); ROSE_ASSERT (scope != NULL); // simply obtain the default value and remove the pragma if (cur_attr-> pragma_type == pragma_mpi_device_default) { mpi_device_default_choice = cur_attr->default_semantics; // no automatic handling of attached preprocessed info. for now removeStatement(cur_attr->pragma_node, false); } // find omp target device(mpi:all) begin else if (cur_attr-> pragma_type == pragma_mpi_device_all_begin) { iter ++; // additional increment once MPI_PragmaAttribute* end_attribute = *iter; ROSE_ASSERT (end_attribute->pragma_type = pragma_mpi_device_all_end); removeStatement(cur_attr->pragma_node, false); removeStatement(end_attribute ->pragma_node, false); } else if (cur_attr-> pragma_type == pragma_mpi_device_master_begin) { // TODO refactor into a function iter ++; // additional increment once MPI_PragmaAttribute* end_attribute = *iter; ROSE_ASSERT (end_attribute->pragma_type = pragma_mpi_device_master_end); //insert a if (rank) .. after the end pragma SgIfStmt * ifstmt = buildIfStmt (buildEqualityOp(buildVarRefExp("_xomp_rank", scope), buildIntVal(0)), buildBasicBlock(), NULL); insertStatementAfter (end_attribute->pragma_node, ifstmt); SgBasicBlock * bb = isSgBasicBlock(ifstmt->get_true_body()); SgStatement* next_stmt = getNextStatement(cur_attr->pragma_node); // the next stmt is BB, skip it by starting the search from it ROSE_ASSERT (next_stmt != NULL); // normalize all declarations while ( next_stmt != end_attribute ->pragma_node) { // save current stmt before getting next one SgStatement* cur_stmt = next_stmt; next_stmt = getNextStatement (next_stmt); ROSE_ASSERT (next_stmt != NULL); if (SgVariableDeclaration* decl = isSgVariableDeclaration (cur_stmt)) splitVariableDeclaration (decl); } // move all non-declaration statements in between into the block next_stmt = getNextStatement(cur_attr->pragma_node); //reset from the beginning while ( next_stmt != end_attribute ->pragma_node) { // save current stmt before getting next one SgStatement* cur_stmt = next_stmt; next_stmt = getNextStatement (next_stmt); ROSE_ASSERT (next_stmt != NULL); if (!isSgVariableDeclaration(cur_stmt)) { // now remove the current stmt removeStatement (cur_stmt, false); appendStatement(cur_stmt, bb); } } // remove pragmas removeStatement(cur_attr->pragma_node, false); removeStatement(end_attribute ->pragma_node, false); } } // end for } // end translatePragmas ()
/* * Add calls to register and unregister expressions/arrays with the memory * management wrapper. */ bool RegisterPointers::addRegUnregCalls() { string msg; if(definedInSystemHeader) { msg = "\t\t\tVariable " + NAME(varSymbol) + " is in system headers"; WARNING(TOOL, msg); return false; } if(compilerGenerated) { msg = "\t\t\tVariable " + NAME(varSymbol) + " is compiler-generated"; WARNING(TOOL, msg); return false; } if(addrUsedInIO) { msg = "\t\t\tVariable " + NAME(varSymbol) + " has its address taken in " + "a function known to not require registering/unregistering"; WARNING(TOOL, msg); return false; } //Add register/unregister calls SgStatement* prevStmt = NULL; SgExprStatement* funcCall = NULL; SgType* type = NULL; SgExpression* expr = NULL; if(isGlobal) { type = varName->get_type(); SgName name = varName->get_name(); int numVals = 1; if(isSgPointerType(type)) return false; //If its a pointer, it points to a static array, dynamic array, or scalar //which has its address taken (all of which have already been registered) SgFunctionDeclaration* main = findMain(getScope(varName)); ROSE_ASSERT(main); expr = buildVarRefExp(name, varName->get_scope()); if(isSgArrayType(type)) numVals = getArrayElementCount(isSgArrayType(type)); else expr = buildAddressOfOp(expr); funcCall = MMCallBuilder::buildRegisterPointerCall(expr, buildUnsignedIntVal(numVals), main->get_definition()); insertStatement(getFirstStatement(main->get_definition()), funcCall);//, false, true); funcCall = MMCallBuilder::buildUnregisterPointerCall(expr, main->get_definition()); instrumentEndOfFunction(main, funcCall); } else if(expression) //Address-of expressions { prevStmt = getEnclosingStatement(expression); funcCall = MMCallBuilder::buildRegisterPointerCall(expression, buildUnsignedIntVal(1), getScope(expression)); insertStatement(prevStmt, funcCall); funcCall = MMCallBuilder::buildUnregisterPointerCall(expression, getScope(expression)); instrumentEndOfFunction(getEnclosingFunctionDeclaration(prevStmt), funcCall); } else //Array types { SgVarRefExp* varRef = buildVarRefExp(varName, getScope(varName)); int numVals = getArrayElementCount(isSgArrayType(varName->get_type())); funcCall = MMCallBuilder::buildRegisterPointerCall(varRef, buildUnsignedIntVal(numVals), varName->get_scope()); insertStatement(varName->get_declaration(), funcCall, false, true); varRef = buildVarRefExp(varName, getScope(varName)); funcCall = MMCallBuilder::buildUnregisterPointerCall(varRef, varName->get_scope()); instrumentEndOfFunction(getEnclosingFunctionDeclaration(varName), funcCall); } return true; }
// =========================================================== //! Fixes up references in a block to point to alternative symbols. // based on an existing symbol-to-symbol map // Also called variable substitution. static void remapVarSyms (const VarSymRemap_t& vsym_remap, // regular shared variables const ASTtools::VarSymSet_t& pdSyms, // special shared variables const VarSymRemap_t& private_remap, // variables using private copies SgBasicBlock* b) { // Check if variable remapping is even needed. if (vsym_remap.empty() && private_remap.empty()){ //cout << "no remapping " << endl ; return; } // Find all variable references typedef Rose_STL_Container<SgNode *> NodeList_t; NodeList_t refs = NodeQuery::querySubTree (b, V_SgVarRefExp); // For each of the references , for (NodeList_t::iterator i = refs.begin (); i != refs.end (); ++i) { // Reference possibly in need of fix-up. SgVarRefExp* ref_orig = isSgVarRefExp (*i); ROSE_ASSERT (ref_orig); // Search for a symbol which needs to be replaced. // cout << "this is the symbol " <<ref_orig->get_symbol()->get_name().str() << endl ; VarSymRemap_t::const_iterator ref_new = vsym_remap.find (ref_orig->get_symbol ()); VarSymRemap_t::const_iterator ref_private = private_remap.find (ref_orig->get_symbol ()); // a variable could be both a variable needing passing original value and private variable // such as OpenMP firstprivate, lastprivate and reduction variable // For variable substitution, private remap has higher priority // remapping private variables if (ref_private != private_remap.end()) { // get the replacement variable SgVariableSymbol* sym_new = ref_private->second; // Do the replacement ref_orig->set_symbol (sym_new); } else if (ref_new != vsym_remap.end ()) // Needs replacement, regular shared variables { if(Outliner::enable_debug) { cout << "replace this " << "variable with that " << endl ; } SgVariableSymbol* sym_new = ref_new->second; if (Outliner::temp_variable || Outliner::useStructureWrapper) // uniform handling if temp variables of the same type are used {// two cases: variable using temp vs. variables using pointer dereferencing! if (pdSyms.find(ref_orig->get_symbol())==pdSyms.end()) //using temp ref_orig->set_symbol(sym_new); else { SgPointerDerefExp * deref_exp = SageBuilder::buildPointerDerefExp(buildVarRefExp(sym_new)); deref_exp->set_need_paren(true); SageInterface::replaceExpression(isSgExpression(ref_orig),isSgExpression(deref_exp)); } } else // no variable cloning is used { if (is_C_language()) // old method of using pointer dereferencing indiscriminately for C input // TODO compare the orig and new type, use pointer dereferencing only when necessary { SgPointerDerefExp * deref_exp = SageBuilder::buildPointerDerefExp(buildVarRefExp(sym_new)); deref_exp->set_need_paren(true); SageInterface::replaceExpression(isSgExpression(ref_orig),isSgExpression(deref_exp)); } else ref_orig->set_symbol (sym_new); } } //find an entry } // for every refs }