Rose

How things fits togehter


 void XOMP_parallel_start (void (*func) (void *), void *data, unsigned numThread)
 {
 #ifdef USE_ROSE_GOMP_OPENMP_LIBRARY  
GOMP_parallel_start (func, data, numThread);
  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)
 {
 ...
 }

src-to-src chain

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);
   }

How Rose parses OpenMP

Rose OpenMP Transformation

List of interesting files


 file rose/src/frontend/SageIII/sageSupport.C:
 void SgFile::secondaryPassOverSourceFile()
 {
    ...
    processOpenMP(sourceFile);
    ...
 }

 void processOpenMP(SgSourceFile *sageFilePtr)
   {
// parse OpenMP directives and attach OmpAttributeList to relevant SgNode
     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);
    }
  }

Doxygen Things to remember

 bool SageInterface::forLoopNormalization(SgForStatement *loop) 	
Normalize a for loop, return true if successful.

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