Skip to content
Permalink
release
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
// DQ (4/8/2006):
// This implements constant folding using both a conventional
// constant folding algorithm and also the work that has already
// been done within EDG on the part of the AST generated by the front-end.
// 1) Constant folded expression trees saved in the AST are eliminated
// simplifying optimizations and a number of analysis operations.
// 2) New constant values expression added after the front-end
// processing are folded. This simplifies transformations introduced
// after front-end processing.
// The constant folding is implemented first to eliminate the front-end
// constant valued expression trees that have been saved into the AST.
// This is done because the PRE had at least one bug specific to nested
// application of itself on the saved constant folded expression trees.
// So eliminating them fixes this problem at least for now.
// tps (01/14/2010) : Switching from rose.h to sage3.
#include "sage3basic.h"
#include "sageBuilder.h"
#include "constantFolding.h"
#include <string>
using namespace ConstantFolding;
using namespace std;
void
ConstantFolding::constantFoldingOptimization(SgNode* n, bool internalTestingAgainstFrontend)
{
// This is the main function interface for constant folding
ConstantFoldingTraversal t;
ConstantFoldingInheritedAttribute ih;
// Set internal ability to do error checking against any constant expression trees stored in the AST.
ih.internalTestingAgainstFrontend = internalTestingAgainstFrontend;
ConstantFoldingSynthesizedAttribute returnAttribute;
// t.traverse(n,ih);
returnAttribute = t.traverse(n,ih);
#if 0
#if 1
printf ("In ConstantFolding::constantFoldingOptimization(): n = %p = %s returnAttribute.newValueExp = %p \n",n,n->class_name().c_str(),returnAttribute.newValueExp);
// Note that returnAttribute.newValueExp can be NULL.
if (returnAttribute.newValueExp != NULL)
{
printf (" --- returnAttribute.newValueExp = %p = %s \n",returnAttribute.newValueExp,returnAttribute.newValueExp->class_name().c_str());
}
#else
ROSE_ASSERT(returnAttribute.newValueExp != NULL);
printf ("In ConstantFolding::constantFoldingOptimization(): n = %p = %s returnAttribute.newValueExp = %p = %s \n",n,n->class_name().c_str(),returnAttribute.newValueExp,returnAttribute.newValueExp->class_name().c_str());
#endif
#endif
}
SgValueExp*
ConstantFolding::returnConstantFoldedValueExpression(SgNode* n, bool internalTestingAgainstFrontend)
{
// This is the main function interface for constant folding
ConstantFoldingTraversal t;
ConstantFoldingInheritedAttribute ih;
// Set internal ability to do error checking against any constant expression trees stored in the AST.
ih.internalTestingAgainstFrontend = internalTestingAgainstFrontend;
ConstantFoldingSynthesizedAttribute returnAttribute;
// t.traverse(n,ih);
returnAttribute = t.traverse(n,ih);
#if 0
printf ("In ConstantFolding::constantFoldingOptimization(): n = %p = %s returnAttribute.newValueExp = %p \n",n,n->class_name().c_str(),returnAttribute.newValueExp);
// Note that returnAttribute.newValueExp can be NULL.
if (returnAttribute.newValueExp != NULL)
{
printf (" --- returnAttribute.newValueExp = %p = %s \n",returnAttribute.newValueExp,returnAttribute.newValueExp->class_name().c_str());
}
#endif
return returnAttribute.newValueExp;
}
void
ConstantFolding::constantUnFoldingTest(SgNode* n)
{
// This is the main function interface for constant un-folding tests.
// Since the constant folding we have only checks the results computed by EDG
// where there are no transformation, we have to generate a transformation to have
// something to constant fold. This transformation generates constant expressions
// from constants to use in testing the constant folding where EDG would not have
// generated the constant folding.
// Note that if we save the AST before hand (AST File IO)
// We could then test the AST to see if the constant folding generated
// the same AST. The concept of same AST (equality) would have to be
// specified precisely.
ConstantUnFoldingTraversal t;
// Test this by turning constants into rather long and ugly constant expressions!
t.traverse(n);
// Now fold the constant expressions that we just generated
// constantFoldingOptimization(n);
// Need a way to verify that it all worked (other than visually)!
}
ConstantFoldingInheritedAttribute
ConstantFoldingTraversal::evaluateInheritedAttribute ( SgNode* astNode, ConstantFoldingInheritedAttribute inheritedAttribute )
{
// Compute the inheritedAttribute. Since the modification of the AST must be done
// bottom up, this is the most we can do here (since the evaluation of inherited
// attributes happens top down).
if (inheritedAttribute.isConstantFoldedValue == true)
{
inheritedAttribute.isConstantFoldedValue = false;
inheritedAttribute.isPartOfFoldedExpression = true;
}
else
{
// Check for constant folded value
SgValueExp* originalExpression = isSgValueExp(astNode);
if (originalExpression != NULL && originalExpression->get_originalExpressionTree() != NULL)
{
if (inheritedAttribute.internalTestingAgainstFrontend == true)
{
// If we are testing the constant folding then refold the values constant expression trees
// stored in the AST and check the result against what EDG computed.
// To test the constant folding skip marking the constant as folded and test if we fold the
// constant expression correctly
inheritedAttribute.isConstantFoldedValue = false;
}
else
{
// This is a resulting value generated from constant folding in the front-end (EDG)
inheritedAttribute.isConstantFoldedValue = true;
// We can just remove a subtree that we have not yet traversed, is this perfectly safe?
// I think it is safe since it is a child and not a sibling! However, this does not delete
// the existing constant folded trees, it just disconnects them from the AST.
#if PRINT_DEVELOPER_WARNINGS
printf ("Deleting the original expression tree within ConstantFoldingTraversal::evaluateInheritedAttribute ... (likely memory leak) \n");
#endif
originalExpression->set_originalExpressionTree(NULL);
}
}
}
return inheritedAttribute;
}
// Macro to permit use of shorter name
#define TRANSFORMATION_FILE_INFO Sg_File_Info::generateDefaultFileInfoForTransformationNode()
static int cf_get_int_value(SgValueExp * sg_value_exp)
{
int rtval;
if (isSgBoolValExp(sg_value_exp))
rtval = isSgBoolValExp(sg_value_exp)->get_value();
else if (isSgCharVal(sg_value_exp))
rtval = isSgCharVal(sg_value_exp)->get_value();
else if (isSgEnumVal(sg_value_exp))
rtval = isSgEnumVal(sg_value_exp)->get_value();
else if (isSgIntVal(sg_value_exp))
rtval = isSgIntVal(sg_value_exp)->get_value();
else if (isSgShortVal(sg_value_exp))
rtval = isSgShortVal(sg_value_exp)->get_value();
else if (isSgUpcMythread(sg_value_exp))
rtval = isSgUpcMythread(sg_value_exp)->get_value();
else if (isSgUpcThreads(sg_value_exp))
rtval = isSgUpcThreads(sg_value_exp)->get_value();
else
{
cerr<<"error: wrong value exp type for cf_get_int_value():"<<sg_value_exp->class_name()<<endl;
ROSE_ABORT();
}
return rtval;
}
#if 0
// Liao, 6/27/2009
//A set of bit flags for categories of data types
//They are useful since operations can only be applied to a certain categories of data types
// We follow ISO C standard (2005 draft version) for the categories
//
// signed integer types = signed 1)char, 2)short int, 3)int , 4)long int, 5) long long int
// unsigned integer types = unsigned 1)char, 2)short int, 3)int , 4)long int, 5) long long int
// integer types = bool + char + signed and unsigned integer types
// (real) floating types = float, double, long double, excluding complex types
// real types = integer types + real floating types
// arithmetic types = integer types + floating types
// scalar types = arithmetic types + pointer types
// base types
#define OP_TYPE_BOOL (1<<0)
#define OP_TYPE_CHAR (1<<1)
#define OP_TYPE_SIGNED_INTEGER (1<<2)
#define OP_TYPE_UNSIGNED_INTEGER (1<<3)
#define OP_TYPE_FLOATING_POINT (1<<4) // We don't consider complex types for now
#define OP_TYPE_POINTER (1<<5)
//aggregate them
#define OP_TYPE_INTEGER \
( OP_TYPE_BOOL | OP_TYPE_CHAR|OP_TYPE_SIGNED_INTEGER|OP_TYPE_UNSIGNED_INTEGER )
#define OP_TYPE_REAL \
(OP_TYPE_INTEGER | OP_TYPE_FLOATING_POINT)
#define OP_TYPE_ARITHMETIC \
( OP_TYPE_INTEGER | OP_TYPE_FLOATING_POINT )
#define OP_TYPE_SCALAR \
(OP_TYPE_ARITHMETIC | OP_TYPE_POINTER)
//! Data type --> allowed operations
//! Calculate the result of a binary operation on two constant values
// Only contain binary operations allows integer operands
// Those binary operations are: %, <<, >>, &, ^, |
//
// We ignore the compound assignment operations for constant folding, since the folding
// will lose the side effect on the assigned variables.
template<typename T>
T calculate_integer_t (SgBinaryOp* binaryOperator, T lhsValue, T rhsValue)
{
T foldedValue; // to be converted to result type
switch (binaryOperator->variantT())
{
case V_SgModOp:
{
foldedValue = lhsValue % rhsValue;
break;
}
case V_SgLshiftOp:
{
foldedValue = (lhsValue << rhsValue);
break;
}
case V_SgRshiftOp:
{
foldedValue = (lhsValue >> rhsValue);
break;
}
// bitwise operations
case V_SgBitAndOp:
{
foldedValue = lhsValue & rhsValue;
break;
}
case V_SgBitOrOp:
{
foldedValue = lhsValue | rhsValue;
break;
}
case V_SgBitXorOp:
{
foldedValue = lhsValue ^ rhsValue;
break;
}
default:
cerr<<"warning: calculuate_integer_t - illegal operator type:"<<binaryOperator->class_name()<<endl;
}
return foldedValue;
}
#endif
//!Evaluate a binary expression a binOp b, return a value exp if both operands are constants
static SgValueExp* evaluateBinaryOp(SgBinaryOp* binaryOperator)
{
SgValueExp* result = NULL;
ROSE_ASSERT(binaryOperator != NULL);
SgExpression* lhsOperand = binaryOperator->get_lhs_operand();
SgExpression* rhsOperand = binaryOperator->get_rhs_operand();
if (lhsOperand == NULL || rhsOperand == NULL)
return NULL;
// Check if these are value expressions (constants appropriate for constant folding)
SgValueExp* lhsValue = isSgValueExp(lhsOperand);
SgValueExp* rhsValue = isSgValueExp(rhsOperand);
if (lhsValue != NULL && rhsValue != NULL)
{
// we ignore the cases of different operand types for now
if (lhsValue->variantT() != rhsValue->variantT())
return NULL;
// TODO what if lhs and rhs have different types?
switch (lhsValue->variantT())
{
case V_SgBoolValExp:
{ // special handling for bool type, since intVal is built as a result
int lhsInteger = cf_get_value_t<int>(isSgBoolValExp(lhsValue));
int rhsInteger = cf_get_value_t<int>(isSgBoolValExp(rhsValue));
int foldedValue = calculate_t(binaryOperator, lhsInteger, rhsInteger);
result = SageBuilder::buildIntVal(foldedValue);
break;
}
case V_SgCharVal: // mostly provide a pair of SgValueExp class type and its internal value type
// for SgCharVal, the internal value type is also char
{
result = buildResultValueExp_t<SgCharVal,char>(binaryOperator,lhsValue,rhsValue);
break;
}
// each calls a subset (bitvec again?) of binary calculation according to data types
case V_SgDoubleVal:
{
result = buildResultValueExp_float_t<SgDoubleVal,double>(binaryOperator,lhsValue,rhsValue);
break;
}
// enumerate value is special, we build an integer equivalent here for simplicity
case V_SgEnumVal:
{
result = buildResultValueExp_t<SgIntVal,int>(binaryOperator,lhsValue,rhsValue);
break;
}
case V_SgFloatVal:
{
// Liao, 9/22/2009, folding float to float may decrease the accuracy. promoting it to double
// TODO, need an option to skip folding float point operations
result = buildResultValueExp_float_t<SgFloatVal,float>(binaryOperator,lhsValue,rhsValue);
break;
}
case V_SgIntVal:
{
#if 1
result = buildResultValueExp_t<SgIntVal,int>(binaryOperator,lhsValue,rhsValue);
#else
int lhsInteger = cf_get_value_t<int>(isSgIntVal(lhsValue));
int rhsInteger = cf_get_value_t<int>(isSgIntVal(rhsValue));
int foldedValue = calculate_t(binaryOperator, lhsInteger, rhsInteger);
result = SageBuilder::buildIntVal(foldedValue);
#endif
break;
}
case V_SgLongDoubleVal:
{
result = buildResultValueExp_float_t<SgLongDoubleVal,long double>(binaryOperator,lhsValue,rhsValue);
break;
}
case V_SgLongIntVal:
{
result = buildResultValueExp_t<SgLongIntVal,long int>(binaryOperator,lhsValue,rhsValue);
break;
}
case V_SgLongLongIntVal:
{
result = buildResultValueExp_t<SgLongLongIntVal,long long int>(binaryOperator,lhsValue,rhsValue);
break;
}
case V_SgShortVal:
{
result = buildResultValueExp_t<SgShortVal,short>(binaryOperator,lhsValue,rhsValue);
break;
}
//special handling for string val due to its unique constructor
case V_SgStringVal:
{
std::string lhsInteger = cf_get_value_t<std::string>(isSgStringVal(lhsValue));
std::string rhsInteger = cf_get_value_t<std::string>(isSgStringVal(rhsValue));
std::string foldedValue = calculate_string_t(binaryOperator, lhsInteger, rhsInteger);
result = SageBuilder::buildStringVal(foldedValue);
break;
}
case V_SgUnsignedCharVal:
{
result = buildResultValueExp_t<SgUnsignedCharVal,unsigned char>(binaryOperator,lhsValue,rhsValue);
break;
}
case V_SgUnsignedIntVal:
{
result = buildResultValueExp_t<SgUnsignedIntVal,unsigned int>(binaryOperator,lhsValue,rhsValue);
break;
}
case V_SgUnsignedLongLongIntVal:
{
result = buildResultValueExp_t<SgUnsignedLongLongIntVal,unsigned long long int>(binaryOperator,lhsValue,rhsValue);
break;
}
case V_SgUnsignedLongVal:
{
result = buildResultValueExp_t<SgUnsignedLongVal,unsigned long>(binaryOperator,lhsValue,rhsValue);
break;
}
case V_SgUnsignedShortVal:
{
result = buildResultValueExp_t<SgUnsignedShortVal,unsigned short>(binaryOperator,lhsValue,rhsValue);
break;
}
default:
{
cout<<"evaluateBinaryOp(): "<<"Unhandled SgValueExp case for:"<<lhsValue->class_name()<<endl;
// Not a handled type
}
}
//TODO what if binaryOperator's type is different from its operands' types
//when to do the cast? or cast is done by unary operation's evaluation?
#if 0
// Now we have to look at the type (since there are a lot of types this could be
// a lot of cases)
SgType* type = binaryOperator->get_type();
switch(type->variantT())
{
// implement at least one case for now
case V_SgTypeInt:
case V_SgTypeBool:
{
SgIntVal* lhsIntValue = isSgIntVal(lhsValue);
SgIntVal* rhsIntValue = isSgIntVal(rhsValue);
SgBoolValExp* lhsBoolValue = isSgBoolValExp(lhsValue);
SgBoolValExp* rhsBoolValue = isSgBoolValExp(rhsValue);
// Both bool value and int value use int value
if ((lhsIntValue != NULL && rhsIntValue != NULL)
||(lhsBoolValue != NULL && rhsBoolValue != NULL))
{
int lhsInteger = 0;
if (lhsIntValue)
lhsInteger = lhsIntValue->get_value();
else if (lhsBoolValue)
lhsInteger = lhsBoolValue->get_value();
int rhsInteger = 0;
if (rhsIntValue)
rhsInteger = rhsIntValue->get_value();
else if (rhsBoolValue)
rhsInteger = rhsBoolValue->get_value();
int foldedValue = calculate_t(binaryOperator, lhsInteger, rhsInteger);
// returnAttribute.newValueExp = SageBuilder::buildIntVal(foldedValue);
result = SageBuilder::buildIntVal(foldedValue);
// printf ("Found a constant expression %d %s %d --> folding to value = %d \n",lhsInteger,binaryOperator->class_name().c_str(),rhsInteger,foldedValue);
}
break;
}
default:
{
cout<<"evaluateBinaryOp(): "<<"Unhandled type case for:"<<type->class_name()<<endl;
// Not a handled type
}
}
#endif
} // both operands are constant
return result;
}
//!Evaluate a unary expression, return a value exp if operand is a constant
static SgValueExp* evaluateUnaryOp(SgUnaryOp* unaryOperator){
SgValueExp* result = NULL;
ROSE_ASSERT(unaryOperator != NULL);
SgExpression* theOperand = unaryOperator->get_operand();
if (theOperand == NULL)
return NULL;
// Check if these are value expressions (constants appropriate for constant folding)
SgValueExp* theValue = isSgValueExp(theOperand);
if (theValue != NULL) {
switch (theValue->variantT()) {
case V_SgBoolValExp:
{ // special handling for bool type, since intVal is built as a result
int theInteger = cf_get_value_t<int>(isSgBoolValExp(theValue));
int foldedValue = calculate_u_t(unaryOperator, theInteger);
result = SageBuilder::buildIntVal(foldedValue);
break;
}
case V_SgDoubleVal:
{
result = buildResultValueExp_u_t<SgDoubleVal,double>(unaryOperator,theValue);
break;
}
case V_SgEnumVal:
{
result = buildResultValueExp_u_t<SgIntVal,int>(unaryOperator,theValue);
break;
}
case V_SgFloatVal:
{
// folding float to float may decrease the accuracy. promoting it to double
result = buildResultValueExp_u_t<SgFloatVal,float>(unaryOperator,theValue);
break;
}
case V_SgIntVal:
{
result = buildResultValueExp_u_t<SgIntVal,int>(unaryOperator,theValue);
break;
}
case V_SgLongDoubleVal:
{
result = buildResultValueExp_u_t<SgLongDoubleVal,long double>(unaryOperator,theValue);
break;
}
case V_SgLongIntVal:
{
result = buildResultValueExp_u_t<SgLongIntVal,long int>(unaryOperator,theValue);
break;
}
case V_SgLongLongIntVal:
{
result = buildResultValueExp_u_t<SgLongLongIntVal,long long int>(unaryOperator,theValue);
break;
}
case V_SgShortVal:
{
result = buildResultValueExp_u_t<SgShortVal,short>(unaryOperator,theValue);
break;
}
case V_SgUnsignedIntVal:
{
result = buildResultValueExp_u_t<SgUnsignedIntVal,unsigned int>(unaryOperator,theValue);
break;
}
case V_SgUnsignedLongLongIntVal:
{
result = buildResultValueExp_u_t<SgUnsignedLongLongIntVal,unsigned long long int>(unaryOperator,theValue);
break;
}
case V_SgUnsignedLongVal:
{
result = buildResultValueExp_u_t<SgUnsignedLongVal,unsigned long>(unaryOperator,theValue);
break;
}
case V_SgUnsignedShortVal:
{
result = buildResultValueExp_u_t<SgUnsignedShortVal,unsigned short>(unaryOperator,theValue);
break;
}
default:
{
cout<<"evaluateUnaryOp(): "<<"Unhandled SgValueExp case for:"<<theValue->class_name()<<endl;
}
}
} // operand is constant
return result;
}
//! Evaluate a conditional expression i.e. a?b:c
static SgValueExp* evaluateConditionalExp(SgConditionalExp * cond_exp)
{
SgValueExp* result = NULL;
// Calculate the current node's synthesized attribute value
SgExpression* c_exp_value = cond_exp->get_conditional_exp();
SgValueExp* value_exp = isSgValueExp(c_exp_value);
SgExpression* t_exp_value = cond_exp->get_true_exp();
SgValueExp* value_exp_t = isSgValueExp(t_exp_value);
SgExpression* f_exp_value = cond_exp->get_false_exp();
SgValueExp* value_exp_f = isSgValueExp(f_exp_value);
if (value_exp)
{
switch (value_exp->variantT())
{
//TODO first operand can be scalar type: arithmetic (integer + floating point) + pointer
// case V_SgCharVal:
// {
// std::string v = cf_get_value_t<std::string>(value_exp);
// break;
// }
// case V_SgDoubleVal:
// {
// double v = cf_get_value_t<double>(value_exp);
// break;
// }
// case V_SgFloatVal:
// {
// float v = cf_get_value_t<float>(value_exp);
// break;
// }
// integer value
case V_SgCharVal:
case V_SgShortVal:
case V_SgBoolValExp:
case V_SgEnumVal:
case V_SgIntVal:
case V_SgUpcMythread:
case V_SgUpcThreads:
{
int v= cf_get_int_value(value_exp);
if (v)
{
if (value_exp_t) // set the value only if the true exp is a constant
result = value_exp_t;
}
else
{
if (value_exp_f)
result = value_exp_f;
}
break;
}
default:
{
cout<<"evaluateConditionalExp(): unhandled value expression type of a conditional exp:"<<value_exp->class_name()<<endl;
}
} // end switch
}// end if (value_exp) the condition is a constant
return result ;
}
ConstantFoldingSynthesizedAttribute
ConstantFoldingTraversal::evaluateSynthesizedAttribute (
SgNode* astNode,
ConstantFoldingInheritedAttribute inheritedAttribute,
SubTreeSynthesizedAttributes synthesizedAttributeList )
{
ConstantFoldingSynthesizedAttribute returnAttribute;
#if 0
printf ("astNode = %p = %s: synthesizedAttributeList.size() = %ld \n",astNode,astNode->class_name().c_str(),synthesizedAttributeList.size());
for (SubTreeSynthesizedAttributes::iterator i = synthesizedAttributeList.begin(); i != synthesizedAttributeList.end(); i++)
{
printf (" synthesizedAttributeList i->newValueExp = %p \n",i->newValueExp);
}
#endif
// Use the inheritedAttribute to simplify the logic
if (inheritedAttribute.isConstantFoldedValue == false)
{
// Here is where the front-end mechanism leaves off and we pickup the job to do the constant folding of
// anything not handled by the front-end. This applies to constant expression trees built as part of
// transformations. This should help cleanup a lot of automatically generated code.
// And of course this section is not yet implemented yet!
SgExpression* expr = isSgExpression(astNode);
if ( expr != NULL )
{
if (inheritedAttribute.internalTestingAgainstFrontend == true)
{
// If this is a SgValueExp it might be that a const expression tree is hidden inside of it.
// This would have been done in the front-end processing. To check our constant folding we have
// to look in the SgValueExp for the originalExpressionTree and copy the generated SgIntVal from
// there (actually where we are just checking, so we only verify that we get the same value).
SgValueExp* valueExpression = isSgValueExp(expr);
if (valueExpression != NULL)
{
// If we have a value expression then there could be many types of value IR nodes
switch(valueExpression->variantT())
{
case V_SgIntVal:
{
#if 0
SgIntVal* integerValue = isSgIntVal(valueExpression);
int originalValue = integerValue->get_value();
// Check if we have a constant folded value computed at a child node (synthesized attribute).
SgValueExp* constantValueExp = synthesizedAttributeList[SgValueExp_originalExpressionTree].newValueExp;
if (constantValueExp != NULL)
{
// I think there it is not required to be a SgIntVal IR node since many constant expressions could return "int"
// So I think we have to check again, not ceratin if this much checking is really required.
SgIntVal* intValue = isSgIntVal(constantValueExp);
ROSE_ASSERT(intValue != NULL); // see if we can assert this!
if (intValue != NULL)
{
int constantFoldedValue = intValue->get_value();
printf ("Error checking: constantFoldedValue = %d originalValue (computed by frontend) = %d \n",constantFoldedValue,originalValue);
ROSE_ASSERT(constantFoldedValue == originalValue);
#if PRINT_DEVELOPER_WARNINGS
printf ("Deleting the original expression tree within ConstantFoldingTraversal::evaluateSynthesizedAttribute ... (likely memory leak) \n");
#endif
// This does not delete the existing constant folded trees, it just disconnects them from the AST.
valueExpression->set_originalExpressionTree(NULL);
}
}
#else
printf ("Warning: originalExpressionTree is no longer a part of the AST traversal (must be accessed explicitly). code in constant folding is disabled. \n");
ROSE_ABORT();
#endif
}
default:
{
}
}
}
}
// Liao, 6/26/2009, add more cases, this is used by SageInterface::loopUnrolling()
// For each type of expressions, do the following:
// step 1: replace children with their synthesized attribute values , if any
// step 1: calculate the current node 's synthesized attribute value if children' values are constants
// Binary expressions
if (isSgBinaryOp(expr)) // we don't use 'switch (expr->variantT())' here to avoid enumerating all variantT values for binary operations
{
// Found an expression see if it is a binary or unary operator
// (else we can ignore it in constant folding, I think).
SgBinaryOp* binaryOperator = isSgBinaryOp(expr);
ROSE_ASSERT(binaryOperator != NULL);
// DQ (2/9/2011): This is now 3 with the addition of the original expression tree.
// ROSE_ASSERT(synthesizedAttributeList.size() == 2);
// ROSE_ASSERT(synthesizedAttributeList.size() == 3);
// step 1: replace children with their synthesized attribute values
//
// Process any SubTreeSynthesizedAttributes so any values there can be reused (propagated up in the AST)
// If we are not testing against values from the constant expression trees saved by ROSE in the AST, then
// this is where we would expect to find the values propagated up from and constant operands or values
// folded from constant expressions.
SgExpression* lhsSynthesizedValue = synthesizedAttributeList[SgBinaryOp_lhs_operand_i].newValueExp;
SgExpression* rhsSynthesizedValue = synthesizedAttributeList[SgBinaryOp_rhs_operand_i].newValueExp;
// printf ("Propagated values: lhsSynthesizedValue = %p rhsSynthesizedValue = %p \n",lhsSynthesizedValue,rhsSynthesizedValue);
// Replace the lhs and/or rhs if generated at a child node in the AST traversal
// Note that this overwrites the existing pointer and is likely a memory leak!
if (lhsSynthesizedValue != NULL)
binaryOperator->set_lhs_operand(lhsSynthesizedValue);
if (rhsSynthesizedValue != NULL)
binaryOperator->set_rhs_operand(rhsSynthesizedValue);
// step 2: calculate the current node 's synthesized attribute value
//
// Get the child nodes (existing or new reset values)
returnAttribute.newValueExp = evaluateBinaryOp(binaryOperator);
} // end if binary op
else if (SgUnaryOp* unaryOperator = isSgUnaryOp(expr))
{
// Constant folding makes sense on unary operators, but this case is not implemented yet!
ROSE_ASSERT(synthesizedAttributeList.size() == 1 || (synthesizedAttributeList.size() == 2 && isSgCastExp(unaryOperator)));
SgExpression* synthesizedValue = synthesizedAttributeList[SgUnaryOp_operand_i].newValueExp;
// Replace the lhs and/or rhs if generated at a child node in the AST traversal
// Note that this overwrites the existing pointer and is likely a memory leak!
if (synthesizedValue != NULL)
unaryOperator->set_operand(synthesizedValue);
SgExpression* operand = unaryOperator->get_operand();
SgValueExp* value = isSgValueExp(operand);
if (value != NULL)
{
switch (unaryOperator->variantT())
{
case V_SgMinusOp:
{
returnAttribute.newValueExp = evaluateUnaryOp(unaryOperator);
break;
}
case V_SgUnaryAddOp:
case V_SgCastExp:
{
//TODO
break;
}
default:
{
// There are a lot of expressions where constant folding does not apply
}
}
}
}
else if (isSgAssignInitializer(expr))
{
SgAssignInitializer* assignInit = isSgAssignInitializer(expr);
ROSE_ASSERT (assignInit != NULL);
ROSE_ASSERT(synthesizedAttributeList.size() == 1);
SgExpression* synthesizedValue = synthesizedAttributeList[SgAssignInitializer_operand_i].newValueExp;
// Replace the lhs and/or rhs if generated at a child node in the AST traversal
// Note that this overwrites the existing pointer and is likely a memory leak!
if (synthesizedValue != NULL)
assignInit->set_operand(synthesizedValue);
}
else if (isSgExprListExp(expr))
{
SgExprListExp* exprList = isSgExprListExp(expr);
ROSE_ASSERT(exprList != NULL);
ROSE_ASSERT(synthesizedAttributeList.size() == exprList->get_expressions().size());
for (size_t i = 0; i < exprList->get_expressions().size(); ++i) {
SgExpression* synthesizedValue = synthesizedAttributeList[i].newValueExp;
if (synthesizedValue != NULL)
exprList->get_expressions()[i] = synthesizedValue;
}
}
else if (isSgConditionalExp(expr)) // a ? b: c
{
SgConditionalExp* cond_exp = isSgConditionalExp(expr);
ROSE_ASSERT(cond_exp);
ROSE_ASSERT(synthesizedAttributeList.size() == 3);
// step 1. replace children with their synthesized values
// src/frontend/SageIII/Cxx_GrammarTreeTraversalAccessEnums.h defines the traversal enum
// enum E_SgConditionalExp {SgConditionalExp_conditional_exp, SgConditionalExp_true_exp, SgConditionalExp_false_exp}
SgExpression* c_exp_value = synthesizedAttributeList[SgConditionalExp_conditional_exp].newValueExp;
SgExpression* t_exp_value = synthesizedAttributeList[SgConditionalExp_true_exp].newValueExp;
SgExpression* f_exp_value = synthesizedAttributeList[SgConditionalExp_false_exp].newValueExp;
if (c_exp_value!= NULL)
cond_exp->set_conditional_exp(c_exp_value);
if (t_exp_value!= NULL)
cond_exp->set_true_exp(t_exp_value);
if (f_exp_value!= NULL)
cond_exp->set_false_exp(f_exp_value);
// step 2. calculate the current node's synthesized attribute value
returnAttribute.newValueExp = evaluateConditionalExp(cond_exp);
}
//TODO SgSizeOfOp ()
//return constant 1 for operand of type char, unsigned char, signed char
//
// ignore expressions without any constant valued children expressions, they are not supposed to be handled here
else if (!isSgValueExp(expr) &&
!isSgVarRefExp(expr) &&
!isSgFunctionRefExp(expr) &&
// DQ (6/14/2015): Added case to ignore. SgNullExpression does not make since in the context of constant folding.
!isSgNullExpression(expr) &&
// DQ (6/14/2015): Added case to ignore. SgSizeOfOp is not clear if it should be constant folded, since it might be dependent on something that might be transformed.
!isSgSizeOfOp(expr) &&
!isSgFunctionCallExp(expr))
{
if (SgProject::get_verbose() > 0)
cout<<"constant folding: unhandled expression type:"<<expr->class_name()<<endl;
}
} // end if (exp)
}
// printf ("Returning returnAttribute.newValueExp = %p \n",returnAttribute.newValueExp);
return returnAttribute;
}
ConstantUnFoldingSynthesizedAttribute
ConstantUnFoldingTraversal::evaluateSynthesizedAttribute (
SgNode* astNode,
SubTreeSynthesizedAttributes synthesizedAttributeList )
{
ConstantUnFoldingSynthesizedAttribute returnAttribute;
// This code will expand out a constant into a constant expression (this is done to test the constant folding)
SgValueExp* valueExp = isSgValueExp(astNode);
if ( valueExp != NULL )
{
SgType* type = valueExp->get_type();
switch(type->variantT())
{
case V_SgTypeInt:
{
// Since a number of value expressions could evaluate to int we don't want to assume
// that this is always a SgIntVal, so we have to test.
SgIntVal* intValueExp = isSgIntVal(valueExp);
if (intValueExp != NULL)
{
int value = intValueExp->get_value();
SgIntVal* lhsIntValue = SageBuilder::buildIntVal(1);
SgIntVal* rhsIntValue = SageBuilder::buildIntVal(value-1);
returnAttribute.newExp = SageBuilder::buildAddOp(lhsIntValue,rhsIntValue);
printf ("Found constant = %d and built a constant expression (%d+%d) \n",
value,lhsIntValue->get_value(),rhsIntValue->get_value());
}
else
{
printf ("Found an integer type value expression which was not a SgIntVal: valueExp = %p = %s \n",valueExp,valueExp->class_name().c_str());
}
break;
}
default:
{
// There are a lot of expressions where constant folding does not get tested using this test
}
}
}
// This will turn binary operators containing value expressions into binary operators with
// binary operators as subexpressions.
SgBinaryOp* binaryOperator = isSgBinaryOp(astNode);
if (binaryOperator != NULL)
{
// Process any SubTreeSynthesizedAttributes so any values there can be reused (propagated up in the AST)
// If we are not testing against values from the constant expression trees saved by ROSE in the AST, then
// this is where we would expect to find the values propagated up from and constant operands or values
// folded from constant expressions.
SgExpression* lhsSynthesizedValue = synthesizedAttributeList[SgBinaryOp_lhs_operand_i].newExp;
SgExpression* rhsSynthesizedValue = synthesizedAttributeList[SgBinaryOp_rhs_operand_i].newExp;
// Replace the lhs and/or rhs if generated at a child node in the AST traversal
// Note that this overwrites the existing pointer and is likely a memory leak!
if (lhsSynthesizedValue != NULL)
binaryOperator->set_lhs_operand(lhsSynthesizedValue);
if (rhsSynthesizedValue != NULL)
binaryOperator->set_rhs_operand(rhsSynthesizedValue);
}
return returnAttribute;
}