Permalink
Cannot retrieve contributors at this time
896 lines (814 sloc)
38 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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; | |
| } | |