void XOMP_parallel_start (void (*func) (void *), void *data, unsigned numThread) { #ifdef USE_ROSE_GOMP_OPENMP_LIBRARY
func(data); #else _ompc_do_parallel (func, data); #endif }
XOMP is a wrapper api for rose that further use GOMP or if GOMP is not set Omni Libraries which is a japanese compiler for OpenMP. The following code is from the Omni project. To get an idea how this works:
void _ompc_do_parallel(cfunc f, void *args) { _ompc_do_parallel_main (1, _ompc_num_threads, f, args); } void _ompc_init(int argc,char *argv[]) { char * cp; int val; long lnp; struct ompc_thread *tp; #ifdef USE_PTHREAD static pthread_t thds[MAX_PROC]; static pthread_attr_t attr; pthread_attr_init(&attr); #ifndef OMNI_OS_FREEBSD #ifndef OMNI_OS_IRIX pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); #endif #endif /*pthread_attr_setschedpolicy(&attr, SCHED_FIFO);*/ #endif ...
And here the small fraction out of the GOMP code:
// from parallel.c
void GOMP_parallel_start (void (*fn) (void *), void *data, unsigned num_threads) { num_threads = gomp_resolve_num_threads (num_threads, 0); gomp_team_start (fn, data, num_threads, gomp_new_team (num_threads)); }
// from team.c
void gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads, struct gomp_team *team) { ... }
Simple src-to-src example:
// Example ROSE Translator: used for testing ROSE infrastructure #include "rose.h" int main( int argc, char * argv[] ) { // Build the AST used by ROSE SgProject* sageProject = frontend(argc,argv); // Run internal consistency tests on AST AstTests::runAllTests(sageProject); // Insert your own manipulation of the AST here... // Generate source code from AST and call the vendor's compiler return backend(sageProject); }
List of interesting files
file rose/src/frontend/SageIII/sageSupport.C: void SgFile::secondaryPassOverSourceFile() { ... processOpenMP(sourceFile); ... } void processOpenMP(SgSourceFile *sageFilePtr) {
attachOmpAttributeInfo(sageFilePtr); // Build OpenMP AST nodes based on parsing results build_OpenMP_AST(sageFilePtr); lower_omp(sageFilePtr); } // find all SgPragmaDeclaration nodes within a file and parse OpenMP pragmas into OmpAttribute info. void attachOmpAttributeInfo(SgSourceFile *sageFilePtr) { // For C/C++, search pragma declarations for OpenMP directives std::vector <SgNode*> all_pragmas = NodeQuery::querySubTree (sageFilePtr, V_SgPragmaDeclaration); std::vector<SgNode*>::iterator iter; for(iter=all_pragmas.begin();iter!=all_pragmas.end();iter++) { SgPragmaDeclaration* pragmaDeclaration = isSgPragmaDeclaration(*iter); ROSE_ASSERT(pragmaDeclaration != NULL); SageInterface::replaceMacroCallsWithExpandedStrings(pragmaDeclaration); string pragmaString = pragmaDeclaration->get_pragma()->get_pragma(); istringstream istr(pragmaString); std::string key; istr >> key; if (key == "omp") { OmpAttributeList* previous = getOmpAttributeList(pragmaDeclaration); // store them into a buffer, reused by build_OpenMP_AST() omp_pragma_list.push_back(pragmaDeclaration); if (previous == NULL ) { // Call parser omp_parser_init(pragmaDeclaration,pragmaString.c_str()); omp_parse(); OmpAttribute* attribute = getParsedDirective(); addOmpAttribute(attribute,pragmaDeclaration); } } }// end for } } void build_OpenMP_AST(SgSourceFile *sageFilePtr) { // build AST for OpenMP directives and clauses // by converting OmpAttributeList to SgOmpxxx Nodes if (sageFilePtr->get_Fortran_only()||sageFilePtr->get_F77_only()||sageFilePtr->get_F90_only()|| sageFilePtr->get_F95_only() || sageFilePtr->get_F2003_only()) { printf("AST construction for Fortran OpenMP is not yet implemented. \n"); assert(false); } // end if (fortran) else { // for C/C++ pragma's OmpAttributeList --> SgOmpxxx nodes convert_OpenMP_pragma_to_AST( sageFilePtr); } } //! Convert omp_pragma_list to SgOmpxxx nodes void convert_OpenMP_pragma_to_AST (SgSourceFile *sageFilePtr) { list<SgPragmaDeclaration* >::reverse_iterator iter; // bottom up handling for nested cases for (iter = omp_pragma_list.rbegin(); iter != omp_pragma_list.rend(); iter ++) { OmpAttributeList* oattlist= getOmpAttributeList(decl); vector <OmpAttribute* > ompattlist = oattlist->ompAttriList; vector <OmpAttribute* >::iterator i = ompattlist.begin(); for (; i!=ompattlist.end(); i++) { OmpAttribute* oa = *i; omp_construct_enum omp_type = oa->getOmpDirectiveType(); SgStatement* omp_stmt = NULL; switch (omp_type) { // simplest OMP directives case e_barrier: { omp_stmt = new SgOmpBarrierStatement(); break; } ... case e_parallel: case e_for: { omp_stmt = buildOmpBodyStatement(oa); break; } case e_parallel_for: case e_parallel_sections: //case e_parallel_workshare://TODO fortran { omp_stmt = buildOmpParallelStatementFromCombinedDirectives(oa); break; } } setOneSourcePositionForTransformation(omp_stmt); replaceOmpPragmaWithOmpStatement(decl, omp_stmt); } // end for (OmpAttribute) }// end for (omp_pragma_list) }
SgOmpBodyStatement * buildOmpBodyStatement(OmpAttribute* att) {
SgStatement* body = getOpenMPBlockFromOmpAttribte(att); SgOmpBodyStatement* result = NULL; switch (att->getOmpDirectiveType()) { ... case e_parallel: result = new SgOmpParallelStatement(NULL, body); break; case e_for: result = new SgOmpForStatement(NULL, body); break; ... } return result;
}
void lower_omp(SgSourceFile* file) { patchUpPrivateVariables(file); patchUpFirstprivateVariables(file); insertRTLHeaders(file); insertRTLinitAndCleanCode(file); Rose_STL_Container<SgNode*> nodeList = NodeQuery::querySubTree(file, V_SgStatement); Rose_STL_Container<SgNode*>::reverse_iterator nodeListIterator = nodeList.rbegin(); for ( ;nodeListIterator !=nodeList.rend(); ++nodeListIterator) { SgStatement* node = isSgStatement(*nodeListIterator); switch (node->variantT()) { case V_SgOmpParallelStatement: { transOmpParallel(node); break; } case V_SgOmpTaskStatement: {...} case V_SgOmpForStatement: { transOmpFor(node); break; } case V_SgOmpBarrierStatement: { } case V_SgOmpFlushStatement: { } case V_SgOmpThreadprivateStatement: { } case V_SgOmpTaskwaitStatement: { } case V_SgOmpSingleStatement: { } case V_SgOmpMasterStatement: { } case V_SgOmpAtomicStatement: { } case V_SgOmpOrderedStatement: { } case V_SgOmpCriticalStatement: { } default: { /* do nothing */ } }// switch } } //! Patch up private variables for omp for. The reason is that loop indices should be private by default and this function will make this explicit. This should happen before the actual translation is done. int patchUpPrivateVariables(SgFile* file) { Rose_STL_Container<SgNode*> nodeList = NodeQuery::querySubTree(file, V_SgOmpForStatement); Rose_STL_Container<SgNode*>::iterator nodeListIterator = nodeList.begin(); // For each omp for statement for ( ;nodeListIterator !=nodeList.end(); ++nodeListIterator) { SgOmpForStatement* node = isSgOmpForStatement(*nodeListIterator); SgScopeStatement* directive_scope = node->get_scope(); Rose_STL_Container<SgNode*> loops = NodeQuery::querySubTree(node->get_body(), V_SgForStatement); Rose_STL_Container<SgNode*>::iterator loopIter = loops.begin(); for (; loopIter!= loops.end(); loopIter++) { SgInitializedName* index_var = getLoopIndexVariable(*loopIter); SgScopeStatement* var_scope = index_var->get_scope(); // Only loop index variables declared in higher or the same scopes matter if (isAncestor(var_scope, directive_scope) || var_scope==directive_scope) { // add it into the private variable list if (!isInClauseVariableList(index_var, node, V_SgOmpPrivateClause)) { result ++; addClauseVariable(index_var,node, V_SgOmpPrivateClause); } } } // end for loops }// end for omp for statments return result; } // end patchUpPrivateVariables() // rose/src/midend/programTransformation/ompLowering/omp_lowering.cpp:603 void transOmpFor(SgNode* node) { SgOmpForStatement* target = isSgOmpForStatement(node); SgScopeStatement* p_scope = target->get_scope(); SgStatement * body = target->get_body(); // The OpenMP syntax requires that the omp for pragma is immediately followed by the for loop. SgForStatement * for_loop = isSgForStatement(body); // Step 1. Loop normalization // we reuse the normalization from SageInterface, though it is different from what gomp expects. // the point is to have a consistent loop form. We can adjust the difference later on. SageInterface::forLoopNormalization(for_loop); SgInitializedName * orig_index = NULL; SgExpression* orig_lower = NULL; SgExpression* orig_upper= NULL; SgExpression* orig_stride= NULL; bool isIncremental = true; // if the loop iteration space is incremental // grab the original loop 's controlling information bool is_canonical = isCanonicalForLoop (for_loop, &orig_index, & orig_lower, &orig_upper, &orig_stride, NULL, &isIncremental); ROSE_ASSERT(is_canonical == true); // step 2. Insert a basic block to replace SgOmpForStatement SgBasicBlock * bb1 = SageBuilder::buildBasicBlock(); replaceStatement(target, bb1, true); // Declare local loop control variables: _p_loop_index _p_loop_lower _p_loop_upper , no change to the original stride SgType* loop_var_type = NULL ; // xomp interface expects long for some runtime calls now, 6/9/2010 loop_var_type = buildLongType(); SgVariableDeclaration* index_decl = buildVariableDeclaration("_p_index", loop_var_type , NULL,bb1); SgVariableDeclaration* lower_decl = buildVariableDeclaration("_p_lower", loop_var_type , NULL,bb1); SgVariableDeclaration* upper_decl = buildVariableDeclaration("_p_upper", loop_var_type , NULL,bb1); appendStatement(index_decl, bb1); appendStatement(lower_decl, bb1); appendStatement(upper_decl, bb1); // Grab or calculate chunk_size SgExpression* my_chunk_size = NULL; bool hasSpecifiedSize = false; Rose_STL_Container<SgOmpClause*> clauses = getClause(target, V_SgOmpScheduleClause); if (clauses.size() !=0) {... } // step 3. Translation for omp for if (!useStaticSchedule(target) || hasOrder || hasSpecifiedSize) { transOmpFor_others( target, index_decl, lower_decl, upper_decl, bb1); } else { ... // adjust start and end iterations for the current thread for static scheduling // --------------------------------------------------------------- // int _p_thread_id = omp_get_thread_num (); SgVariableDeclaration* thread_id_decl = buildVariableDeclaration("_p_thread_id", buildIntType(), buildAssignInitializer(buildFunctionCallExp("omp_get_thread_num", buildVoidType(), NULL, bb1)), bb1); appendStatement(thread_id_decl, bb1); // _p_lower = lower + _p_chunk_size * _p_thread_id * stride; SgExprStatement * assign_lower = buildAssignStatement(buildVarRefExp(lower_decl), buildAddOp(copyExpression(orig_lower), buildMultiplyOp( buildMultiplyOp( copyExpression(my_chunk_size), buildVarRefExp(thread_id_decl)) , createAdjustedStride(orig_stride,isIncremental) )) ); appendStatement(assign_lower, bb1); // _p_upper = _p_lower + _p_chunk_size * stride; // _p_upper = _p_lower + (_p_chunk_size) * stride -1; // we normalized loop to have inclusive upper bound, so -1 is needed // _p_upper = _p_lower + (_p_chunk_size) * stride +1; // +1 if decremental int upperAdjust; if (isIncremental) upperAdjust = -1; else upperAdjust = 1; SgExprStatement * assign_upper = buildAssignStatement(buildVarRefExp(upper_decl), buildAddOp( buildAddOp(buildVarRefExp(lower_decl), buildMultiplyOp(copyExpression(my_chunk_size), createAdjustedStride(orig_stride,isIncremental))), buildIntVal(upperAdjust))); appendStatement(assign_upper, bb1); // _p_upper = _p_upper<upper? _p_upper: upper; //or _p_upper = _p_upper>upper? _p_upper: upper; if decremental SgExpression* cond_exp = NULL; if (isIncremental) cond_exp = buildLessThanOp(buildVarRefExp(upper_decl), copyExpression(orig_upper)); else cond_exp = buildGreaterThanOp(buildVarRefExp(upper_decl), copyExpression(orig_upper)); assign_upper = buildAssignStatement(buildVarRefExp(upper_decl), buildConditionalExp(cond_exp, buildVarRefExp(upper_decl), copyExpression(orig_upper) )); appendStatement(assign_upper, bb1); // add loop here appendStatement(for_loop, bb1); // replace loop index with the new one replaceVariableReferences(for_loop, isSgVariableSymbol(orig_index->get_symbol_from_symbol_table()), getFirstVarSym(index_decl)) ; // rewrite the lower and upper bounds SageInterface::setLoopLowerBound(for_loop, buildVarRefExp(lower_decl)); SageInterface::setLoopUpperBound(for_loop, buildVarRefExp(upper_decl)); transOmpVariables(target, bb1,orig_upper); // This should happen before the barrier is inserted. // insert barrier if there is no nowait clause if (!hasClause(target, V_SgOmpNowaitClause)) appendStatement(buildFunctionCallStmt("GOMP_barrier", buildVoidType(), NULL, bb1), bb1); } }
bool SageInterface::forLoopNormalization(SgForStatement *loop)
Translations are : For test expression: i<x is normalized to i<= (x-1) and i>x is normalized to i>= (x+1) For increment expression: i++ is normalized to i+=1 and i-- is normalized to i+=-1 i-=s is normalized to i+= -s