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