Program Listing for File constantFolding.h

Program Listing for File constantFolding.h#

↰ Return to documentation for file (src/midend/programTransformation/constantFolding/constantFolding.h)

// This file implements constant folding, but leverages the work done
// by the frontend and adds support for constant folding on any transformations
// introduced after the frontend processing (the transformations are typically
// not seen by the frontend, so we have to handle constant folding directly
// for transformations.  Since many transformations are introduced automatically
// there is a substantial requirement for constant folding to clean the generated
// code up a bit.  However, since the backend compiler (vendor's compiler)

#ifndef ROSE_CONSTANT_FOLDING_H
#define ROSE_CONSTANT_FOLDING_H

#include <cmath>

namespace ConstantFolding {

// Build an inherited attribute for the tree traversal to skip constant folded expressions
class ConstantFoldingInheritedAttribute
   {
     public:
          bool isConstantFoldedValue;
          bool isPartOfFoldedExpression;
          bool internalTestingAgainstFrontend;

          ConstantFoldingInheritedAttribute()
             : isConstantFoldedValue(false),
               isPartOfFoldedExpression(false),
               internalTestingAgainstFrontend(false)
             {};

       // Need to implement the copy constructor
          ConstantFoldingInheritedAttribute ( const ConstantFoldingInheritedAttribute & X )
             : isConstantFoldedValue(X.isConstantFoldedValue),
               isPartOfFoldedExpression(X.isPartOfFoldedExpression),
               internalTestingAgainstFrontend(X.internalTestingAgainstFrontend)
             {};
   };

class ConstantFoldingSynthesizedAttribute
   {
     public:
          SgValueExp* newValueExp;

          ConstantFoldingSynthesizedAttribute() : newValueExp(NULL) {};
          ConstantFoldingSynthesizedAttribute ( const ConstantFoldingSynthesizedAttribute & X )
             : newValueExp(X.newValueExp) {};
   };

class ConstantFoldingTraversal
   : public SgTopDownBottomUpProcessing<ConstantFoldingInheritedAttribute,ConstantFoldingSynthesizedAttribute>
   {
     public:
       // Functions required by the rewrite mechanism
          ConstantFoldingInheritedAttribute evaluateInheritedAttribute (
             SgNode* n,
             ConstantFoldingInheritedAttribute inheritedAttribute );
          ConstantFoldingSynthesizedAttribute evaluateSynthesizedAttribute (
             SgNode* n,
             ConstantFoldingInheritedAttribute inheritedAttribute,
             SubTreeSynthesizedAttributes synthesizedAttributeList );
   };
//It relies on the EDG frontend to do constant folding by default.
// The original source code pass trough EDG will have all constant fold already  (not know how)
// Only new constant folding opportunities introduced by custom transformations will be
// actually handled by this function itself.
// Note: It will fold children nodes of the input node to some constants,
// not folding the input node itself.
ROSE_DLL_API void constantFoldingOptimization(SgNode* n, bool internalTestingAgainstFrontend = false);

// DQ (6/13/2015): Added support to return the constant valued expression.
ROSE_DLL_API SgValueExp* returnConstantFoldedValueExpression(SgNode* n, bool internalTestingAgainstFrontend = false);

// ***************************************************************************
// Constant un-folding is implemented here as a test to verify the correctness
// of the constant folding.
//    As an example: "int x = 3;" is transformed to be "int x = 1 + 2;"
// This transformation permits automated testing of the constant folding.
// ***************************************************************************

// Build a synthesized attribute for the tree traversal to unfold constants so that we can test the constant folding
class ConstantUnFoldingSynthesizedAttribute
   {
     public:
          SgExpression* newExp;

          ConstantUnFoldingSynthesizedAttribute() : newExp(NULL) {};
          ConstantUnFoldingSynthesizedAttribute ( const ConstantUnFoldingSynthesizedAttribute & X )
             : newExp(X.newExp) {};
   };

class ConstantUnFoldingTraversal
   : public SgBottomUpProcessing<ConstantUnFoldingSynthesizedAttribute>
   {
     public:
       // Functions required by the traversal mechanism
          ConstantUnFoldingSynthesizedAttribute evaluateSynthesizedAttribute (
             SgNode* n,
          // ConstantUnFoldingInheritedAttribute inheritedAttribute,
             SubTreeSynthesizedAttributes synthesizedAttributeList );
   };

// This test transforms the AST to turn constant values into expressions that have the
// same value. This is a test for the constant folding optimization implemented above.
ROSE_DLL_API void constantUnFoldingTest(SgNode* n);

// We move many template functions into this header since they are generally useful for others to use.
// Liao 8/1/2018

// A helper function: get value if it fits into int type
// T1: the internal value's type
// T2: the concrete value exp type
template <typename T1, typename T2>
 T1 cf_get_value_t(T2* sg_value_exp)
{
  return sg_value_exp->get_value();
}

//   Integer-type-only binary operations are excluded : %, <<, >>, &, ^, |
// We ignore pointer and complex types for constant folding
//   none_integer types: floating point types
// The operators compatible with floating-point types are
//  + - * / <, > <=, >=, ==, !=  &&, ||
//
template<typename T>
T calculate_float_t (SgBinaryOp* binaryOperator, T lhsValue, T rhsValue)
{
// DQ (3/27/2017): Initialize this to avoid Clang warning: from default case.
// T foldedValue; // to be converted to result type
  T foldedValue = 0; // to be converted to result type

  switch (binaryOperator->variantT())
  {
    // Basic arithmetic
    case V_SgAddOp:
      {
        foldedValue = lhsValue + rhsValue;
        break;
      }
    case V_SgSubtractOp:
      {
        foldedValue = lhsValue - rhsValue;
        break;
      }
    case V_SgMultiplyOp:
      {
        foldedValue = lhsValue * rhsValue;
        break;
      }
    case V_SgDivideOp:
      {
        foldedValue = lhsValue / rhsValue;
        break;
      }
     // Fortran only? a**b
      //    case V_SgExponentiationOp:
      //      {
      //        foldedValue = lhsValue ** rhsValue;
      //        break;
      //      }

    case V_SgIntegerDivideOp://TODO what is this ??
      {
        foldedValue = lhsValue / rhsValue;
        break;
      }
    // logic operations
    case V_SgAndOp:
      {
        foldedValue = lhsValue && rhsValue;
        break;
      }

    case V_SgOrOp:
      {
        foldedValue = lhsValue || rhsValue;
        break;
      }

      // relational operations
    case V_SgEqualityOp:
      {
        foldedValue = (lhsValue == rhsValue);
        break;
      }
    case V_SgNotEqualOp:
      {
        foldedValue = (lhsValue != rhsValue);
        break;
      }
    case V_SgGreaterOrEqualOp:
      {
        foldedValue = (lhsValue >= rhsValue);
        break;
      }
    case V_SgGreaterThanOp:
      {
        foldedValue = (lhsValue > rhsValue);
        break;
      }
    case V_SgLessOrEqualOp:
      {
        foldedValue = (lhsValue <= rhsValue);
        break;
      }
    case V_SgLessThanOp:
      {
        foldedValue = (lhsValue < rhsValue);
        break;
      }
   default:
      {
        std::cerr<<"warning: calculuate - unhandled operator type:"<<binaryOperator->class_name()<<std::endl;
        //ROSE_ASSERT(false); // not every binary operation type can be evaluated
      }

  } // end switch

  return foldedValue;
}
// + , <, >, <=, >=, ==, !=
template<typename T>
T calculate_string_t (SgBinaryOp* binaryOperator, T lhsValue, T rhsValue)
{
  T foldedValue; // to be converted to result type

  switch (binaryOperator->variantT())
  {
    // Basic arithmetic
    case V_SgAddOp:
      {
        foldedValue = lhsValue + rhsValue;
        break;
      }
      // relational operations
    case V_SgEqualityOp:
      {
        foldedValue = (lhsValue == rhsValue);
        break;
      }
    case V_SgNotEqualOp:
      {
        foldedValue = (lhsValue != rhsValue);
        break;
      }
    case V_SgGreaterOrEqualOp:
      {
        foldedValue = (lhsValue >= rhsValue);
        break;
      }
    case V_SgGreaterThanOp:
      {
        foldedValue = (lhsValue > rhsValue);
        break;
      }
    case V_SgLessOrEqualOp:
      {
        foldedValue = (lhsValue <= rhsValue);
        break;
      }
    case V_SgLessThanOp:
      {
        foldedValue = (lhsValue < rhsValue);
        break;
      }
    default:
      {
        std::cerr<<"warning: calculate_string_t - unacceptable operator type:"<<binaryOperator->class_name()<<std::endl;
        ROSE_ABORT();
      }
  } // end switch
  return foldedValue;
}
// For T type which is compatible for all binary operators we are interested in.
template<typename T>
T calculate_t (SgBinaryOp* binaryOperator, T lhsValue, T rhsValue)
{
  // DQ (3/27/2017): Initialize this value to avoid Clang warning from default case.
  // T foldedValue; // to be converted to result type
  T foldedValue = 0; // to be converted to result type

  switch (binaryOperator->variantT())
  {
    // integer-exclusive oprations
    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;
      }
   // non-integer-exclusive operations
     case V_SgAddOp:
      {
        foldedValue = lhsValue + rhsValue;
        break;
      }
    case V_SgSubtractOp:
      {
        foldedValue = lhsValue - rhsValue;
        break;
      }
    case V_SgMultiplyOp:
      {
        foldedValue = lhsValue * rhsValue;
        break;
      }
    case V_SgDivideOp:
      {
        foldedValue = lhsValue / rhsValue;
        break;
      }
     // Fortran only? a**b
      //    case V_SgExponentiationOp:
      //      {
      //        foldedValue = lhsValue ** rhsValue;
      //        break;
      //      }

    case V_SgIntegerDivideOp://TODO what is this ??
      {
        foldedValue = lhsValue / rhsValue;
        break;
      }
    // logic operations
    case V_SgAndOp:
      {
        foldedValue = lhsValue && rhsValue;
        break;
      }

    case V_SgOrOp:
      {
        foldedValue = lhsValue || rhsValue;
        break;
      }

      // relational operations
    case V_SgEqualityOp:
      {
        foldedValue = (lhsValue == rhsValue);
        break;
      }
    case V_SgNotEqualOp:
      {
        foldedValue = (lhsValue != rhsValue);
        break;
      }
    case V_SgGreaterOrEqualOp:
      {
        foldedValue = (lhsValue >= rhsValue);
        break;
      }
    case V_SgGreaterThanOp:
      {
        foldedValue = (lhsValue > rhsValue);
        break;
      }
    case V_SgLessOrEqualOp:
      {
        foldedValue = (lhsValue <= rhsValue);
        break;
      }
    case V_SgLessThanOp:
      {
        foldedValue = (lhsValue < rhsValue);
        break;
      }
    case V_SgExponentiationOp:
      {
        // TODO: 2^64 can be a problem!! too large
        // A workaroud is that another separated phase is called before calling constant folding to do the translation
        foldedValue = (T)pow(lhsValue, rhsValue);
        break;
      }

   default:
      {
        std::cerr<<"warning: calculuate - unhandled binary operator type:"<<binaryOperator->class_name()<<std::endl;
        //ROSE_ASSERT(false); // not every binary operation type can be evaluated
      }
  }
  return foldedValue;
}

// For T type which is compatible for all unary operators we are interested in.
template<typename T>
T calculate_u_t (SgUnaryOp* unaryOperator, T theValue)
{
  T foldedValue = 0; // to be converted to result type
  switch (unaryOperator->variantT())
  {
    // integer-exclusive oprations
    case V_SgMinusOp:
      {
        foldedValue = -theValue;
        break;
      }
   default:
      {
        std::cerr<<"warning: calculuate - unhandled unary operator type:"<<unaryOperator->class_name()<<std::endl;
      }
  }
  return foldedValue;
}



// T1: a SgValExp's child SAGE class type,
// T2: its internal storage C type for its value
template <typename T1, typename T2>
static SgValueExp* buildResultValueExp_t (SgBinaryOp* binaryOperator, SgValueExp* lhsValue, SgValueExp* rhsValue)
{
  SgValueExp* result = NULL;
  T1* lhs_v = dynamic_cast<T1*>(lhsValue);
  T1* rhs_v = dynamic_cast<T1*>(rhsValue);
  ROSE_ASSERT(lhs_v);
  ROSE_ASSERT(rhs_v);

  T2 lhs = cf_get_value_t<T2>(lhs_v);
  T2 rhs = cf_get_value_t<T2>(rhs_v);
  T2 foldedValue ;
  foldedValue = calculate_t(binaryOperator,lhs,rhs);
  result = new T1(foldedValue,"");
  ROSE_ASSERT(result != NULL);
  SageInterface::setOneSourcePositionForTransformation(result);
  return result;
}

// T1: a SgValExp's child SAGE class type,
// T2: its internal storage C type for its value
template <typename T1, typename T2>
static SgValueExp* buildResultValueExp_u_t (SgUnaryOp* unaryOperator, SgValueExp* theValue)
{
  SgValueExp* result = NULL;
  T1* t1_v = dynamic_cast<T1*>(theValue);
  ROSE_ASSERT(t1_v);
  T2 t2_v = cf_get_value_t<T2>(t1_v);
  T2 foldedValue ;
  foldedValue = calculate_u_t(unaryOperator,t2_v);
  result = new T1(foldedValue,"");
  ROSE_ASSERT(result != NULL);
  SageInterface::setOneSourcePositionForTransformation(result);
  return result;
}

// T1: a SgValExp's child SAGE class type,
// T2: its internal storage C type for its value
// for T2 types (floating point types) which are incompatible with integer-only operations: e.g. if T2 is double, then % is now allowed
template <typename T1, typename T2>
static SgValueExp* buildResultValueExp_float_t (SgBinaryOp* binaryOperator, SgValueExp* lhsValue, SgValueExp* rhsValue)
{
  SgValueExp* result = NULL;
  T1* lhs_v = dynamic_cast<T1*>(lhsValue);
  T1* rhs_v = dynamic_cast<T1*>(rhsValue);
  ROSE_ASSERT(lhs_v);
  ROSE_ASSERT(rhs_v);

  T2 lhs = cf_get_value_t<T2>(lhs_v);
  T2 rhs = cf_get_value_t<T2>(rhs_v);
  T2 foldedValue ;
  foldedValue = calculate_float_t(binaryOperator,lhs,rhs);
  result = new T1(foldedValue,"");
  ROSE_ASSERT(result != NULL);
  SageInterface::setOneSourcePositionForTransformation(result);
  return result;
}

// end of ConstantFolding namespace
}


#endif