void Unparse_Jovial::unparseIfStmt(SgStatement* stmt, SgUnparse_Info& info) { SgIfStmt* if_stmt = isSgIfStmt(stmt); ROSE_ASSERT(if_stmt != NULL); ROSE_ASSERT(if_stmt->get_conditional()); // condition curprint("IF ("); info.set_inConditional(); SgExprStatement* expressionStatement = isSgExprStatement(if_stmt->get_conditional()); unparseExpression(expressionStatement->get_expression(), info); info.unset_inConditional(); curprint(") ;"); unp->cur.insert_newline(1); // true body ROSE_ASSERT(if_stmt->get_true_body()); unparseStatement(if_stmt->get_true_body(), info); // false body if (if_stmt->get_false_body() != NULL) { curprint("ELSE"); unp->cur.insert_newline(1); unparseStatement(if_stmt->get_false_body(), info); } }
void Unparse_Jovial::unparseSwitchStmt(SgStatement* stmt, SgUnparse_Info& info) { // Sage node corresponding to Jovial CaseStatement; SgSwitchStatement* switch_stmt = isSgSwitchStatement(stmt); ROSE_ASSERT(switch_stmt != NULL); curprint("CASE "); SgExprStatement* expressionStatement = isSgExprStatement(switch_stmt->get_item_selector()); ROSE_ASSERT(expressionStatement != NULL); unparseExpression(expressionStatement->get_expression(), info); curprint(";"); unp->cur.insert_newline(1); curprint("BEGIN"); unp->cur.insert_newline(1); if (switch_stmt->get_body()) { unparseStatement(switch_stmt->get_body(), info); } unp->cur.insert_newline(1); curprint("END"); unp->cur.insert_newline(1); unp->cur.insert_newline(1); }
bool findCallsWithFuncArgs2(SgNode *node, string &str) { SgExprStatement *statement; if (statement = isSgExprStatement(node)) { SgFunctionCallExp *call_exp; if (call_exp = isSgFunctionCallExp(statement->get_the_expr())) { m_nodes.clear(); m_nodes.insert(call_exp); m_domain.expand(&m_nodes, QRQueryDomain::all_children); m_domain.getNodes()->erase(call_exp); NodeQuery::VariantVector vector (V_SgFunctionCallExp); QRQueryOpVariant op(vector); op.performQuery(&m_domain, &m_range); unsigned hits = m_range.countRange(); if (hits) { set<SgNode *> *rnodes = m_range.getNodes(); for (set<SgNode *>::iterator iter = rnodes->begin(); iter != rnodes->end(); ) { SgFunctionCallExp *exp = (SgFunctionCallExp *) *iter; iter++; SgExpression *funcexpr = exp->get_function(); str += funcexpr->unparseToString(); if (iter != rnodes->end()) { str += ", "; } } return true; } } } return false; }
virtual void visit (SgNode * node) { SgExprStatement * isExprStatement = isSgExprStatement ( node ); if ( isExprStatement != NULL ) { SgFunctionCallExp * functionCallExp = isSgFunctionCallExp ( isExprStatement->get_expression() ); if ( functionCallExp != NULL ) { string const calleeName = functionCallExp->getAssociatedFunctionSymbol ()->get_name ().getString (); Debug::getInstance ()->debugMessage ("Found function call in user subroutine " + calleeName + "'", Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__); /* * ====================================================== * As we are in fortran, all user subroutines must be * SgProcedureHeaderStatements = subroutines and not * functions. This might be extended to cover also * functions in the future (?). Probably not in OP2 * ====================================================== */ SgProcedureHeaderStatement * isProcedureHeaderStatement = isSgProcedureHeaderStatement ( functionCallExp->getAssociatedFunctionDeclaration() ); calledRoutines.push_back ( isProcedureHeaderStatement ); } } }
SgExpression* doFdVariableUpdate( RewriteRule* rules, SgExpression* cache, SgExpression* old_val /* Cannot be referenced in output tree w/o copying */, SgExpression* new_val) { #ifdef FD_DEBUG cout << "Trying to convert from " << old_val->unparseToString() << " to " << new_val->unparseToString() << ", using cache " << cache->unparseToString() << endl; #endif SgTreeCopy tc; SgExpression* old_valCopy = isSgExpression(old_val->copy(tc)); ROSE_ASSERT (old_valCopy); SgCommaOpExp* innerComma = new SgCommaOpExp(SgNULL_FILE, old_valCopy, new_val); old_valCopy->set_parent(innerComma); new_val->set_parent(innerComma); SgExpression* expr = new SgCommaOpExp(SgNULL_FILE,cache,innerComma); cache->set_parent(expr); innerComma->set_parent(expr); // This is done so rewrite's expression replacement code will never find a // NULL parent for the expression being replaced SgExprStatement* dummyExprStatement = new SgExprStatement(SgNULL_FILE, expr); expr->set_parent(dummyExprStatement); SgNode* exprCopyForRewrite = expr; rewrite(rules, exprCopyForRewrite); // This might modify exprCopyForRewrite ROSE_ASSERT (isSgExpression(exprCopyForRewrite)); expr = isSgExpression(exprCopyForRewrite); expr->set_parent(NULL); dummyExprStatement->set_expression(NULL); delete dummyExprStatement; SgExpression* expr2 = expr; ROSE_ASSERT (expr2); if (// The rewrite rules may have changed the form of expr to something other than a comma pair isSgCommaOpExp(expr2) && isSgCommaOpExp(isSgCommaOpExp(expr2)->get_rhs_operand())) { SgExpression* cache2 = isSgCommaOpExp(expr2)->get_lhs_operand(); SgCommaOpExp* rhs = isSgCommaOpExp(isSgCommaOpExp(expr2)->get_rhs_operand()); // SgExpression* old_val2 = rhs->get_lhs_operand(); SgExpression* new_val2 = rhs->get_rhs_operand(); // return new SgAssignOp(SgNULL_FILE, cache2, new_val2); cache2->set_lvalue(true); SgAssignOp* assignmentOperator = new SgAssignOp(SgNULL_FILE, cache2, new_val2); cache2->set_parent(assignmentOperator); new_val2->set_parent(assignmentOperator); #ifdef FD_DEBUG printf ("In doFdVariableUpdate(): assignmentOperator = %p \n",assignmentOperator); #endif return assignmentOperator; } else { return expr2; } }
virtual void visit(SgNode* n) { if (isSgBasicBlock(n)) { SgBasicBlock* bb = isSgBasicBlock(n); SgStatementPtrList& stmts = bb->get_statements(); size_t initi; for (size_t decli = 0; decli < stmts.size(); ++decli) { if (isSgVariableDeclaration(stmts[decli])) { SgVariableDeclaration* decl = isSgVariableDeclaration(stmts[decli]); SgInitializedNamePtrList& vars = decl->get_variables(); for (size_t vari = 0; vari != vars.size(); ++vari) { SgInitializedName* in = vars[vari]; if (in->get_initializer() == 0) { bool used = false; for (initi = decli + 1; initi < stmts.size(); used |= containsVariableReference(stmts[initi], in), ++initi) { SgExprStatement* initExprStmt = isSgExprStatement(stmts[initi]); if (initExprStmt) { SgExpression* top = initExprStmt->get_expression(); if (isSgAssignOp(top)) { SgVarRefExp* vr = isSgVarRefExp(isSgAssignOp(top)->get_lhs_operand()); ROSE_ASSERT(isSgAssignOp(top) != NULL); SgExpression* newinit = isSgAssignOp(top)->get_rhs_operand(); if (!used && vr && vr->get_symbol()->get_declaration() == in) { ROSE_ASSERT(newinit != NULL); // printf ("MoveDeclarationsToFirstUseVisitor::visit(): newinit = %p = %s \n",newinit,newinit->class_name().c_str()); ROSE_ASSERT(newinit->get_type() != NULL); SgAssignInitializer* i = new SgAssignInitializer(SgNULL_FILE,newinit,newinit->get_type()); i->set_endOfConstruct(SgNULL_FILE); // printf ("Built a SgAssignInitializer #1 \n"); vars[vari]->set_initializer(i); stmts[initi] = decl; newinit->set_parent(i); // DQ (6/23/2006): Set the parent and file_info pointers // printf ("Setting parent of i = %p = %s to parent = %p = %s \n",i,i->class_name().c_str(),in,in->class_name().c_str()); i->set_parent(in); ROSE_ASSERT(i->get_parent() != NULL); i->set_file_info(new Sg_File_Info(*(newinit->get_file_info()))); ROSE_ASSERT(i->get_file_info() != NULL); // Assumes only one var per declaration FIXME ROSE_ASSERT (vars.size() == 1); stmts.erase(stmts.begin() + decli); --decli; // To counteract ++decli in loop header break; // To get out of initi loop } } } } } } } } } }
// Propagate definitions of a variable to its uses. // Assumptions: var is only assigned at the top level of body // nothing var depends on is assigned within body // Very simple algorithm designed to only handle simplest cases void simpleUndoFiniteDifferencingOne(SgBasicBlock* body, SgExpression* var) { SgExpression* value = 0; SgStatementPtrList& stmts = body->get_statements(); vector<SgStatement*> stmts_to_remove; for (SgStatementPtrList::iterator i = stmts.begin(); i != stmts.end(); ++i) { // cout << "Next statement: value = " << (value ? value->unparseToString() : "(null)") << endl; // cout << (*i)->unparseToString() << endl; if (isSgExprStatement(*i) && isSgAssignOp(isSgExprStatement(*i)->get_expression())) { SgAssignOp* assignment = isSgAssignOp(isSgExprStatement(*i)->get_expression()); // cout << "In assignment statement " << assignment->unparseToString() << endl; if (value) replaceCopiesOfExpression(var, value, assignment->get_rhs_operand()); if (isSgVarRefExp(assignment->get_lhs_operand()) && isSgVarRefExp(var)) { SgVarRefExp* vr = isSgVarRefExp(assignment->get_lhs_operand()); if (vr->get_symbol()->get_declaration() == isSgVarRefExp(var)->get_symbol()->get_declaration()) { value = assignment->get_rhs_operand(); stmts_to_remove.push_back(*i); } } } else { if (value) replaceCopiesOfExpression(var, value, *i); } } for (vector<SgStatement*>::iterator i = stmts_to_remove.begin(); i != stmts_to_remove.end(); ++i) { stmts.erase(std::find(stmts.begin(), stmts.end(), *i)); } if (value) { // DQ (12/17/2006): Separate out the construction of the SgAssignOp from the SgExprStatement to support debugging and testing. // stmts.push_back(new SgExprStatement(SgNULL_FILE, new SgAssignOp(SgNULL_FILE, var, value))); var->set_lvalue(true); SgAssignOp* assignmentOperator = new SgAssignOp(SgNULL_FILE, var, value); var->set_parent(assignmentOperator); value->set_parent(assignmentOperator); printf ("In simpleUndoFiniteDifferencingOne(): assignmentOperator = %p \n",assignmentOperator); // DQ: Note that the parent of the SgExprStatement will be set in AST post-processing (or it should be). SgExprStatement* es = new SgExprStatement(SgNULL_FILE, assignmentOperator); assignmentOperator->set_parent(es); stmts.push_back(es); es->set_parent(body); } }
void CompassAnalyses::ExplicitTestForNonBooleanValue::Traversal:: visit(SgNode* node) { // Implement your traversal here. // 1. conditional expression if(NULL != isSgBasicBlock(node)) { Rose_STL_Container<SgNode*> conditionalExpList = NodeQuery::querySubTree(node, V_SgConditionalExp); for(Rose_STL_Container<SgNode*>::iterator i=conditionalExpList.begin(); i != conditionalExpList.end(); i++) { SgConditionalExp* conditionalExp = isSgConditionalExp(*i); //ROSE_ASSERT(conditionalExp != NULL); if(NULL != conditionalExp && NULL != isSgCastExp(conditionalExp->get_conditional_exp())) { output->addOutput(new CheckerOutput(conditionalExp)); } } } else { SgExprStatement* exprStatement = NULL; // 2. test statement in a if statement SgIfStmt* ifStmt = isSgIfStmt(node); if(NULL != ifStmt) exprStatement = isSgExprStatement(ifStmt->get_conditional()); // 3. test statement in a while statement SgWhileStmt* whileStmt = isSgWhileStmt(node); if(NULL != whileStmt) exprStatement = isSgExprStatement(whileStmt->get_condition()); // 4. test statement in a do-while statement SgDoWhileStmt* doWhileStmt = isSgDoWhileStmt(node); if(NULL != doWhileStmt) exprStatement = isSgExprStatement(doWhileStmt->get_condition()); // 5. test statement in a for statement SgForStatement* forStatement = isSgForStatement(node); if(NULL != forStatement) exprStatement = isSgExprStatement(forStatement->get_test()); if(NULL != exprStatement && NULL != isSgCastExp(exprStatement->get_expression())) { output->addOutput(new CheckerOutput(node)); } } } //End of the visit function.
void CompassAnalyses::FloatingPointExactComparison::Traversal:: visit(SgNode* node) { // Implement your traversal here. SgExprStatement* exprStatement = NULL; SgIfStmt* ifStmt = isSgIfStmt(node); if(NULL != ifStmt) exprStatement = isSgExprStatement(ifStmt->get_conditional()); SgWhileStmt* whileStmt = isSgWhileStmt(node); if(NULL != whileStmt) exprStatement = isSgExprStatement(whileStmt->get_condition()); SgDoWhileStmt* doWhileStmt = isSgDoWhileStmt(node); if(NULL != doWhileStmt) exprStatement = isSgExprStatement(doWhileStmt->get_condition()); SgForStatement* forStatement = isSgForStatement(node); if(NULL != forStatement) exprStatement = isSgExprStatement(forStatement->get_test()); if(NULL != exprStatement && NULL != isSgNotEqualOp(exprStatement->get_expression())) { SgNotEqualOp* comparison = isSgNotEqualOp(exprStatement->get_expression()); if((comparison->get_lhs_operand_i() != NULL && isSgDoubleVal(comparison->get_lhs_operand_i()) != NULL) || (comparison->get_rhs_operand_i() != NULL && isSgDoubleVal(comparison->get_rhs_operand_i()) != NULL)) { output->addOutput(new CheckerOutput(comparison)); } } if(NULL != exprStatement && NULL != isSgEqualityOp(exprStatement->get_expression())) { SgEqualityOp* comparison = isSgEqualityOp(exprStatement->get_expression()); if((comparison->get_lhs_operand_i() != NULL && isSgDoubleVal(comparison->get_lhs_operand_i()) != NULL) || (comparison->get_rhs_operand_i() != NULL && isSgDoubleVal(comparison->get_rhs_operand_i()) != NULL)) { output->addOutput(new CheckerOutput(comparison)); } } } //End of the visit function.
bool isHtThreadControlStmt(SgStatement *S) { SgExprStatement *es = isSgExprStatement(S); SgFunctionCallExp *fce = 0; if (es && (fce = isSgFunctionCallExp(es->get_expression()))) { SgFunctionDeclaration *calleeFD = fce->getAssociatedFunctionDeclaration(); std::string fname = calleeFD->get_name().getString(); size_t pos = 0; if (fname == "WriteMemPause" || fname == "ReadMemPause" || fname == "HtBarrier" || (((pos = fname.find("SendCall_")) != std::string::npos /* || (pos = fname.find("SendCallFork_")) != std::string::npos */ || (pos = fname.find("SendReturn_")) != std::string::npos || (pos = fname.find("RecvReturnJoin_")) != std::string::npos) && pos == 0)) { return true; } } return false; }
bool findCallsWithFuncArgs(SgNode *node, string &str) { SgExprStatement *statement; if (statement = isSgExprStatement(node)) { SgFunctionCallExp *call_exp; if (call_exp = isSgFunctionCallExp(statement->get_the_expr())) { m_nodes.clear(); m_nodes.insert(call_exp); m_domain.expand(&m_nodes, QRQueryDomain::all_children); m_domain.getNodes()->erase(call_exp); NodeQuery::VariantVector vector(V_SgFunctionCallExp); QRQueryOpVariant op(vector); op.performQuery(&m_domain, &m_range); unsigned hits = m_range.countRange(); if (hits) { sprintf(m_buffer, "%d", hits); str = m_buffer; return true; } } } return false; }
void FortranCUDAUserSubroutine::createStatements () { using namespace SageInterface; using boost::iequals; using std::string; using std::vector; class TreeVisitor: public AstSimpleProcessing { private: /* * ====================================================== * The recursive visit of a user subroutine populates * this vector with successive function calls which are * then appended after the visit * ====================================================== */ vector < SgProcedureHeaderStatement * > calledRoutines; public: vector < SgProcedureHeaderStatement * > getCalledRoutinesInStatement() { return calledRoutines; } TreeVisitor () { } virtual void visit (SgNode * node) { SgExprStatement * isExprStatement = isSgExprStatement ( node ); if ( isExprStatement != NULL ) { SgFunctionCallExp * functionCallExp = isSgFunctionCallExp ( isExprStatement->get_expression() ); if ( functionCallExp != NULL ) { string const calleeName = functionCallExp->getAssociatedFunctionSymbol ()->get_name ().getString (); Debug::getInstance ()->debugMessage ("Found function call in user subroutine " + calleeName + "'", Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__); /* * ====================================================== * As we are in fortran, all user subroutines must be * SgProcedureHeaderStatements = subroutines and not * functions. This might be extended to cover also * functions in the future (?). Probably not in OP2 * ====================================================== */ SgProcedureHeaderStatement * isProcedureHeaderStatement = isSgProcedureHeaderStatement ( functionCallExp->getAssociatedFunctionDeclaration() ); calledRoutines.push_back ( isProcedureHeaderStatement ); } } } }; Debug::getInstance ()->debugMessage ("User subroutine: outputting and modifying statements", Debug::FUNCTION_LEVEL, __FILE__, __LINE__); SgFunctionParameterList * originalParameters = originalSubroutine->get_parameterList (); vector <SgStatement *> originalStatements = originalSubroutine->get_definition ()->get_body ()->get_statements (); for (vector <SgStatement *>::iterator it = originalStatements.begin (); it != originalStatements.end (); ++it) { SgExprStatement * isExprStatement = isSgExprStatement ( *it ); if ( isExprStatement != NULL ) { SgFunctionCallExp * functionCallExp = isSgFunctionCallExp ( isExprStatement->get_expression() ); if ( functionCallExp != NULL ) { string const calleeName = functionCallExp->getAssociatedFunctionSymbol ()->get_name ().getString (); Debug::getInstance ()->debugMessage ("Found function call in user subroutine " + calleeName + "'", Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__); /* * ====================================================== * As we are in fortran, all user subroutines must be * SgProcedureHeaderStatements = subroutines and not * functions. This might be extended to cover also * functions in the future (probably not in OP2) * ====================================================== */ SgProcedureHeaderStatement * isProcedureHeaderStatement = isSgProcedureHeaderStatement ( functionCallExp->getAssociatedFunctionDeclaration() ); calledRoutines.push_back ( isProcedureHeaderStatement ); } } SgVariableDeclaration * isVariableDeclaration = isSgVariableDeclaration ( *it); if (isVariableDeclaration == NULL) { /* * ====================================================== * Do not append use statement, because other subroutines * are directly appended to the CUDA module * ====================================================== */ SgUseStatement * isUseStmt = isSgUseStatement ( *it ); if (isUseStmt != NULL) { Debug::getInstance ()->debugMessage ( "Not appending use statement", Debug::HIGHEST_DEBUG_LEVEL, __FILE__, __LINE__); } else { Debug::getInstance ()->debugMessage ( "Appending (non-variable-declaration) statement", Debug::HIGHEST_DEBUG_LEVEL, __FILE__, __LINE__); appendStatement (*it, subroutineScope); /* * ====================================================== * Recursively look for subroutine calls inside shallow * nodes in the routines (e.g. when a call is inside an * if). After the visit get the generated vector of names * and append it to the userSubroutine vector * ====================================================== */ TreeVisitor * visitor = new TreeVisitor (); visitor->traverse (*it, preorder); Debug::getInstance ()->debugMessage ("Appending deep subroutine calls", Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__); vector < SgProcedureHeaderStatement * > deepStatementCalls = visitor->getCalledRoutinesInStatement (); vector < SgProcedureHeaderStatement * >::iterator itDeepCalls; for (itDeepCalls = deepStatementCalls.begin(); itDeepCalls != deepStatementCalls.end(); ++itDeepCalls) calledRoutines.push_back (*itDeepCalls); Debug::getInstance ()->debugMessage ("Appending deep subroutine calls", Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__); } } else { Debug::getInstance ()->debugMessage ("Appending variable declaration", Debug::HIGHEST_DEBUG_LEVEL, __FILE__, __LINE__); unsigned int OP_DAT_ArgumentGroup = 1; for (SgInitializedNamePtrList::iterator variableIt = isVariableDeclaration->get_variables ().begin (); variableIt != isVariableDeclaration->get_variables ().end (); ++variableIt) { string const variableName = (*variableIt)->get_name ().getString (); SgType * type = (*variableIt)->get_typeptr (); /* * ====================================================== * Specification of "value" attribute is only * for user kernels. Our call convention is that * in all deeper level calls we always pass parameters * by reference (see else branch below) * ====================================================== */ bool isFormalParamater = false; for (SgInitializedNamePtrList::iterator paramIt = originalParameters->get_args ().begin (); paramIt != originalParameters->get_args ().end (); ++paramIt, ++OP_DAT_ArgumentGroup) { string const formalParamterName = (*paramIt)->get_name ().getString (); if (iequals (variableName, formalParamterName)) { isFormalParamater = true; if (parallelLoop->isIndirect (OP_DAT_ArgumentGroup) && parallelLoop->isRead (OP_DAT_ArgumentGroup)) { Debug::getInstance ()->debugMessage ("'" + variableName + "' is an INDIRECT formal parameter which is READ", Debug::HIGHEST_DEBUG_LEVEL, __FILE__, __LINE__); SgVariableDeclaration * variableDeclaration; if ( isUserKernel == true ) variableDeclaration = FortranStatementsAndExpressionsBuilder::appendVariableDeclarationAsFormalParameter ( variableName, type, subroutineScope, formalParameters, 0); else variableDeclaration = FortranStatementsAndExpressionsBuilder::appendVariableDeclarationAsFormalParameter ( variableName, type, subroutineScope, formalParameters, 0); ROSE_ASSERT ( variableDeclaration != NULL ); } else if (parallelLoop->isGlobal (OP_DAT_ArgumentGroup) && parallelLoop->isRead (OP_DAT_ArgumentGroup)) { Debug::getInstance ()->debugMessage ("'" + variableName + "' is a GLOBAL formal parameter which is READ", Debug::HIGHEST_DEBUG_LEVEL, __FILE__, __LINE__); SgVariableDeclaration * variableDeclaration = FortranStatementsAndExpressionsBuilder::appendVariableDeclarationAsFormalParameter ( variableName, type, subroutineScope, formalParameters, 0); } else { Debug::getInstance ()->debugMessage ("'" + variableName + "' is a formal parameter " + parallelLoop->getOpDatInformation (OP_DAT_ArgumentGroup), Debug::HIGHEST_DEBUG_LEVEL, __FILE__, __LINE__); if ( isUserKernel == true ) SgVariableDeclaration * variableDeclaration = FortranStatementsAndExpressionsBuilder::appendVariableDeclarationAsFormalParameter ( variableName, type, subroutineScope, formalParameters, 0); else SgVariableDeclaration * variableDeclaration = FortranStatementsAndExpressionsBuilder::appendVariableDeclarationAsFormalParameter ( variableName, type, subroutineScope, formalParameters, 0); } } } if (isFormalParamater == false) { Debug::getInstance ()->debugMessage ("'" + variableName + "' is NOT a formal parameter", Debug::HIGHEST_DEBUG_LEVEL, __FILE__, __LINE__); SgVariableDeclaration * variableDeclaration = FortranStatementsAndExpressionsBuilder::appendVariableDeclaration ( variableName, type, subroutineScope); } } } } }
// Main inliner code. Accepts a function call as a parameter, and inlines // only that single function call. Returns true if it succeeded, and false // otherwise. The function call must be to a named function, static member // function, or non-virtual non-static member function, and the function // must be known (not through a function pointer or member function // pointer). Also, the body of the function must already be visible. // Recursive procedures are handled properly (when allowRecursion is set), by // inlining one copy of the procedure into itself. Any other restrictions on // what can be inlined are bugs in the inliner code. bool doInline(SgFunctionCallExp* funcall, bool allowRecursion) { #if 0 // DQ (4/6/2015): Adding code to check for consitancy of checking the isTransformed flag. ROSE_ASSERT(funcall != NULL); ROSE_ASSERT(funcall->get_parent() != NULL); SgGlobal* globalScope = TransformationSupport::getGlobalScope(funcall); ROSE_ASSERT(globalScope != NULL); // checkTransformedFlagsVisitor(funcall->get_parent()); checkTransformedFlagsVisitor(globalScope); #endif SgExpression* funname = funcall->get_function(); SgExpression* funname2 = isSgFunctionRefExp(funname); SgDotExp* dotexp = isSgDotExp(funname); SgArrowExp* arrowexp = isSgArrowExp(funname); SgExpression* thisptr = 0; if (dotexp || arrowexp) { funname2 = isSgBinaryOp(funname)->get_rhs_operand(); if (dotexp) { SgExpression* lhs = dotexp->get_lhs_operand(); // FIXME -- patch this into p_lvalue bool is_lvalue = lhs->get_lvalue(); if (isSgInitializer(lhs)) is_lvalue = false; if (!is_lvalue) { SgAssignInitializer* ai = SageInterface::splitExpression(lhs); ROSE_ASSERT (isSgInitializer(ai->get_operand())); #if 1 printf ("ai = %p ai->isTransformation() = %s \n",ai,ai->isTransformation() ? "true" : "false"); #endif SgInitializedName* in = isSgInitializedName(ai->get_parent()); ROSE_ASSERT (in); removeRedundantCopyInConstruction(in); lhs = dotexp->get_lhs_operand(); // Should be a var ref now } thisptr = new SgAddressOfOp(SgNULL_FILE, lhs); } else if (arrowexp) { thisptr = arrowexp->get_lhs_operand(); } else { assert (false); } } if (!funname2) { // std::cout << "Inline failed: not a call to a named function" << std::endl; return false; // Probably a call through a fun ptr } SgFunctionSymbol* funsym = 0; if (isSgFunctionRefExp(funname2)) funsym = isSgFunctionRefExp(funname2)->get_symbol(); else if (isSgMemberFunctionRefExp(funname2)) funsym = isSgMemberFunctionRefExp(funname2)->get_symbol(); else assert (false); assert (funsym); if (isSgMemberFunctionSymbol(funsym) && isSgMemberFunctionSymbol(funsym)->get_declaration()->get_functionModifier().isVirtual()) { // std::cout << "Inline failed: cannot inline virtual member functions" << std::endl; return false; } SgFunctionDeclaration* fundecl = funsym->get_declaration(); fundecl = fundecl ? isSgFunctionDeclaration(fundecl->get_definingDeclaration()) : NULL; SgFunctionDefinition* fundef = fundecl ? fundecl->get_definition() : NULL; if (!fundef) { // std::cout << "Inline failed: no definition is visible" << std::endl; return false; // No definition of the function is visible } if (!allowRecursion) { SgNode* my_fundef = funcall; while (my_fundef && !isSgFunctionDefinition(my_fundef)) { // printf ("Before reset: my_fundef = %p = %s \n",my_fundef,my_fundef->class_name().c_str()); my_fundef = my_fundef->get_parent(); ROSE_ASSERT(my_fundef != NULL); // printf ("After reset: my_fundef = %p = %s \n",my_fundef,my_fundef->class_name().c_str()); } // printf ("After reset: my_fundef = %p = %s \n",my_fundef,my_fundef->class_name().c_str()); assert (isSgFunctionDefinition(my_fundef)); if (isSgFunctionDefinition(my_fundef) == fundef) { std::cout << "Inline failed: trying to inline a procedure into itself" << std::endl; return false; } } SgVariableDeclaration* thisdecl = 0; SgName thisname("this__"); thisname << ++gensym_counter; SgInitializedName* thisinitname = 0; if (isSgMemberFunctionSymbol(funsym) && !fundecl->get_declarationModifier().get_storageModifier().isStatic()) { assert (thisptr != NULL); SgType* thisptrtype = thisptr->get_type(); const SgSpecialFunctionModifier& specialMod = funsym->get_declaration()->get_specialFunctionModifier(); if (specialMod.isConstructor()) { SgFunctionType* ft = funsym->get_declaration()->get_type(); ROSE_ASSERT (ft); SgMemberFunctionType* mft = isSgMemberFunctionType(ft); ROSE_ASSERT (mft); SgType* ct = mft->get_class_type(); thisptrtype = new SgPointerType(ct); } SgConstVolatileModifier& thiscv = fundecl->get_declarationModifier().get_typeModifier().get_constVolatileModifier(); // if (thiscv.isConst() || thiscv.isVolatile()) { FIXME thisptrtype = new SgModifierType(thisptrtype); isSgModifierType(thisptrtype)->get_typeModifier().get_constVolatileModifier() = thiscv; // } // cout << thisptrtype->unparseToString() << " --- " << thiscv.isConst() << " " << thiscv.isVolatile() << endl; SgAssignInitializer* assignInitializer = new SgAssignInitializer(SgNULL_FILE, thisptr); assignInitializer->set_endOfConstruct(SgNULL_FILE); #if 1 printf ("before new SgVariableDeclaration(): assignInitializer = %p assignInitializer->isTransformation() = %s \n",assignInitializer,assignInitializer->isTransformation() ? "true" : "false"); #endif thisdecl = new SgVariableDeclaration(SgNULL_FILE, thisname, thisptrtype, assignInitializer); #if 1 printf ("(after new SgVariableDeclaration(): assignInitializer = %p assignInitializer->isTransformation() = %s \n",assignInitializer,assignInitializer->isTransformation() ? "true" : "false"); #endif thisdecl->set_endOfConstruct(SgNULL_FILE); thisdecl->get_definition()->set_endOfConstruct(SgNULL_FILE); thisdecl->set_definingDeclaration(thisdecl); thisinitname = (thisdecl->get_variables()).back(); //thisinitname = lastElementOfContainer(thisdecl->get_variables()); // thisinitname->set_endOfConstruct(SgNULL_FILE); assignInitializer->set_parent(thisinitname); markAsTransformation(assignInitializer); // printf ("Built new SgVariableDeclaration #1 = %p \n",thisdecl); // DQ (6/23/2006): New test ROSE_ASSERT(assignInitializer->get_parent() != NULL); } // Get the list of actual argument expressions from the function call, which we'll later use to initialize new local // variables in the inlined code. We need to detach the actual arguments from the AST here since we'll be reattaching // them below (otherwise we would violate the invariant that the AST is a tree). SgFunctionDefinition* targetFunction = PRE::getFunctionDefinition(funcall); SgExpressionPtrList funargs = funcall->get_args()->get_expressions(); funcall->get_args()->get_expressions().clear(); BOOST_FOREACH (SgExpression *actual, funargs) actual->set_parent(NULL); // Make a copy of the to-be-inlined function so we're not modifying and (re)inserting the original. SgBasicBlock* funbody_raw = fundef->get_body(); SgInitializedNamePtrList& params = fundecl->get_args(); std::vector<SgInitializedName*> inits; SgTreeCopy tc; SgFunctionDefinition* function_copy = isSgFunctionDefinition(fundef->copy(tc)); ROSE_ASSERT (function_copy); SgBasicBlock* funbody_copy = function_copy->get_body(); renameLabels(funbody_copy, targetFunction); ASSERT_require(funbody_raw->get_symbol_table()->size() == funbody_copy->get_symbol_table()->size()); // We don't need to keep the copied SgFunctionDefinition now that the labels in it have been moved to the target function // (having it in the memory pool confuses the AST tests), but we must not delete the formal argument list or the body // because we need them below. if (function_copy->get_declaration()) { ASSERT_require(function_copy->get_declaration()->get_parent() == function_copy); function_copy->get_declaration()->set_parent(NULL); function_copy->set_declaration(NULL); } if (function_copy->get_body()) { ASSERT_require(function_copy->get_body()->get_parent() == function_copy); function_copy->get_body()->set_parent(NULL); function_copy->set_body(NULL); } delete function_copy; function_copy = NULL; #if 0 SgPragma* pragmaBegin = new SgPragma("start_of_inline_function", SgNULL_FILE); SgPragmaDeclaration* pragmaBeginDecl = new SgPragmaDeclaration(SgNULL_FILE, pragmaBegin); pragmaBeginDecl->set_endOfConstruct(SgNULL_FILE); pragmaBegin->set_parent(pragmaBeginDecl); pragmaBeginDecl->set_definingDeclaration(pragmaBeginDecl); funbody_copy->prepend_statement(pragmaBeginDecl); pragmaBeginDecl->set_parent(funbody_copy); #endif // In the to-be-inserted function body, create new local variables with distinct non-conflicting names, one per formal // argument and having the same type as the formal argument. Initialize those new local variables with the actual // arguments. Also, build a paramMap that maps each formal argument (SgInitializedName) to its corresponding new local // variable (SgVariableSymbol). ReplaceParameterUseVisitor::paramMapType paramMap; SgInitializedNamePtrList::iterator formalIter = params.begin(); SgExpressionPtrList::iterator actualIter = funargs.begin(); for (size_t argNumber=0; formalIter != params.end() && actualIter != funargs.end(); ++argNumber, ++formalIter, ++actualIter) { SgInitializedName *formalArg = *formalIter; SgExpression *actualArg = *actualIter; // Build the new local variable. // FIXME[Robb P. Matzke 2014-12-12]: we need a better way to generate a non-conflicting local variable name SgAssignInitializer* initializer = new SgAssignInitializer(SgNULL_FILE, actualArg, formalArg->get_type()); ASSERT_not_null(initializer); initializer->set_endOfConstruct(SgNULL_FILE); #if 1 printf ("initializer = %p initializer->isTransformation() = %s \n",initializer,initializer->isTransformation() ? "true" : "false"); #endif SgName shadow_name(formalArg->get_name()); shadow_name << "__" << ++gensym_counter; SgVariableDeclaration* vardecl = new SgVariableDeclaration(SgNULL_FILE, shadow_name, formalArg->get_type(), initializer); vardecl->set_definingDeclaration(vardecl); vardecl->set_endOfConstruct(SgNULL_FILE); vardecl->get_definition()->set_endOfConstruct(SgNULL_FILE); vardecl->set_parent(funbody_copy); // Insert the new local variable into the (near) beginning of the to-be-inserted function body. We insert them in the // order their corresponding actuals/formals appear, although the C++ standard does not require this order of // evaluation. SgInitializedName* init = vardecl->get_variables().back(); inits.push_back(init); initializer->set_parent(init); init->set_scope(funbody_copy); funbody_copy->get_statements().insert(funbody_copy->get_statements().begin() + argNumber, vardecl); SgVariableSymbol* sym = new SgVariableSymbol(init); paramMap[formalArg] = sym; funbody_copy->insert_symbol(shadow_name, sym); sym->set_parent(funbody_copy->get_symbol_table()); } // Similarly for "this". We create a local variable in the to-be-inserted function body that will be initialized with the // caller's "this". if (thisdecl) { thisdecl->set_parent(funbody_copy); thisinitname->set_scope(funbody_copy); funbody_copy->get_statements().insert(funbody_copy->get_statements().begin(), thisdecl); SgVariableSymbol* thisSym = new SgVariableSymbol(thisinitname); funbody_copy->insert_symbol(thisname, thisSym); thisSym->set_parent(funbody_copy->get_symbol_table()); ReplaceThisWithRefVisitor(thisSym).traverse(funbody_copy, postorder); } ReplaceParameterUseVisitor(paramMap).traverse(funbody_copy, postorder); SgName end_of_inline_name = "rose_inline_end__"; end_of_inline_name << ++gensym_counter; SgLabelStatement* end_of_inline_label = new SgLabelStatement(SgNULL_FILE, end_of_inline_name); end_of_inline_label->set_endOfConstruct(SgNULL_FILE); #if 0 printf ("\n\nCalling AST copy mechanism on a SgBasicBlock \n"); // Need to set the parent of funbody_copy to avoid error. funbody_copy->set_parent(funbody_raw->get_parent()); printf ("This is a copy of funbody_raw = %p to build funbody_copy = %p \n",funbody_raw,funbody_copy); printf ("funbody_raw->get_statements().size() = %" PRIuPTR " \n",funbody_raw->get_statements().size()); printf ("funbody_copy->get_statements().size() = %" PRIuPTR " \n",funbody_copy->get_statements().size()); printf ("funbody_raw->get_symbol_table()->size() = %d \n",(int)funbody_raw->get_symbol_table()->size()); printf ("funbody_copy->get_symbol_table()->size() = %d \n",(int)funbody_copy->get_symbol_table()->size()); printf ("Output the symbol table for funbody_raw \n"); funbody_raw->get_symbol_table()->print("debugging copy problem"); // printf ("Output the symbol table for funbody_copy \n"); // funbody_copy->get_symbol_table()->print("debugging copy problem"); SgProject* project_copy = TransformationSupport::getProject(funbody_raw); ROSE_ASSERT(project_copy != NULL); const int MAX_NUMBER_OF_IR_NODES_TO_GRAPH_FOR_WHOLE_GRAPH = 4000; generateAstGraph(project_copy,MAX_NUMBER_OF_IR_NODES_TO_GRAPH_FOR_WHOLE_GRAPH); #endif funbody_copy->append_statement(end_of_inline_label); end_of_inline_label->set_scope(targetFunction); SgLabelSymbol* end_of_inline_label_sym = new SgLabelSymbol(end_of_inline_label); end_of_inline_label_sym->set_parent(targetFunction->get_symbol_table()); targetFunction->get_symbol_table()->insert(end_of_inline_label->get_name(), end_of_inline_label_sym); // To ensure that there is some statement after the label SgExprStatement* dummyStatement = SageBuilder::buildExprStatement(SageBuilder::buildNullExpression()); dummyStatement->set_endOfConstruct(SgNULL_FILE); funbody_copy->append_statement(dummyStatement); dummyStatement->set_parent(funbody_copy); #if 0 SgPragma* pragmaEnd = new SgPragma("end_of_inline_function", SgNULL_FILE); SgPragmaDeclaration* pragmaEndDecl = new SgPragmaDeclaration(SgNULL_FILE, pragmaEnd); pragmaEndDecl->set_endOfConstruct(SgNULL_FILE); pragmaEnd->set_parent(pragmaEndDecl); pragmaEndDecl->set_definingDeclaration(pragmaEndDecl); funbody_copy->append_statement(pragmaEndDecl); pragmaEndDecl->set_parent(funbody_copy); #endif ChangeReturnsToGotosPrevisitor previsitor = ChangeReturnsToGotosPrevisitor(end_of_inline_label, funbody_copy); replaceExpressionWithStatement(funcall, &previsitor); // Make sure the AST is consistent. To save time, we'll just fix things that we know can go wrong. For instance, the // SgAsmExpression.p_lvalue data member is required to be true for certain operators and is set to false in other // situations. Since we've introduced new expressions into the AST we need to adjust their p_lvalue according to the // operators where they were inserted. markLhsValues(targetFunction); #ifdef NDEBUG AstTests::runAllTests(SageInterface::getProject()); #endif #if 0 // DQ (4/6/2015): Adding code to check for consitancy of checking the isTransformed flag. ROSE_ASSERT(funcall != NULL); ROSE_ASSERT(funcall->get_parent() != NULL); ROSE_ASSERT(globalScope != NULL); // checkTransformedFlagsVisitor(funcall->get_parent()); checkTransformedFlagsVisitor(globalScope); #endif // DQ (4/7/2015): This fixes something I was required to fix over the weekend and which is fixed more directly, I think. // Mark the things we insert as being transformations so they get inserted into the output by backend() markAsTransformation(funbody_copy); return true; }
InheritedAttribute visitorTraversal::evaluateInheritedAttribute(SgNode* n, InheritedAttribute inheritedAttribute) { Sg_File_Info* s = n->get_startOfConstruct(); Sg_File_Info* e = n->get_endOfConstruct(); Sg_File_Info* f = n->get_file_info(); for(int x=0; x < inheritedAttribute.depth; ++x) { printf(" "); } if(s != NULL && e != NULL && !isSgLabelStatement(n)) { printf ("%s (%d, %d, %d)->(%d, %d): %s",n->sage_class_name(),s->get_file_id()+1,s->get_raw_line(),s->get_raw_col(),e->get_raw_line(),e->get_raw_col(), verbose ? n->unparseToString().c_str() : "" ); if(isSgAsmDwarfConstruct(n)) { printf(" [DWARF construct name: %s]", isSgAsmDwarfConstruct(n)->get_name().c_str()); } SgExprStatement * exprStmt = isSgExprStatement(n); if(exprStmt != NULL) { printf(" [expr type: %s]", exprStmt->get_expression()->sage_class_name()); SgFunctionCallExp * fcall = isSgFunctionCallExp(exprStmt->get_expression()); if(fcall != NULL) { SgExpression * funcExpr = fcall->get_function(); if(funcExpr != NULL) { printf(" [function expr: %s]", funcExpr->class_name().c_str()); } SgFunctionDeclaration * fdecl = fcall->getAssociatedFunctionDeclaration(); if(fdecl != NULL) { printf(" [called function: %s]", fdecl->get_name().str()); } } } if(isSgFunctionDeclaration(n)) { printf(" [declares function: %s]", isSgFunctionDeclaration(n)->get_name().str()); } SgStatement * sgStmt = isSgStatement(n); if(sgStmt != NULL) { printf(" [scope: %s, %p]", sgStmt->get_scope()->sage_class_name(), sgStmt->get_scope()); } //SgLabelStatement * lblStmt = isSgLabelStatement(n); //if(lblStmt != NULL) { // SgStatement * lblStmt2 = lblStmt->get_statement(); //} } else if (f != NULL) { SgInitializedName * iname = isSgInitializedName(n); if(iname != NULL) { SgType* inameType = iname->get_type(); printf("%s (%d, %d, %d): %s [type: %s", n->sage_class_name(),f->get_file_id()+1,f->get_raw_line(),f->get_raw_col(),n->unparseToString().c_str(),inameType->class_name().c_str()); SgDeclarationStatement * ds = isSgDeclarationStatement(iname->get_parent()); if(ds != NULL) { if(ds->get_declarationModifier().get_storageModifier().isStatic()) { printf(" static"); } } SgArrayType * art = isSgArrayType(iname->get_type()); if(art != NULL) { printf(" %d", art->get_rank()); } printf("]"); if(isSgAsmDwarfConstruct(n)) { printf(" [DWARF construct name: %s]", isSgAsmDwarfConstruct(n)->get_name().c_str()); } } else { printf("%s (%d, %d, %d): %s", n->sage_class_name(),f->get_file_id()+1,f->get_raw_line(),f->get_raw_col(), verbose ? n->unparseToString().c_str() : ""); } } else { printf("%s : %s", n->sage_class_name(), verbose ? n->unparseToString().c_str() : ""); if(isSgAsmDwarfConstruct(n)) { printf(" [DWARF construct name: %s]", isSgAsmDwarfConstruct(n)->get_name().c_str()); } } printf(" succ# %lu", n->get_numberOfTraversalSuccessors()); printf("\n"); return InheritedAttribute(inheritedAttribute.depth+1); }
// Main inliner code. Accepts a function call as a parameter, and inlines // only that single function call. Returns true if it succeeded, and false // otherwise. The function call must be to a named function, static member // function, or non-virtual non-static member function, and the function // must be known (not through a function pointer or member function // pointer). Also, the body of the function must already be visible. // Recursive procedures are handled properly (when allowRecursion is set), by // inlining one copy of the procedure into itself. Any other restrictions on // what can be inlined are bugs in the inliner code. bool doInline(SgFunctionCallExp* funcall, bool allowRecursion) { SgExpression* funname = funcall->get_function(); SgExpression* funname2 = isSgFunctionRefExp(funname); SgDotExp* dotexp = isSgDotExp(funname); SgArrowExp* arrowexp = isSgArrowExp(funname); SgExpression* thisptr = 0; if (dotexp || arrowexp) { funname2 = isSgBinaryOp(funname)->get_rhs_operand(); if (dotexp) { SgExpression* lhs = dotexp->get_lhs_operand(); // FIXME -- patch this into p_lvalue bool is_lvalue = lhs->get_lvalue(); if (isSgInitializer(lhs)) is_lvalue = false; if (!is_lvalue) { SgAssignInitializer* ai = SageInterface::splitExpression(lhs); ROSE_ASSERT (isSgInitializer(ai->get_operand())); SgInitializedName* in = isSgInitializedName(ai->get_parent()); ROSE_ASSERT (in); removeRedundantCopyInConstruction(in); lhs = dotexp->get_lhs_operand(); // Should be a var ref now } thisptr = new SgAddressOfOp(SgNULL_FILE, lhs); } else if (arrowexp) { thisptr = arrowexp->get_lhs_operand(); } else { assert (false); } } if (!funname2) { // std::cout << "Inline failed: not a call to a named function" << std::endl; return false; // Probably a call through a fun ptr } SgFunctionSymbol* funsym = 0; if (isSgFunctionRefExp(funname2)) funsym = isSgFunctionRefExp(funname2)->get_symbol(); else if (isSgMemberFunctionRefExp(funname2)) funsym = isSgMemberFunctionRefExp(funname2)->get_symbol(); else assert (false); assert (funsym); if (isSgMemberFunctionSymbol(funsym) && isSgMemberFunctionSymbol(funsym)->get_declaration()->get_functionModifier().isVirtual()) { // std::cout << "Inline failed: cannot inline virtual member functions" << std::endl; return false; } SgFunctionDeclaration* fundecl = funsym->get_declaration(); SgFunctionDefinition* fundef = fundecl->get_definition(); if (!fundef) { // std::cout << "Inline failed: no definition is visible" << std::endl; return false; // No definition of the function is visible } if (!allowRecursion) { SgNode* my_fundef = funcall; while (my_fundef && !isSgFunctionDefinition(my_fundef)) { // printf ("Before reset: my_fundef = %p = %s \n",my_fundef,my_fundef->class_name().c_str()); my_fundef = my_fundef->get_parent(); ROSE_ASSERT(my_fundef != NULL); // printf ("After reset: my_fundef = %p = %s \n",my_fundef,my_fundef->class_name().c_str()); } // printf ("After reset: my_fundef = %p = %s \n",my_fundef,my_fundef->class_name().c_str()); assert (isSgFunctionDefinition(my_fundef)); if (isSgFunctionDefinition(my_fundef) == fundef) { std::cout << "Inline failed: trying to inline a procedure into itself" << std::endl; return false; } } SgVariableDeclaration* thisdecl = 0; SgName thisname("this__"); thisname << ++gensym_counter; SgInitializedName* thisinitname = 0; if (isSgMemberFunctionSymbol(funsym) && !fundecl->get_declarationModifier().get_storageModifier().isStatic()) { assert (thisptr != NULL); SgType* thisptrtype = thisptr->get_type(); const SgSpecialFunctionModifier& specialMod = funsym->get_declaration()->get_specialFunctionModifier(); if (specialMod.isConstructor()) { SgFunctionType* ft = funsym->get_declaration()->get_type(); ROSE_ASSERT (ft); SgMemberFunctionType* mft = isSgMemberFunctionType(ft); ROSE_ASSERT (mft); SgType* ct = mft->get_class_type(); thisptrtype = new SgPointerType(ct); } SgConstVolatileModifier& thiscv = fundecl->get_declarationModifier().get_typeModifier().get_constVolatileModifier(); // if (thiscv.isConst() || thiscv.isVolatile()) { FIXME thisptrtype = new SgModifierType(thisptrtype); isSgModifierType(thisptrtype)->get_typeModifier().get_constVolatileModifier() = thiscv; // } // cout << thisptrtype->unparseToString() << " --- " << thiscv.isConst() << " " << thiscv.isVolatile() << endl; SgAssignInitializer* assignInitializer = new SgAssignInitializer(SgNULL_FILE, thisptr); assignInitializer->set_endOfConstruct(SgNULL_FILE); // thisdecl = new SgVariableDeclaration(SgNULL_FILE, thisname, thisptrtype, new SgAssignInitializer(SgNULL_FILE, thisptr)); thisdecl = new SgVariableDeclaration(SgNULL_FILE, thisname, thisptrtype, assignInitializer); thisdecl->set_endOfConstruct(SgNULL_FILE); thisdecl->get_definition()->set_endOfConstruct(SgNULL_FILE); thisdecl->set_definingDeclaration(thisdecl); thisinitname = (thisdecl->get_variables()).back(); //thisinitname = lastElementOfContainer(thisdecl->get_variables()); // thisinitname->set_endOfConstruct(SgNULL_FILE); assignInitializer->set_parent(thisinitname); // printf ("Built new SgVariableDeclaration #1 = %p \n",thisdecl); // DQ (6/23/2006): New test ROSE_ASSERT(assignInitializer->get_parent() != NULL); } std::cout << "Trying to inline function " << fundecl->get_name().str() << std::endl; SgBasicBlock* funbody_raw = fundef->get_body(); SgInitializedNamePtrList& params = fundecl->get_args(); SgInitializedNamePtrList::iterator i; SgExpressionPtrList& funargs = funcall->get_args()->get_expressions(); SgExpressionPtrList::iterator j; //int ctr; // unused variable, Liao std::vector<SgInitializedName*> inits; SgTreeCopy tc; SgFunctionDefinition* function_copy = isSgFunctionDefinition(fundef->copy(tc)); ROSE_ASSERT (function_copy); SgBasicBlock* funbody_copy = function_copy->get_body(); SgFunctionDefinition* targetFunction = PRE::getFunctionDefinition(funcall); renameLabels(funbody_copy, targetFunction); std::cout << "Original symbol count: " << funbody_raw->get_symbol_table()->size() << std::endl; std::cout << "Copied symbol count: " << funbody_copy->get_symbol_table()->size() << std::endl; // std::cout << "Original symbol count f: " << fundef->get_symbol_table()->size() << std::endl; // std::cout << "Copied symbol count f: " << function_copy->get_symbol_table()->size() << std::endl; // We don't need to keep the copied function definition now that the // labels in it have been moved to the target function. Having it in the // memory pool confuses the AST tests. function_copy->set_declaration(NULL); function_copy->set_body(NULL); delete function_copy; function_copy = NULL; #if 0 SgPragma* pragmaBegin = new SgPragma("start_of_inline_function", SgNULL_FILE); SgPragmaDeclaration* pragmaBeginDecl = new SgPragmaDeclaration(SgNULL_FILE, pragmaBegin); pragmaBeginDecl->set_endOfConstruct(SgNULL_FILE); pragmaBegin->set_parent(pragmaBeginDecl); pragmaBeginDecl->set_definingDeclaration(pragmaBeginDecl); funbody_copy->prepend_statement(pragmaBeginDecl); pragmaBeginDecl->set_parent(funbody_copy); #endif ReplaceParameterUseVisitor::paramMapType paramMap; for (i = params.begin(), j = funargs.begin(); i != params.end() && j != funargs.end(); ++i, ++j) { SgAssignInitializer* ai = new SgAssignInitializer(SgNULL_FILE, *j, (*i)->get_type()); ROSE_ASSERT(ai != NULL); ai->set_endOfConstruct(SgNULL_FILE); SgName shadow_name((*i)->get_name()); shadow_name << "__" << ++gensym_counter; SgVariableDeclaration* vardecl = new SgVariableDeclaration(SgNULL_FILE,shadow_name,(*i)->get_type(),ai); vardecl->set_definingDeclaration(vardecl); vardecl->set_endOfConstruct(SgNULL_FILE); vardecl->get_definition()->set_endOfConstruct(SgNULL_FILE); printf ("Built new SgVariableDeclaration #2 = %p = %s initializer = %p \n",vardecl,shadow_name.str(),(*(vardecl->get_variables().begin()))->get_initializer()); vardecl->set_parent(funbody_copy); SgInitializedName* init = (vardecl->get_variables()).back(); // init->set_endOfConstruct(SgNULL_FILE); inits.push_back(init); ai->set_parent(init); init->set_scope(funbody_copy); funbody_copy->get_statements().insert(funbody_copy->get_statements().begin() + (i - params.begin()), vardecl); SgVariableSymbol* sym = new SgVariableSymbol(init); paramMap[*i] = sym; funbody_copy->insert_symbol(shadow_name, sym); sym->set_parent(funbody_copy->get_symbol_table()); } if (thisdecl) { thisdecl->set_parent(funbody_copy); thisinitname->set_scope(funbody_copy); funbody_copy->get_statements().insert(funbody_copy->get_statements().begin(), thisdecl); SgVariableSymbol* thisSym = new SgVariableSymbol(thisinitname); funbody_copy->insert_symbol(thisname, thisSym); thisSym->set_parent(funbody_copy->get_symbol_table()); ReplaceThisWithRefVisitor(thisSym).traverse(funbody_copy, postorder); } ReplaceParameterUseVisitor(paramMap).traverse(funbody_copy, postorder); SgName end_of_inline_name = "rose_inline_end__"; end_of_inline_name << ++gensym_counter; SgLabelStatement* end_of_inline_label = new SgLabelStatement(SgNULL_FILE, end_of_inline_name); end_of_inline_label->set_endOfConstruct(SgNULL_FILE); #if 0 printf ("\n\nCalling AST copy mechanism on a SgBasicBlock \n"); // Need to set the parent of funbody_copy to avoid error. funbody_copy->set_parent(funbody_raw->get_parent()); printf ("This is a copy of funbody_raw = %p to build funbody_copy = %p \n",funbody_raw,funbody_copy); printf ("funbody_raw->get_statements().size() = %zu \n",funbody_raw->get_statements().size()); printf ("funbody_copy->get_statements().size() = %zu \n",funbody_copy->get_statements().size()); printf ("funbody_raw->get_symbol_table()->size() = %d \n",(int)funbody_raw->get_symbol_table()->size()); printf ("funbody_copy->get_symbol_table()->size() = %d \n",(int)funbody_copy->get_symbol_table()->size()); printf ("Output the symbol table for funbody_raw \n"); funbody_raw->get_symbol_table()->print("debugging copy problem"); // printf ("Output the symbol table for funbody_copy \n"); // funbody_copy->get_symbol_table()->print("debugging copy problem"); SgProject* project_copy = TransformationSupport::getProject(funbody_raw); ROSE_ASSERT(project_copy != NULL); const int MAX_NUMBER_OF_IR_NODES_TO_GRAPH_FOR_WHOLE_GRAPH = 4000; generateAstGraph(project_copy,MAX_NUMBER_OF_IR_NODES_TO_GRAPH_FOR_WHOLE_GRAPH); #endif // printf ("Exiting as a test after testing the symbol table \n"); // ROSE_ASSERT(false); funbody_copy->append_statement(end_of_inline_label); end_of_inline_label->set_scope(targetFunction); SgLabelSymbol* end_of_inline_label_sym = new SgLabelSymbol(end_of_inline_label); end_of_inline_label_sym->set_parent(targetFunction->get_symbol_table()); targetFunction->get_symbol_table()->insert(end_of_inline_label->get_name(), end_of_inline_label_sym); // To ensure that there is some statement after the label SgExprStatement* dummyStatement = SageBuilder::buildExprStatement(SageBuilder::buildNullExpression()); dummyStatement->set_endOfConstruct(SgNULL_FILE); funbody_copy->append_statement(dummyStatement); dummyStatement->set_parent(funbody_copy); #if 0 SgPragma* pragmaEnd = new SgPragma("end_of_inline_function", SgNULL_FILE); SgPragmaDeclaration* pragmaEndDecl = new SgPragmaDeclaration(SgNULL_FILE, pragmaEnd); pragmaEndDecl->set_endOfConstruct(SgNULL_FILE); pragmaEnd->set_parent(pragmaEndDecl); pragmaEndDecl->set_definingDeclaration(pragmaEndDecl); funbody_copy->append_statement(pragmaEndDecl); pragmaEndDecl->set_parent(funbody_copy); #endif // std::cout << "funbody_copy is " << funbody_copy->unparseToString() << std::endl; ChangeReturnsToGotosPrevisitor previsitor = ChangeReturnsToGotosPrevisitor(end_of_inline_label, funbody_copy); // std::cout << "funbody_copy 2 is " << funbody_copy->unparseToString() << std::endl; replaceExpressionWithStatement(funcall, &previsitor); // std::cout << "Inline succeeded " << funcall->get_parent()->unparseToString() << std::endl; return true; }
//Generates SSA form numbers for the variables contained in the CFG node labeled *label and attaches them as AstValueAttributes to the related SgNodes //Generates phi statements for the node if it is an if node; Collects those phi statements in a phi attribute and attaches it to the related SgNode //Continues the traversal of the CFG; The CFG nodes are traversed in the topological order that treats if nodes as follows: //if node -> true branch -> false branch -> (phi statements for the if node are now finished) -> if node's associated continue node and its successors //Assumption: The node is located in in the inTrueBranch branch of the if node labeled *condLabel (These two arguments are required to generate the SSA form numbers) void SSAGenerator::processNode(Label* label, Label* condLabel, bool inTrueBranch) { SgNode* node = labeler->getNode(*label); LabelSet successors = flow->succ(*label); assert(successors.size() <= 2); //Skip the current node if it is just a return node for a called function if(labeler->isFunctionCallReturnLabel(*label)) { logger[Sawyer::Message::DEBUG] << "- - - - - - - - - - - - - - - - - - - - - - - - -" << endl; logger[Sawyer::Message::DEBUG] << "Ignoring function call return node " << *label << endl; assert(successors.size() == 1); Label nextLabel = *successors.begin(); //If the next node is not the continue node to any of the enclosing condition nodes and not the exit node: Process it if(!isExitOrContOfPred(&nextLabel, label)) processNode(&nextLabel, condLabel, inTrueBranch); return; } logger[Sawyer::Message::DEBUG] << "- - - - - - - - - - - - - - - - - - - - - - - - -" << endl; logger[Sawyer::Message::DEBUG] << "processNode() called for label " << *label << endl; SgVariableDeclaration* varDec = dynamic_cast<SgVariableDeclaration*>(node); SgExprStatement* exprStmt = dynamic_cast<SgExprStatement*>(node); if(varDec) //Variable declaration { SgInitializedNamePtrList varNames = varDec->get_variables(); SgInitializedNamePtrList::iterator i = varNames.begin(); while(i != varNames.end()) { string name = (*i)->get_qualified_name(); //Update the varsDeclaredInTrueBranch/varsDeclaredInFalseBranch attribute in the PhiAttribute of the condition node if(condLabel != NULL) { SgNode* condNode = labeler->getNode(*condLabel); AstAttribute* condAtt = condNode->getAttribute("PHI"); assert(condAtt != NULL); PhiAttribute* condPhiAtt = dynamic_cast<PhiAttribute*>(condAtt); assert(condPhiAtt != NULL); if(inTrueBranch) condPhiAtt->varsDeclaredInTrueBranch.insert(name); else condPhiAtt->varsDeclaredInFalseBranch.insert(name); } SgAssignInitializer* assignInit = dynamic_cast<SgAssignInitializer*>((*i)->get_initializer()); if(assignInit) //Declaration with initialization { SgExpression* ex = assignInit->get_operand(); processSgExpression(ex, condLabel, inTrueBranch); } else //Declaration without initialization { assert((*i)->get_initializer() == NULL); } //Assign number to declared variable int number = nextNumber(name, condLabel, inTrueBranch); logger[Sawyer::Message::DEBUG] << "Next number for variable " << name << ": " << number << endl; AstValueAttribute<int>* numberAtt = new AstValueAttribute<int>(number); (*i)->setAttribute("SSA_NUMBER", numberAtt); i++; } } else if(exprStmt) //Assignment to variable or if statement or function call or ... { SgExpression* ex = exprStmt->get_expression(); processSgExpression(ex, condLabel, inTrueBranch); } else //CFG node that is not a variable declaration and not an expression statement; Should only be the case for the first node (Entry), the last node (Exit) and return nodes { logger[Sawyer::Message::DEBUG] << "Node is not a variable declaration and not an expression statement" << endl; SgReturnStmt* retStmt = dynamic_cast<SgReturnStmt*>(node); assert(labeler->isFunctionEntryLabel(*label) || labeler->isFunctionExitLabel(*label) || retStmt != NULL); } //Continue traversal of CFG if(successors.size() == 1) //Current node is a regular node (not an if node) { Label nextLabel = *successors.begin(); //If the next node is not the continue node to any of the enclosing condition nodes and not the exit node: Process it if(!isExitOrContOfPred(&nextLabel, label)) processNode(&nextLabel, condLabel, inTrueBranch); } else if(successors.size() == 2) //Current node is an if node { assert(exprStmt != NULL); //Attach PhiAttribute to node that (for now) only includes its reaching variable numbers map<string, int> reachingNumbers = currentNumberMap; if(condLabel != NULL) { SgNode* condNode = labeler->getNode(*condLabel); AstAttribute* condAtt = condNode->getAttribute("PHI"); assert(condAtt != NULL); PhiAttribute* condPhiAtt = dynamic_cast<PhiAttribute*>(condAtt); assert(condPhiAtt != NULL); map<string, int>::iterator m = reachingNumbers.begin(); while(m != reachingNumbers.end()) { //m->first is in scope at the current node only if it is in scope at the condition node or it is declared locally in the current node's branch of the condition node bool inScope = (condPhiAtt->reachingNumbers.find(m->first) != condPhiAtt->reachingNumbers.end()) || (inTrueBranch && condPhiAtt->varsDeclaredInTrueBranch.find(m->first) != condPhiAtt->varsDeclaredInTrueBranch.end()) || (!inTrueBranch && condPhiAtt->varsDeclaredInFalseBranch.find(m->first) != condPhiAtt->varsDeclaredInFalseBranch.end()); if(!inScope) { m = reachingNumbers.erase(m); continue; } //Reaching number for m->first has to be updated //TODO: Makes no sense to take reaching numbers from current numbers in the first place m->second = currentNumber(m->first, condLabel, inTrueBranch); m++; } } CondAtomic* cond = new CondAtomic(*label); PhiAttribute* phiAtt = new PhiAttribute(reachingNumbers, cond); exprStmt->setAttribute("PHI", phiAtt); //Identify true successor, false successor and continue node Flow trueOutEdges = flow->outEdgesOfType(*label, EDGE_TRUE); Flow falseOutEdges = flow->outEdgesOfType(*label, EDGE_FALSE); assert( (trueOutEdges.size() == 1) && (falseOutEdges.size() == 1) ); Edge outTrue = *trueOutEdges.begin(); Edge outFalse = *falseOutEdges.begin(); Label nextLabelTrue = outTrue.target(); Label nextLabelFalse = outFalse.target(); Label* contLabel = getContinueLabel(*label); //Process true and false branch ContNodeAttribute* contAttr = getContinueNodeAttr(*label); bool commitPhiStatements = true; //"Hack": //If one or both of the two branches definitely return there will be phi statements created for the current node although the SSA form that is being created here does not require them in that case //They are however required to find out current variable numbers in the branch/branches that definitely return //Therefore in that case the phi statements will be created but not committed if (contAttr == NULL) //Both branches definitely return { if(!isExitOrContOrContOfPred(&nextLabelTrue, label)) processNode(&nextLabelTrue, label, true); //"Hack" if(!isExitOrContOrContOfPred(&nextLabelFalse, label)) processNode(&nextLabelFalse, label, false); //"Hack" commitPhiStatements = false; } else if (contAttr->trueBranchReturns == YES && contAttr->falseBranchReturns != YES) //Only the true branch definitely returns { if(!isExitOrContOrContOfPred(&nextLabelTrue, label)) processNode(&nextLabelTrue, label, true); //"Hack" if(condLabel == NULL) //No enclosing condition node exists { //"Hack"-phi-statement needs to be used to determine current variable numbers because processing the true branch modified currentNumberMap if(!isExitOrContOrContOfPred(&nextLabelFalse, label)) processNode(&nextLabelFalse, label, inTrueBranch); } else if(!isExitOrContOrContOfPred(&nextLabelFalse, label)) processNode(&nextLabelFalse, condLabel, inTrueBranch); commitPhiStatements = false; } else if (contAttr->trueBranchReturns != YES && contAttr->falseBranchReturns == YES) //Only the false branch definitely returns { if(!isExitOrContOrContOfPred(&nextLabelTrue, label)) processNode(&nextLabelTrue, condLabel, inTrueBranch); if(!isExitOrContOrContOfPred(&nextLabelFalse, label)) processNode(&nextLabelFalse, label, false); //"Hack" commitPhiStatements = false; } else //Neither of the two branches definitely returns { assert(!(contAttr->trueBranchReturns == YES && contAttr->falseBranchReturns == YES)); if(!isExitOrContOrContOfPred(&nextLabelTrue, label)) processNode(&nextLabelTrue, label, true); if(!isExitOrContOrContOfPred(&nextLabelFalse, label)) processNode(&nextLabelFalse, label, false); commitPhiStatements = true; } if(commitPhiStatements) //Commit phi statements: Generate a new number for the variable of each phi statement and save that number in its respective newNumber attribute { vector<PhiStatement*>::iterator i = phiAtt->phiStatements.begin(); logger[Sawyer::Message::DEBUG] << "- - - - - - - - - - - - - - - - - - - - - - - - -" << endl; logger[Sawyer::Message::DEBUG] << "Phi statements created for node with label " << *label << ":" << endl; while (i != phiAtt->phiStatements.end()) { if((*i)->trueNumber != (*i)->falseNumber) { //Generate new number for phi statement's variable int newNumber = nextNumber((*i)->varName, condLabel, inTrueBranch); (*i)->newNumber = newNumber; logger[Sawyer::Message::DEBUG] << (*i)->toString() << endl; } i++; } logger[Sawyer::Message::DEBUG] << "- - - - - - - - - - - - - - - - - - - - - - - - -" << endl; logger[Sawyer::Message::DEBUG] << "COMPLETE PHI ATTRIBUTE:" << endl << phiAtt->toString() << endl; } else //Delete phi statements ("Hack") { phiAtt->phiStatements.clear(); } //If the continue node exists and is not the continue node to any of the enclosing condition nodes and not the exit node: Process it if(contLabel != NULL && !isExitOrContOfPred(contLabel, label)) { processNode(contLabel, condLabel, inTrueBranch); } } }
// Supporting function (not one of the global functions required for the Query interface) ArrayAssignmentStatementQuerySynthesizedAttributeType ArrayAssignmentStatementTransformation::expressionStatementTransformation(SgExprStatement* astNode, ArrayAssignmentStatementQueryInheritedAttributeType & arrayAssignmentStatementQueryInheritedData, const ArrayAssignmentStatementQuerySynthesizedAttributeType & innerLoopTransformation, OperandDataBaseType & operandDataBase) { // Since we input the operandDataBase we could skip the initial AST queries and query the data base instead. // (the operandDataBase has more information than the initial queries represent). #if DEBUG cout << " TOP of expressionStatementTransformation " << astNode->unparseToString() << endl; #endif // declaration of return value ArrayAssignmentStatementQuerySynthesizedAttributeType returnSynthesizedAttribute; string returnString; printf("In expressionStatementTransformation(): operandDataBase.displayString() = %s \n", operandDataBase.displayString().c_str()); // Make sure the data base has been setup properly ROSE_ASSERT(operandDataBase.transformationOption > ArrayTransformationSupport::UnknownIndexingAccess); ROSE_ASSERT(operandDataBase.dimension > -1); // printf ("######################### START OF VARIABLE TYPE NAME QUERY ######################## \n"); //list<string> operandNameStringList = NameQuery::getVariableNamesWithTypeNameQuery (astNode, "doubleArray" ); printf(" Kamal - Need to handle NameQuery \n"); // Commented below two lines Kamal // NameQuerySynthesizedAttributeType operandNameStringList = // NameQuery::querySubTree ( // astNode, // "doubleArray", // NameQuery::VariableNamesWithTypeName ); // printf ("Print out the list of variable names: \n%s \n",StringUtility::listToString(operandNameStringList).c_str()); // Now use STL to build a list of unique names // Commented the two lines below Kamal //list<string> uniqueOperandNameStringList = operandNameStringList; //uniqueOperandNameStringList.unique(); // printf ("Print out the list of unique variable names: \n%s \n",StringUtility::listToString(uniqueOperandNameStringList).c_str()); // printf ("######################### START OF VARIABLE NAME QUERY ######################## \n"); // Specify optimization assertions defined by user (specified by the user in his application code) operandDataBase.setUserOptimizationAssertions(arrayAssignmentStatementQueryInheritedData.transformationOptions); // This query gets the indexing code for each operand used in the expression statement // (but for now we make them all the same, later we will support the optimization of indexing of individual array operands) // Query the operand data base to find out the global properties of the indexing in the array statement // int globalIndexingProperties = ArrayTransformationSupport::UniformSizeUniformStride; // int globalIndexingProperties = operandDataBase.globalIndexingProperties(); // printf ("globalIndexingProperties = %d \n",globalIndexingProperties); #if DEBUG cout << " Creating unique operand list " << endl; #endif operandDataBase.removeDups(); printf("######################### END OF ALL PRELIMINARY QUERIES ######################## \n"); // Template string into which we substitute the variableData and loopNestString strings string transformationTemplateString = "\ // Automatically Introduced Transformation (via preprocessor built by ROSE)\n\n"; attachComment(astNode, transformationTemplateString); // ####################################### // COMPUTE THE GLOBAL DECLARATIONS // ####################################### // A string to hold the variables required for this transformation // Build the variable data into the array statment transformation string globalDeclarations = ""; #if OLD ArrayTransformationSupport::buildOperandSpecificGlobalDeclarations( arrayAssignmentStatementQueryInheritedData, operandDataBase); #endif // printf ("globalDeclarations = \n%s \n",globalDeclarations.c_str()); // ############################################### // COMPUTE THE LOCAL VARIABLE DECLARATIONS // ############################################### // A string to hold the variables required for this transformation // Build the variable data into the array statment transformation // e.g. ARRAY_OPERAND_VARIABLE_SIZE_DECLARATION_MACRO_D6(_A); ArrayTransformationSupport::buildOperandSpecificVariableDeclarations(astNode, arrayAssignmentStatementQueryInheritedData, operandDataBase); // ################################################## // COMPUTE THE LOCAL VARIABLE INITIALIZATIONS // ################################################## // Variable initialization must occur imediately before the transformations using the variables // e.g. ARRAY_OPERAND_VARIABLE_SIZE_INITIALIZATION_MACRO_D6(A,_A); ArrayTransformationSupport::buildOperandSpecificVariableInitialization(astNode, arrayAssignmentStatementQueryInheritedData, operandDataBase); // ############################# // COMPUTE THE LOOP NEST // ############################# // Get the dimensionality of the array statement ROSE_ASSERT(arrayAssignmentStatementQueryInheritedData.arrayStatementDimensionDefined == TRUE); int dimensionOfArrayStatement = arrayAssignmentStatementQueryInheritedData.arrayStatementDimension; // call function to build loop nest string loopNestString; cout << " LoopDependence : " << innerLoopTransformation.getLoopDependence() << endl; if (innerLoopTransformation.getLoopDependence() == TRUE) { #if DEBUG cout << " In innerLoopTransformation.getLoopDependence() = TRUE " << endl; #endif // Kamal (07/21/2011) Do not remove this now since it may be important in certain loops // If a loop dependence was found in the assembly then generate a special form of the // transformation to preserve the array semantics. This can be optimized later to block the // the computation so that we avoid poor use of cache. Add an additional loop nest to the // loopNestString so that we can transform A = A+A into: // _T.redim(lhs); for (...) {_T = A+A;} for (...) {A = _T}; // Insert "T.redim(<lhs>);" at front of loopNestString string lhsArrayOperandName = operandDataBase.arrayOperandList[0].arrayVariableName; cout << "lhsOperandName: " << lhsArrayOperandName << endl; loopNestString = "__T_pointer = _T.getDataPointer(); \n _T.redim(" + lhsArrayOperandName + ");\n" + loopNestString; string temporaryString = innerLoopTransformation.getLoopDependenceLhs(); // Use the same indexing with the temporary as is used with the lhs (copy lhs and change the // variable name (add to data base so that we generate the correct supporting declarations // and initializations)). Since _T is the same size as A we don't have to change the // subscript macro. temporaryString = StringUtility::copyEdit(temporaryString, lhsArrayOperandName, "_T"); attachArbitraryText(getEnclosingStatement(astNode), loopNestString, PreprocessingInfo::before); // Handle Second Loop creation A = Temp SgExprStatement* lhsExprStatement = createSecondLoop(astNode, arrayAssignmentStatementQueryInheritedData, operandDataBase); #if DEBUG cout << " Second Loop lhsExprStatement: " << lhsExprStatement->unparseToString() << endl; #endif ArrayTransformationSupport::buildLoopNest(lhsExprStatement, operandDataBase, dimensionOfArrayStatement); // call function to build loop nest //LHS creation, doesn't create a new node createFirstLoop(astNode, arrayAssignmentStatementQueryInheritedData, operandDataBase); loopNestString = ""; ArrayTransformationSupport::buildLoopNest(astNode, operandDataBase, dimensionOfArrayStatement); #if DEBUG cout << " innerLoopTransformation.getLoopDependence() = TRUE LHS: " << innerLoopTransformation.getLoopDependenceLhs() << " RHS:" << innerLoopTransformation.getLoopDependenceRhs(); #endif #if OLD // *************************************************** // Setup loop bodies for loop dependent transformation // *************************************************** // First loop body string firstLoopBody = innerLoopTransformation.getLoopDependenceRhs(); firstLoopBody = temporaryString + firstLoopBody; firstLoopBody = StringUtility::copyEdit(firstLoopBody, "$ASSIGNMENT_OPERATOR", " = "); // Second loop body string secondLoopBody = innerLoopTransformation.getLoopDependenceLhs(); secondLoopBody = secondLoopBody + string(" = ") + temporaryString; // Mark the first "$INNER_LOOP" substring so that we can differentiate between the first and second loops loopNestString = StringUtility::copyEdit(loopNestString, "$INNER_LOOP", "$FIRST_INNER_LOOP"); //loopNestString += ArrayTransformationSupport::buildLoopNest (astNode, operandDataBase, dimensionOfArrayStatement ); loopNestString = StringUtility::copyEdit(loopNestString, "$INNER_LOOP", "$SECOND_INNER_LOOP"); loopNestString = StringUtility::copyEdit(loopNestString, "$FIRST_INNER_LOOP", firstLoopBody); loopNestString = StringUtility::copyEdit(loopNestString, "$SECOND_INNER_LOOP", secondLoopBody); #if DEBUG printf ("firstLoopBody = %s \n",firstLoopBody.c_str()); printf ("secondLoopBody = %s \n",secondLoopBody.c_str()); printf ("loopNestString = \n%s \n",loopNestString.c_str()); #endif #endif // Add "T" to operand data base for loop dependent array statement // operandDataBase.setVariableName( "_T" ); ArrayOperandDataBase temporaryArrayOperand = operandDataBase.arrayOperandList[0]; temporaryArrayOperand.arrayVariableName = "_T"; operandDataBase.arrayOperandList.push_back(temporaryArrayOperand); } else { #if DEBUG cout << " In innerLoopTransformation.getLoopDependence() = FALSE " << endl; #endif // call function to build loop nest ArrayTransformationSupport::buildLoopNest(astNode, operandDataBase, dimensionOfArrayStatement); } #if DEBUG printf ("Before generation of global declarations: loopNestString = \n%s\n",loopNestString.c_str()); #endif // Reset the workspace to "" in the synthesized attribute (part of general cleanup, but not required) returnSynthesizedAttribute.setWorkSpace(""); return returnSynthesizedAttribute; }
bool ArrayAssignmentStatementTransformation::targetForTransformation(SgNode* astNode) { // This is a static function which returns true when the current node // of the AST is a target for transformation. bool returnValue = FALSE; ROSE_ASSERT (astNode != NULL); // This code used to recognize array statements checks to see if the name of the type of the // function contained in the expression statement is "doubleArray". This code will be // dramatically simplified once we can use the higher level grammars to recognise array // statements. At present this code is not a robust test for the use existence of a transformable // array statement it will be robust once we can use the higher level grammars (AST restructuring // tools) generated by ROSETTA. SgExprStatement *expressionStatement = isSgExprStatement(astNode); // In this example we only perform transformations on declaration statements if (expressionStatement != NULL) { SgExpression* expression = expressionStatement->get_expression(); ROSE_ASSERT (expression != NULL); // See if this is an A++ member function call SgFunctionCallExp* functionCallExp = isSgFunctionCallExp(expression); // ROSE_ASSERT (functionCallExp != NULL); if (functionCallExp != NULL) { SgType* type = functionCallExp->get_type(); ROSE_ASSERT (type != NULL); SgClassType* classType = isSgClassType(type); if (classType == NULL) { // Check to see if it a reference to a class type (and get it's base type) SgType* type = functionCallExp->get_type(); ROSE_ASSERT (type != NULL); SgReferenceType* referenceType = isSgReferenceType(type); if (referenceType != NULL) { ROSE_ASSERT (referenceType != NULL); SgType* baseType = referenceType->get_base_type(); ROSE_ASSERT (baseType != NULL); classType = isSgClassType(baseType); ROSE_ASSERT (classType != NULL); } else { return FALSE; } } ROSE_ASSERT (classType != NULL); // It is the get_name which returns the type name (not the qualified name (I forget what it is for) SgName name = classType->get_name(); if (name == "intArray" || name == "floatArray" || name == "doubleArray") { #if DEBUG printf( "ArrayAssignmentStatementTransformation::targetForTransformation Expression Statement %s \n", expressionStatement->unparseToString().c_str()); #endif returnValue = TRUE; } else { printf( "Not a expression statement containing a function call expression of type {double,float,int}Array ... \n"); } } else { // This case could be "A;" in which case there is no transformation printf("Not a expression statement containing a function call expression ... \n"); } } else { // printf ("Not an expression statement (only expression statements qualify!) \n"); } return returnValue; }
// Do finite differencing on one expression within one context. The expression // must be defined and valid within the entire body of root. The rewrite rules // are used to simplify expressions. When a variable var is updated from // old_value to new_value, an expression of the form (var, (old_value, // new_value)) is created and rewritten. The rewrite rules may either produce // an arbitrary expression (which will be used as-is) or one of the form (var, // (something, value)) (which will be changed to (var = value)). void doFiniteDifferencingOne(SgExpression* e, SgBasicBlock* root, RewriteRule* rules) { SgStatementPtrList& root_stmts = root->get_statements(); SgStatementPtrList::iterator i; for (i = root_stmts.begin(); i != root_stmts.end(); ++i) { if (expressionComputedIn(e, *i)) break; } if (i == root_stmts.end()) return; // Expression is not used within root, so quit vector<SgVariableSymbol*> used_symbols = SageInterface::getSymbolsUsedInExpression(e); SgName cachename = "cache_fd__"; cachename << ++SageInterface::gensym_counter; SgVariableDeclaration* cachedecl = new SgVariableDeclaration(SgNULL_FILE, cachename, e->get_type(),0 /* new SgAssignInitializer(SgNULL_FILE, e) */); SgInitializedName* cachevar = cachedecl->get_variables().back(); ROSE_ASSERT (cachevar); root->get_statements().insert(i, cachedecl); cachedecl->set_parent(root); cachedecl->set_definingDeclaration(cachedecl); cachevar->set_scope(root); SgVariableSymbol* sym = new SgVariableSymbol(cachevar); root->insert_symbol(cachename, sym); SgVarRefExp* vr = new SgVarRefExp(SgNULL_FILE, sym); vr->set_endOfConstruct(SgNULL_FILE); replaceCopiesOfExpression(e, vr, root); vector<SgExpression*> modifications_to_used_symbols; FdFindModifyingStatementsVisitor(used_symbols, modifications_to_used_symbols).go(root); cachedecl->addToAttachedPreprocessingInfo( new PreprocessingInfo(PreprocessingInfo::CplusplusStyleComment,(string("// Finite differencing: ") + cachename.str() + " is a cache of " + e->unparseToString()).c_str(),"Compiler-Generated in Finite Differencing",0, 0, 0, PreprocessingInfo::before)); if (modifications_to_used_symbols.size() == 0) { SgInitializer* cacheinit = new SgAssignInitializer(SgNULL_FILE, e); e->set_parent(cacheinit); cachevar->set_initializer(cacheinit); cacheinit->set_parent(cachevar); } else { for (unsigned int i = 0; i < modifications_to_used_symbols.size(); ++i) { SgExpression* modstmt = modifications_to_used_symbols[i]; #ifdef FD_DEBUG cout << "Updating cache after " << modstmt->unparseToString() << endl; #endif SgExpression* updateCache = 0; SgVarRefExp* varref = new SgVarRefExp(SgNULL_FILE, sym); varref->set_endOfConstruct(SgNULL_FILE); SgTreeCopy tc; SgExpression* eCopy = isSgExpression(e->copy(tc)); switch (modstmt->variantT()) { case V_SgAssignOp: { SgAssignOp* assignment = isSgAssignOp(modstmt); assert (assignment); SgExpression* lhs = assignment->get_lhs_operand(); SgExpression* rhs = assignment->get_rhs_operand(); replaceCopiesOfExpression(lhs, rhs, eCopy); } break; case V_SgPlusAssignOp: case V_SgMinusAssignOp: case V_SgAndAssignOp: case V_SgIorAssignOp: case V_SgMultAssignOp: case V_SgDivAssignOp: case V_SgModAssignOp: case V_SgXorAssignOp: case V_SgLshiftAssignOp: case V_SgRshiftAssignOp: { SgBinaryOp* assignment = isSgBinaryOp(modstmt); assert (assignment); SgExpression* lhs = assignment->get_lhs_operand(); SgExpression* rhs = assignment->get_rhs_operand(); SgTreeCopy tc; SgExpression* rhsCopy = isSgExpression(rhs->copy(tc)); SgExpression* newval = 0; switch (modstmt->variantT()) { #define DO_OP(op, nonassignment) \ case V_##op: { \ newval = new nonassignment(SgNULL_FILE, lhs, rhsCopy); \ newval->set_endOfConstruct(SgNULL_FILE); \ } \ break DO_OP(SgPlusAssignOp, SgAddOp); DO_OP(SgMinusAssignOp, SgSubtractOp); DO_OP(SgAndAssignOp, SgBitAndOp); DO_OP(SgIorAssignOp, SgBitOrOp); DO_OP(SgMultAssignOp, SgMultiplyOp); DO_OP(SgDivAssignOp, SgDivideOp); DO_OP(SgModAssignOp, SgModOp); DO_OP(SgXorAssignOp, SgBitXorOp); DO_OP(SgLshiftAssignOp, SgLshiftOp); DO_OP(SgRshiftAssignOp, SgRshiftOp); #undef DO_OP default: break; } assert (newval); replaceCopiesOfExpression(lhs, newval, eCopy); } break; case V_SgPlusPlusOp: { SgExpression* lhs = isSgPlusPlusOp(modstmt)->get_operand(); SgIntVal* one = new SgIntVal(SgNULL_FILE, 1); one->set_endOfConstruct(SgNULL_FILE); SgAddOp* add = new SgAddOp(SgNULL_FILE, lhs, one); add->set_endOfConstruct(SgNULL_FILE); lhs->set_parent(add); one->set_parent(add); replaceCopiesOfExpression(lhs,add,eCopy); } break; case V_SgMinusMinusOp: { SgExpression* lhs = isSgMinusMinusOp(modstmt)->get_operand(); SgIntVal* one = new SgIntVal(SgNULL_FILE, 1); one->set_endOfConstruct(SgNULL_FILE); SgSubtractOp* sub = new SgSubtractOp(SgNULL_FILE, lhs, one); sub->set_endOfConstruct(SgNULL_FILE); lhs->set_parent(sub); one->set_parent(sub); replaceCopiesOfExpression(lhs,sub,eCopy); } break; default: cerr << modstmt->sage_class_name() << endl; assert (false); break; } #ifdef FD_DEBUG cout << "e is " << e->unparseToString() << endl; cout << "eCopy is " << eCopy->unparseToString() << endl; #endif updateCache = doFdVariableUpdate(rules, varref, e, eCopy); #ifdef FD_DEBUG cout << "updateCache is " << updateCache->unparseToString() << endl; #endif if (updateCache) { ROSE_ASSERT(modstmt != NULL); SgNode* ifp = modstmt->get_parent(); SgCommaOpExp* comma = new SgCommaOpExp(SgNULL_FILE, updateCache, modstmt); modstmt->set_parent(comma); updateCache->set_parent(comma); if (ifp == NULL) { printf ("modstmt->get_parent() == NULL modstmt = %p = %s \n",modstmt,modstmt->class_name().c_str()); modstmt->get_startOfConstruct()->display("modstmt->get_parent() == NULL: debug"); } ROSE_ASSERT(ifp != NULL); #ifdef FD_DEBUG cout << "New expression is " << comma->unparseToString() << endl; cout << "IFP is " << ifp->sage_class_name() << ": " << ifp->unparseToString() << endl; #endif if (isSgExpression(ifp)) { isSgExpression(ifp)->replace_expression(modstmt, comma); comma->set_parent(ifp); } else { // DQ (12/16/2006): Need to handle cases that are not SgExpression (now that SgExpressionRoot is not used!) // cerr << ifp->sage_class_name() << endl; // assert (!"Bad parent type for inserting comma expression"); SgStatement* statement = isSgStatement(ifp); if (statement != NULL) { #ifdef FD_DEBUG printf ("Before statement->replace_expression(): statement = %p = %s modstmt = %p = %s \n",statement,statement->class_name().c_str(),modstmt,modstmt->class_name().c_str()); SgExprStatement* expresionStatement = isSgExprStatement(statement); if (expresionStatement != NULL) { SgExpression* expression = expresionStatement->get_expression(); printf ("expressionStatement expression = %p = %s \n",expression,expression->class_name().c_str()); } #endif statement->replace_expression(modstmt, comma); comma->set_parent(statement); } else { ROSE_ASSERT(ifp != NULL); printf ("Error: parent is neither a SgExpression nor a SgStatement ifp = %p = %s \n",ifp,ifp->class_name().c_str()); ROSE_ASSERT(false); } } #ifdef FD_DEBUG cout << "IFP is now " << ifp->unparseToString() << endl; #endif } } } }
ForLoop::ForLoop( SgForStatement * l ) : BasicNode(LOOPHEAD), myLoop(l), myLoopType(UNDEFINED), start(NULL), end(NULL), body(NULL), back_edge(NULL), out(NULL), Iter(false) { /* STEP 1 : Get initialization expression and symbol */ SgStatementPtrList stmList = myLoop->get_init_stmt(); if ( stmList.size() != 1 ) { report_error("Too many init statements",l); } else if ( isSgVariableDeclaration(stmList[0]) ) { SgInitializedNamePtrList initList = isSgVariableDeclaration(stmList[0])->get_variables(); if ( initList.size() != 1 ) { report_error("To many induction variables",l); } else { SgInitializedName * initName = initList[0]; if ( isSgAssignInitializer(initName->get_initializer()) ) { symbol = initName->get_name().getString(); start = isSgAssignInitializer(initName->get_initializer())->get_operand(); } else { report_error("Loop initializer is too complecated",initName); } } } else if ( isSgExprStatement(stmList[0]) ) { SgExpression * exp = isSgExprStatement(stmList[0])->get_expression(); if ( isSgAssignOp(exp) ) { SgExpression * lhs = isSgAssignOp(exp)->get_lhs_operand(); SgExpression * rhs = isSgAssignOp(exp)->get_rhs_operand(); if ( isSgVarRefExp(lhs) ) { symbol = isSgVarRefExp(lhs)->get_symbol()->get_name().getString(); start = rhs; } else { report_error("LHS of expression must be a single variable",exp); } } else { report_error("Init expression must be an Assign operation",exp); } } else { report_error("Loop initialization is not recognized",l); } /* STEP 2 : Get the test expression */ SgExprStatement * expStm = isSgExprStatement(myLoop->get_test()); if ( expStm ) { SgExpression * exp = expStm->get_expression(); if ( isSgLessOrEqualOp(exp) ) { SgBinaryOp * binOp = isSgBinaryOp(exp); string name = isSgVarRefExp(isSgBinaryOp(exp)->get_lhs_operand())->get_symbol()->get_name().getString(); if ( name != symbol ) report_error("Loop init and test variable miss-match",exp); end = binOp->get_rhs_operand(); } else if ( isSgLessThanOp(exp) ) { SgBinaryOp * binOp = isSgBinaryOp(exp); string name = isSgVarRefExp(binOp->get_lhs_operand())->get_symbol()->get_name().getString(); if ( name != symbol ) report_error("Loop init and test variable miss-match",exp); SgExpression * tempExp = SageInterface::copyExpression(binOp->get_rhs_operand()); end = buildSubtractOp( tempExp, buildIntVal(1) ); end->set_need_paren(true); tempExp = buildLessOrEqualOp( SageInterface::copyExpression(binOp->get_lhs_operand()), end ); SageInterface::replaceExpression(exp, tempExp, false); } else { report_error("Test expression is not recognized. Re-write the loop or normilize it accordingly",exp); } } else { report_error("Test expression is not recognized. Sorry !", l); } /* STEP 3 : Check the stride */ if ( !isSgPlusPlusOp(l->get_increment()) ) report_error("Increment expression is not recognized. Re-write the loop or normilize it accordingly. Note: Only \"++\" operator supported.",l); /* STEP 4 : Link with Loop Tail node */ back_edge = new ForLoop(start,end,symbol,l,this,this,LOOPTAIL); body = back_edge; }
// Move variables declared in a for statement to just outside that statement. void moveForDeclaredVariables(SgNode* root) { vector<SgForStatement*> for_statements; FindForStatementsVisitor(for_statements).traverse(root, preorder); for (unsigned int i = 0; i < for_statements.size(); ++i) { SgForStatement* stmt = for_statements[i]; #ifdef FD_DEBUG cout << "moveForDeclaredVariables: " << stmt->unparseToString() << endl; #endif SgForInitStatement* init = stmt->get_for_init_stmt(); if (!init) continue; SgStatementPtrList& inits = init->get_init_stmt(); vector<SgVariableDeclaration*> decls; for (SgStatementPtrList::iterator j = inits.begin(); j != inits.end(); ++j) { SgStatement* one_init = *j; if (isSgVariableDeclaration(one_init)) { decls.push_back(isSgVariableDeclaration(one_init)); } } if (decls.empty()) continue; SgStatement* parent = isSgStatement(stmt->get_parent()); assert (parent); SgBasicBlock* bb = new SgBasicBlock(SgNULL_FILE); stmt->set_parent(bb); bb->set_parent(parent); SgStatementPtrList ls; for (unsigned int j = 0; j < decls.size(); ++j) { for (SgInitializedNamePtrList::iterator k = decls[j]->get_variables().begin(); k != decls[j]->get_variables().end(); ++k) { #ifdef FD_DEBUG cout << "Working on variable " << (*k)->get_name().getString() << endl; #endif SgVariableSymbol* sym = new SgVariableSymbol(*k); bb->insert_symbol((*k)->get_name(), sym); (*k)->set_scope(bb); SgAssignInitializer* kinit = 0; if (isSgAssignInitializer((*k)->get_initializer())) { kinit = isSgAssignInitializer((*k)->get_initializer()); (*k)->set_initializer(0); } if (kinit) { SgVarRefExp* vr = new SgVarRefExp(SgNULL_FILE, sym); vr->set_endOfConstruct(SgNULL_FILE); vr->set_lvalue(true); SgAssignOp* assignment = new SgAssignOp(SgNULL_FILE,vr,kinit->get_operand()); vr->set_parent(assignment); kinit->get_operand()->set_parent(assignment); SgExprStatement* expr = new SgExprStatement(SgNULL_FILE, assignment); assignment->set_parent(expr); ls.push_back(expr); expr->set_parent(init); } } #if 0 SgStatementPtrList::iterator fiiter = std::find(inits.begin(), inits.end(), decls[j]); assert (fiiter != inits.end()); size_t idx = fiiter - inits.begin(); inits.erase(inits.begin() + idx); inits.insert(inits.begin() + idx, ls.begin(), ls.end()); #endif bb->get_statements().push_back(decls[j]); decls[j]->set_parent(bb); } inits = ls; bb->get_statements().push_back(stmt); // printf ("In moveForDeclaredVariables(): parent = %p = %s bb = %p stmt = %p = %s \n",parent,parent->class_name().c_str(),bb,stmt,stmt->class_name().c_str()); ROSE_ASSERT(stmt->get_parent() == bb); parent->replace_statement(stmt, bb); } }