Exemplo n.º 1
0
// 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;
}