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 ); } } }
/* * Check to see if a variable has its address taken in an I/O operation. */ bool RegisterPointers::isAddrTakenInIrrelevantFunc(SgVarRefExp* expr) { //TODO get function call name /*SgExprStatement* stmt = isSgExprStatement(getEnclosingStatement(expr)); if(!stmt) return false; SgFunctionCallExp* funcCall = isSgFunctionCallExp(stmt->get_expression()); if(!funcCall) return false; string name = NAME(funcCall->getAssociatedFunctionSymbol());*/ SgStatement* encStmt = getEnclosingStatement(expr); SgNode* parent = expr->get_parent(); SgFunctionCallExp* funcCall = NULL; while(parent != encStmt) { funcCall = isSgFunctionCallExp(parent); if(funcCall && (functions.find(NAME(funcCall->getAssociatedFunctionSymbol())) != functions.end())) return true; parent = parent->get_parent(); } /*set<string>::const_iterator funcIt = functions.begin(); for(funcIt = functions.begin(); funcIt != functions.end(); funcIt++) { if(name.find(*funcIt) != string::npos) return true; }*/ return false; }
void evaluateAnalysisStates::visit(const Function& func, const DataflowNode& n, NodeState& state) { SgFunctionCallExp *fnCall = isSgFunctionCallExp(n.getNode()); if (!fnCall) return; if (!fnCall->getAssociatedFunctionSymbol()) return; string funcName = fnCall->getAssociatedFunctionSymbol()->get_name().getString(); if (funcName.find("testFunc") == string::npos) return; FiniteVarsExprsProductLattice *lat = dynamic_cast<FiniteVarsExprsProductLattice *>(state.getLatticeAbove(div)[0]); cout << indent << "Lattice before call to " << funcName << ": " << lat->str() << endl; set<varID> allVars = lat->getAllVars(); for (set<varID>::iterator i = allVars.begin(); i != allVars.end(); ++i) { string name = i->str(); cout << "Variable " << name << " "; if (expectations[funcName].find(name) == expectations[funcName].end()) { cout << "unspecified" << endl; continue; } Lattice *got = lat->getVarLattice(*i); ROSE_ASSERT(got); if (expectations[funcName][name] != got) { cout << "mismatched: " << got->str() << " was not the expected " << expectations[funcName][name].str(); numFails++; } else { cout << "matched"; numPass++; } cout << endl; } }
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); } } } } }
void FortranProgramDeclarationsAndDefinitions::visit (SgNode * node) { using boost::filesystem::path; using boost::filesystem::system_complete; using boost::iequals; using boost::starts_with; using boost::lexical_cast; using std::string; if (isSgSourceFile (node)) { path p = system_complete (path (isSgSourceFile (node)->getFileName ())); currentSourceFile = p.filename (); Debug::getInstance ()->debugMessage ("Source file '" + currentSourceFile + "' detected", Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__ ); } else if (Globals::getInstance ()->isInputFile (currentSourceFile)) { /* * ====================================================== * Only process this portion of the AST if we recognise * this source file as one passed on the command line. In * Fortran, .rmod files are sometimes generated whose * traversal should be avoided * ====================================================== */ switch (node->variantT ()) { case V_SgModuleStatement: { SgModuleStatement * moduleStatement = isSgModuleStatement (node); currentModuleName = moduleStatement->get_name ().getString (); fileNameToModuleNames[currentSourceFile].push_back (currentModuleName); moduleNameToFileName[currentModuleName] = currentSourceFile; Debug::getInstance ()->debugMessage ("Module '" + currentModuleName + "' in file '" + currentSourceFile + "'", Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__ ); break; } case V_SgProcedureHeaderStatement: { /* * ====================================================== * We need to store all subroutine definitions since we * later have to copy and modify the user kernel subroutine * ====================================================== */ SgProcedureHeaderStatement * procedureHeaderStatement = isSgProcedureHeaderStatement (node); string const subroutineName = procedureHeaderStatement->get_name ().getString (); subroutinesInSourceCode[subroutineName] = procedureHeaderStatement; ROSE_ASSERT (currentModuleName.size() > 0); moduleNameToSubroutines[currentModuleName].push_back (subroutineName); subroutineToFileName[subroutineName] = currentSourceFile; Debug::getInstance ()->debugMessage ( "Found procedure header statement '" + procedureHeaderStatement->get_name ().getString () + "' in file '" + currentSourceFile + "', and module '" + currentModuleName + "'", Debug::FUNCTION_LEVEL, __FILE__, __LINE__); break; } case V_SgFunctionCallExp: { /* * ====================================================== * Function call found in the AST. Get its actual arguments * and the callee name * ====================================================== */ SgFunctionCallExp * functionCallExp = isSgFunctionCallExp (node); SgExprListExp * actualArguments = functionCallExp->get_args (); string const calleeName = functionCallExp->getAssociatedFunctionSymbol ()->get_name ().getString (); Debug::getInstance ()->debugMessage ("Found function call '" + calleeName + "'", Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__); if ( iequals (calleeName, OP2::OP_DECL_SET) || iequals (calleeName, OP2::OP_DECL_SET_HDF5) ) { /* * ====================================================== * An OP_SET variable declared through an OP_DECL_SET call * ====================================================== */ bool isHDF5Format = false; if ( iequals (calleeName, OP2::OP_DECL_SET_HDF5) ) isHDF5Format = true; FortranOpSetDefinition * opSetDeclaration = new FortranOpSetDefinition (actualArguments, isHDF5Format); OpSetDefinitions[opSetDeclaration->getVariableName ()] = opSetDeclaration; } else if ( iequals (calleeName, OP2::OP_DECL_MAP) || iequals (calleeName, OP2::OP_DECL_MAP_HDF5) ) { /* * ====================================================== * An OP_MAP variable declared through an OP_DECL_MAP call * ====================================================== */ bool isHDF5Format = false; if ( iequals (calleeName, OP2::OP_DECL_MAP_HDF5) ) { isHDF5Format = true; Debug::getInstance ()->debugMessage ("This is the HDF5 version: '" + calleeName + "'", Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__); } FortranOpMapDefinition * opMapDeclaration = new FortranOpMapDefinition (actualArguments, isHDF5Format); OpMapDefinitions[opMapDeclaration->getVariableName ()] = opMapDeclaration; } else if ( iequals (calleeName, OP2::OP_DECL_DAT) || iequals (calleeName, OP2::OP_DECL_DAT_HDF5) ) { /* * ====================================================== * An OP_DAT variable declared through an OP_DECL_DAT call * ====================================================== */ bool isHDF5Format = false; if ( iequals (calleeName, OP2::OP_DECL_DAT_HDF5) ) isHDF5Format = true; FortranOpDatDefinition * opDatDeclaration = new FortranOpDatDefinition (actualArguments, isHDF5Format); OpDatDefinitions[opDatDeclaration->getVariableName ()] = opDatDeclaration; } else if (iequals (calleeName, OP2::OP_DECL_CONST)) { /* * ====================================================== * A constant declared through an OP_DECL_CONST call * ====================================================== */ FortranOpConstDefinition * opConstDeclaration = new FortranOpConstDefinition (actualArguments, functionCallExp); OpConstDefinitions[opConstDeclaration->getVariableName ()] = opConstDeclaration; } else if (starts_with (calleeName, OP2::OP_PAR_LOOP)) { /* * ====================================================== * The first argument to an 'OP_PAR_LOOP' call should be * a reference to the kernel function. Cast it and proceed, * otherwise throw an exception * ====================================================== */ SgExprListExp * actualArguments = functionCallExp->get_args (); SgFunctionRefExp * functionRefExpression = isSgFunctionRefExp ( actualArguments->get_expressions ().front ()); ROSE_ASSERT (functionRefExpression != NULL); string const userSubroutineName = functionRefExpression->getAssociatedFunctionDeclaration ()->get_name ().getString (); Debug::getInstance ()->debugMessage ("Found '" + calleeName + "' with (host) user subroutine '" + userSubroutineName + "'", Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__); if (parallelLoops.find (userSubroutineName) == parallelLoops.end ()) { int numberOfOpArgs = getLoopSuffixNumber ( calleeName ); /* * ====================================================== * If this kernel has not been previously encountered then * build a new parallel loop representation * ====================================================== */ FortranParallelLoop * parallelLoop = new FortranParallelLoop ( functionCallExp); parallelLoop->addFileName (currentSourceFile); parallelLoops[userSubroutineName] = parallelLoop; Debug::getInstance ()->debugMessage ("Parallel loop with '" + lexical_cast <string> (numberOfOpArgs) + "' arguments", Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__); analyseParallelLoopArguments (parallelLoop, actualArguments, numberOfOpArgs); parallelLoop->checkArguments (); parallelLoop->setIncrementalID (IDCounter); IDCounter++; } else { Debug::getInstance ()->debugMessage ("Parallel loop for '" + userSubroutineName + "' already created", Debug::OUTER_LOOP_LEVEL, __FILE__, __LINE__); ParallelLoop * parallelLoop = parallelLoops[userSubroutineName]; parallelLoop->addFunctionCallExpression (functionCallExp); parallelLoop->addFileName (currentSourceFile); } } break; } default: { break; } } } }
//Generates SSA form numbers for the variables contained in *ex and attaches them as AstValueAttributes to the related SgNodes //Assumption: *ex 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::processSgExpression(SgExpression* ex, Label* condLabel, bool inTrueBranch) { SgIntVal* intVal = dynamic_cast<SgIntVal*>(ex); SgMinusOp* minusOp = dynamic_cast<SgMinusOp*>(ex); SgVarRefExp* varRef = dynamic_cast<SgVarRefExp*>(ex); SgBinaryOp* binOp = dynamic_cast<SgBinaryOp*>(ex); SgFunctionCallExp* funcCall = dynamic_cast<SgFunctionCallExp*>(ex); if(intVal) //Int value { //Nothing needs to be done; Case is listed here to have a collection of all expected cases } else if(minusOp) { processSgExpression(minusOp->get_operand(), condLabel, inTrueBranch); } else if(varRef) //Reference to variable that is NOT on the left hand side of an assignment { //Assign number to variable string varName = varRef->get_symbol()->get_name().getString(); int varNumber = currentNumber(varName, condLabel, inTrueBranch); logger[Sawyer::Message::DEBUG] << "Current number for variable " << varName << ": " << varNumber << endl; AstValueAttribute<int>* varNumberAtt = new AstValueAttribute<int>(varNumber); varRef->setAttribute("SSA_NUMBER", varNumberAtt); } else if(binOp) //Binary operation { SgExpression* lhs = binOp->get_lhs_operand(); SgExpression* rhs = binOp->get_rhs_operand(); //Process right hand side first processSgExpression(rhs, condLabel, inTrueBranch); //Process left hand side second SgAssignOp* assignOp = dynamic_cast<SgAssignOp*>(binOp); if(assignOp) //Assignment to a variable { //Assign new number to that variable SgVarRefExp* lhsVarRef = dynamic_cast<SgVarRefExp*>(lhs); assert(lhsVarRef != NULL); processAssignmentTo(lhsVarRef, condLabel, inTrueBranch); } else //Arithmetic operation or boolean operation (or something unexpected) { processSgExpression(lhs, condLabel, inTrueBranch); } } else if(funcCall) //Call to a function //RERS specific; Only two function call types are supported: //(1) scanf("%d",&...); //(2) __VERIFIER_error(RERSVerifierErrorNumber); The artificial bool variable RERSErrorOccured has to be updated { string funcName = funcCall->getAssociatedFunctionSymbol()->get_name().getString(); logger[Sawyer::Message::DEBUG] << "Call to function: " << funcName << endl; if(funcName == "scanf") //(1) { SgExprListExp* funcArgs = funcCall->get_args(); SgExpressionPtrList funcArgsPtrs = funcArgs->get_expressions(); SgExpressionPtrList::iterator i = funcArgsPtrs.begin(); while(i != funcArgsPtrs.end()) { SgAddressOfOp* addrOp = dynamic_cast<SgAddressOfOp*>(*i); if(addrOp) { SgVarRefExp* varRef = dynamic_cast<SgVarRefExp*>(addrOp->get_operand()); if(varRef) { processAssignmentTo(varRef, condLabel, inTrueBranch); } else logger[Sawyer::Message::DEBUG] << "FOUND NO REFERENCE TO VARIABLE" << endl; } i++; } } else if(funcName == "__VERIFIER_error" && prepareReachabilityAnalysisZ3) { SgExprListExp* funcArgs = funcCall->get_args(); SgExpressionPtrList funcArgsPtrs = funcArgs->get_expressions(); assert(funcArgsPtrs.size() == 1); SgExpression* argument = *funcArgsPtrs.begin(); SgIntVal* intArgument = dynamic_cast<SgIntVal*>(argument); assert(intArgument != NULL); if(intArgument->get_value() == RERSVerifierErrorNumber) //(2) { int RERSErrorOccuredNumber = nextNumber("RERSErrorOccured", condLabel, inTrueBranch); logger[Sawyer::Message::DEBUG] << "Next number for variable RERSErrorOccured: " << RERSErrorOccuredNumber << endl; AstValueAttribute<int>* numberAtt = new AstValueAttribute<int>(RERSErrorOccuredNumber); funcCall->setAttribute("SSA_NUMBER", numberAtt); } } else logger[Sawyer::Message::DEBUG] << "Ignoring function call" << endl; } else //Unexpected { logger[Sawyer::Message::ERROR] << "ERROR: SgExpression could not be handled: " << ex->class_name() << endl; assert(false); } }