/*

  Copyright (C) 2000, 2001 Silicon Graphics, Inc.  All Rights Reserved.

   Path64 is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   Path64 is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
   License for more details.

   You should have received a copy of the GNU General Public License
   along with Path64; see the file COPYING.  If not, write to the Free
   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
   02110-1301, USA.

   Special thanks goes to SGI for their continued support to open source

*/


// This may look like C code, but it is really -*- C++ -*-
//
// ========================================================================
// .NAME REGION - a class to hold array regions
// .INCLUDE ara_region.h
// .FILE ara_region.h
// .FILE ara_region.inline.h ara_region.cxx
//
// .SECTION Description
//
// Region is a simple class for holding a bounded convex region (polytope).
// It contains two parts (dual representations of polytope):
//
//     (1) Constraints:
//             [lower1:upper1:stride1]  --- constraint for dimension 1
//             [lower2:upper2:stride2]  --- constraint for dimension 2
//                 ...
//             [lowern:uppern:striden]  --- constraint for dimension n
//    
//         representing the inequality constraints for each dimensions.
//
//     (2) Vertices:
//             {(x1,x2, ..., xn)| all the vertices of the polytope}
//
//     (3) Conditions:
//             conditions for the region to be valid.
//
//     (4) Kernel:
//             kernel matrix of array occurrence for efficiency purpose.
//
// Exported Type:
//
//    REGION
//
// Exported Functions
//    
//    BOOL Is_Empty()
//          ------ Return TRUE if the region is empty.
//
//    BOOL Is_Included(const REGION &a)
//          ------ Test if 'a' is a subregion.
//
//    REGION * Region_Intersect(const REGION &a, const REGION &b)
//    REGION * Region_Intersect(const SLIST_REGION &list_of_regions)
//          ------ Return the intersection of regions.
//
//    REGION * Region_Union(const REGION &a, const REGION &b)
//    REGION * Region_Union(const SLIST_REGION &list_of_regions)
//          ------ If the union of regions is convex
//                    return the union
//                 else
//                    return NULL
//
//    REGION * Region_Projection(const WN &loop)
//          ------ Project away the loop index of &loop from the region.
//    
// =======================================================================

#ifndef _ara_region_INCLUDED
#define _ara_region_INCLUDED

#include <stdlib.h>
#ifndef defs_INCLUDED
#include "defs.h"
#endif
#ifndef cxx_template_INCLUDED
#include "cxx_template.h"
#endif
#ifndef cxx_base_INCLUDED
#include "cxx_base.h"
#endif
#ifndef wn_INCLUDED
#include "wn.h"
#endif
#ifndef access_vector_INCLUDED
#include "access_vector.h"
#endif
#ifndef soe_INCLUDED
#include "soe.h"
#endif
// #include "ara_loop.h"

extern MEM_POOL ARA_memory_pool;     // default mem pool
class KERNEL_IMAGE;                  // forward declaration
class KERNEL_LIST;                   // forward declaration
class ARA_LOOP_INFO;                 // forward declaration

typedef STACK<INT> INT_ST;

enum ARA_REGION_TYPE {
  ARA_TOP, ARA_BOTTOM, ARA_TOO_MESSY, ARA_NORMAL
};

//======================================================================
// This data structure hold one inequality constraint:
// (refer to AXLE_NODE for how various constraints are represented.)
// 
//  _coeff * X + _ac_v * Y  <= 0
//  ----- X is a vector representing the axles of a region
//  ----- Y is a vector representing the enclosing loop indices
//  ----- _coeff is a vector representing the relations among the
//        axles.  
//             If (_coeff == NULL), the region is decoupled.
//  ----- _ac_v is an access vector representing the coefficients
//        for loop indices, linear terms, and constants.
//======================================================================
class CON_PAIR {

public:
  
  ACCESS_VECTOR *_ac_v;
  INT32         *_coeff;

  CON_PAIR() { 
    _ac_v = NULL;
    _coeff = NULL;
  }

  CON_PAIR(CON_PAIR* c, INT dim);

  CON_PAIR(ACCESS_VECTOR *av) {
    _coeff = NULL;
    _ac_v = CXX_NEW(ACCESS_VECTOR(av,&ARA_memory_pool), &ARA_memory_pool);
  }

  CON_PAIR(ACCESS_VECTOR *av, INT* coeff, INT dim, MEM_POOL* mem_pool) { 
    if (coeff != NULL) {
      _coeff = CXX_NEW_ARRAY(INT, dim, mem_pool);
      for (INT i = 0; i < dim; i++) 
	_coeff[i] = coeff[i];
    } else {
      _coeff = NULL; 
    }
    _ac_v = CXX_NEW(ACCESS_VECTOR(av, mem_pool), mem_pool);
  }

  // create a CON_PAIR from inequality 'i' of 'soe' using symbols in 'syms'
  CON_PAIR(SYSTEM_OF_EQUATIONS *soe, const INT i, const SYMBOL_LIST *syms);

  CON_PAIR(const CON_PAIR &a, const INT dim);
    
  ~CON_PAIR() {
    if (_ac_v) {
      CXX_DELETE(_ac_v, &ARA_memory_pool);
      _ac_v = NULL;
    }
    if (_coeff) {
      CXX_DELETE_ARRAY(_coeff, &ARA_memory_pool);
      _coeff = NULL;
    }
  }

  BOOL Has_Formal_Parameter();
  ACCESS_VECTOR * Access_Vector(){ return _ac_v; }
  INT32         * Coeff() { return _coeff; }
  friend BOOL Equivalent(const CON_PAIR &a, const CON_PAIR &b, const INT dim);
  void Print(FILE *fp, INT dim) const;
  void WB_Print(FILE *fp, INT dim) const;
  INT WB_Print(char* bf, INT ccount, INT dim) const;
  void Print_Analysis_Info(FILE *fp, INT dim, DOLOOP_STACK &do_stack);

};

//============================================================================
// 
// A class to hold the constraints for one axle of an array.
// Representing 
//    lower <= axle <= upper, using:
//
//               -axle + lower <= 0
//                axle - upper <= 0
//
// If (up==NULL) 'lo' represents an equality: 
//
//                axle = lower
//
//============================================================================
class AXLE_NODE {

public:

                           // lower <= axle <= upper
  CON_PAIR      *lo;       // lower bound  [-axle + lower <= 0]
                           //                    ax1 ax2
                           // axle2 <= axle1    [ -1  1 ]

  CON_PAIR      *up;       // upper bound  [ axle - upper <= 0]
                           // coefficients between other axles
                           //                    ax1 ax2
                           // axle1 <= axle2    [  1 -1 ]

  INT16          step;     // step

  AXLE_NODE() {
    lo = up = NULL;
    step = 1;
  }

  AXLE_NODE(AXLE_NODE* a, INT dim);

  AXLE_NODE(const AXLE_NODE &a, const INT dim) {
    step = a.step;
    if (a.lo) lo = CXX_NEW(CON_PAIR(*a.lo,dim),&ARA_memory_pool);
    if (a.up) up = CXX_NEW(CON_PAIR(*a.up,dim),&ARA_memory_pool);
  }

  ~AXLE_NODE() {
    if (lo) CXX_DELETE(lo, &ARA_memory_pool);
    if (up) CXX_DELETE(up, &ARA_memory_pool);
  }

  BOOL Has_Formal_Parameter(); 
  void Clear();

  // Set axle according to system of equations and symbols
  void Set_Axle(const SYSTEM_OF_EQUATIONS *soe,
		const INT i, const INT j, const SYMBOL_LIST *syms,
		const INT depth, const INT dim,
		const INT_ST & non_const_loops,
		const INT stride);

  void Set_Axle_Eq(const SYSTEM_OF_EQUATIONS *soe,
		   const INT i, const INT j, const SYMBOL_LIST *syms,
		   const INT depth, const INT dim,
		   const INT_ST & non_const_loops,
		   const INT stride);

  void Set_Axle_Le(const SYSTEM_OF_EQUATIONS *soe,
		   const INT i, const INT j, const SYMBOL_LIST *syms,
		   const INT depth, const INT dim,
		   const INT_ST & non_const_loops,
		   const INT stride);

  void Set_Axle(const CON_PAIR *lo_new, const CON_PAIR *up_new, 
		const INT16 step_new, const INT dim);
  void Set_To_Kernel_Image(const AXLE_NODE &a, const INT dim, const INT kernel_offset);
  void Init_To_Access(ACCESS_VECTOR *av);
  
  friend BOOL Equivalent(const AXLE_NODE &a, 
			 const AXLE_NODE &b, const INT dim);

  void Print(FILE *fp, INT dim) const;
  void WB_Print(FILE *fp, INT dim) const;
  INT WB_Print(char* bf, INT ccount, INT dim) const;
  void Print_Analysis_Info(FILE *fp, INT dim, INT indent, DOLOOP_STACK &do_stack);

};

//======================================================================
// 
// A class to hold a convex region.  It is an array of AXLE_NODE where
// each AXLE_NODE representing a convex region for each axle. 
// 
//======================================================================
class REGION : public SLIST_NODE {

public:

  INT32                 _dim;         // Number of dimensions of the region
  AXLE_NODE            *_axle;        // Each axle's constraint and stride
  mUINT16               _depth;       // Nesting depth.
  ARA_REGION_TYPE       _type;        // Special region type
  BOOL                  _coupled;     // 
  ACCESS_ARRAY         *_conditions;  
  KERNEL_IMAGE         *_kernel;
  STACK<WN*>            _wn_list;     // list of WNs associated to the region

  // Create a region for array access node wn
  REGION(WN* wn, ARA_LOOP_INFO *ara_loop_info);
  REGION(WN* wn, ACCESS_ARRAY* array);
  REGION(const REGION &a);
  REGION(REGION* r);
  REGION(const INT depth, const INT dim):_wn_list(&ARA_memory_pool)
    {

      _type         = ARA_TOO_MESSY;
      _axle         = NULL;
      _conditions   = NULL;
      _kernel       = NULL;
      _depth        = depth;
      _dim          = dim;
      
    }  

  ~REGION() {

    if (_axle != NULL) CXX_DELETE_ARRAY(_axle, &ARA_memory_pool);
    if (_conditions != NULL) CXX_DELETE(_conditions, &ARA_memory_pool);

  }

  BOOL Has_Formal_Parameter();
  INT16 Num_Dim() { return _dim; }
  AXLE_NODE & Dim(INT32 i) { return _axle[i]; }
  void Set_Too_Messy() { _type = ARA_TOO_MESSY; }
  const KERNEL_IMAGE * Kernel(){ return _kernel; }
  BOOL Is_Too_Messy() const { return _type==ARA_TOO_MESSY; }
  BOOL Is_Empty() const { return _type==ARA_BOTTOM; }
  BOOL Is_All() const { return _type==ARA_TOP; }
  BOOL Is_Included(const REGION &a, const ARA_LOOP_INFO &ara_info);
  BOOL Is_Coupled() const { return _coupled; }
  BOOL Contains(WN* array_wn);
  BOOL Is_Loop_Invariant(WN *loop);
  REGION & Region_Projection(const INT pos, const ARA_LOOP_INFO &ara_info);
  void  Set_Region(const SYSTEM_OF_EQUATIONS * soe, 
		   const SYMBOL_LIST * syms,
		   const INT_ST & non_const_loops,
		   const INT strides[]);

  void Set_Region(const SYSTEM_OF_EQUATIONS * soe,
		  const SYMBOL_LIST * syms,
		  const INT_ST & non_const_loops,
		  INT strides[],
		  const INT pivot_row,
		  const INT pos, const INT step, const INT projected_axle);

  void Print(FILE *fp) const;
  void WB_Print(FILE *fp) const;
  INT WB_Print(char* bf, INT ccount) const;
  void Print_Analysis_Info(FILE *fp, INT indent, DOLOOP_STACK &do_stack);

friend  REGION * Region_Intersect(const REGION &a, const REGION &b, const ARA_LOOP_INFO &ara_info);
friend  REGION * Region_Union(const REGION &a, const REGION &b, const ARA_LOOP_INFO &ara_info);
friend  INT Region_Compare(const REGION &a, const REGION &b, const ARA_LOOP_INFO &ara_info);
friend  void Add_To_SOE(const REGION &a, const INT pos, 
			SYSTEM_OF_EQUATIONS *soe, 
			SYMBOL_LIST *syms, INT_ST & non_const_loops,
			const BOOL convert_equation,
			const ARA_LOOP_INFO &ara_info);

};

// A class to hold a list of convex regions
class REGION_UN : public SLIST {
  DECLARE_SLIST_CLASS(REGION_UN, REGION);
  
public:

  ~REGION_UN(){
    while (!Is_Empty()) CXX_DELETE(Remove_Headnode(), &ARA_memory_pool);
  }

  BOOL Has_Formal_Parameter();
  BOOL Is_Bottom() { return (Is_Empty() || Head()->Is_Empty()); }
  BOOL Is_All() { return (Head() && Head()->Is_All()); }
  BOOL Is_Included(const REGION &a, const ARA_LOOP_INFO &ara_info);
  BOOL Is_Included(const REGION_UN &a, const ARA_LOOP_INFO &ara_info);
  BOOL Contains(WN *array_wn);
  WN * Any_Wn();

  REGION_UN & Add_Region(REGION *a, const ARA_LOOP_INFO &ara_info);
  REGION_UN & RegionUN_Projection(const INT depth, ARA_LOOP_INFO &ara_info);
  void Print(FILE *fp) const;
  void WB_Print(FILE *fp) const; 
  INT WB_Print(char* bf, INT ccount) const; 
  void Print_Analysis_Info(FILE *fp, INT indent, DOLOOP_STACK &do_stack);
  
friend  REGION_UN * RegionUN_Intersect(const REGION_UN &a, const REGION_UN &b, const ARA_LOOP_INFO &ara_info);
friend  REGION_UN * RegionUN_Union(const REGION_UN &a, const REGION_UN &b, const ARA_LOOP_INFO &ara_info);
friend  BOOL RegionUN_LE(const REGION_UN &a, const REGION_UN &b, const ARA_LOOP_INFO &ara_info);
friend  BOOL RegionUN_EQ(const REGION_UN &a, const REGION_UN &b, const ARA_LOOP_INFO &ara_info);

};

class REGION_ITER : public SLIST_ITER {
  DECLARE_SLIST_ITER_CLASS(REGION_ITER, REGION, REGION_UN);
};

class REGION_CONST_ITER : public SLIST_ITER {
  DECLARE_SLIST_CONST_ITER_CLASS(REGION_CONST_ITER, REGION, REGION_UN);
};

#endif

