// $Id: MapTemplate.java,v 1.8 2001/03/21 07:57:24 msato Exp $
// $RWC_Release: Omni-1.6 $
// $RWC_Copyright:
//  Omni Compiler Software Version 1.5-1.6
//  Copyright (C) 2002 PC Cluster Consortium
//  
//  This software is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License version
//  2.1 published by the Free Software Foundation.
//  
//  Omni Compiler Software Version 1.0-1.4
//  Copyright (C) 1999, 2000, 2001.
//   Tsukuba Research Center, Real World Computing Partnership, Japan.
//  
//  Please check the Copyright and License information in the files named
//  COPYRIGHT and LICENSE under the top  directory of the Omni Compiler
//  Software release kit.
//  
//  
//  $

package exc.tea;

import exc.object.*;

public class MapTemplate {
  Xobject name;		/* key of this mapping */
  Ident id;		/* bounded Ident */
  int map_mode; 	/* TEA.MAP_xxx */
  int dist_dim;  	/* distributed dimension */
  int n_dim;		/* the number of dimension */

  int dist_dim_size;	/* size of distributed dimension */
  int lb,ub;		/* lower and upper bound of active index
			   (TEA.MAP_BLOCK) if lb == ub == 0, template only */
  int block_size;	/* block size of cyclic distribution (TEA.MAP_CYLIC) */
  int scale,offset; 	/* scaling and offset (TEA.MAP_EXPR) */
  Xobject index;
  MapTemplate ref;
  Xobject dim_info;	/* dimension information for f77 */

  public MapTemplate(Xobject name,Xobject dim_info, 
		     int map_mode,int n_dim,int dist_dim){
    this.name = name;
    this.dim_info = dim_info;
    this.map_mode = map_mode;
    this.n_dim = n_dim;
    this.dist_dim = dist_dim;
    this.scale = 1;	/* default */

    if(dim_info != null){  // set lower and upper bound 
      Xobject info = dim_info.getArg(n_dim-(dist_dim+1));
      if(info.getArg(0) == null) lb = 1;
      else lb = info.getArg(0).getInt();
      ub = info.getArg(1).getInt();
    }
  }

  public int getMode() { return map_mode; }
  public Xobject getIdent() { return name; }
  public String getName() { return name.getName(); }
  public Xobject getDimInfo() { return dim_info; }
  public int getNumDimensions() { return n_dim; }
  public void setNumDimensions(int n) { n_dim = n; }
  public int getDistDim() { return dist_dim; }
  public void setDistDim(int n) { dist_dim = n; }
  public int getBlockSize() { return block_size; }
  public int getUpperBound() { return ub; }
  public int getLowerBound() { return lb; }
  public int getScale() { return scale; }
  public int getOffset() { return offset; }
  public Xobject getIndex() { return index; }
  public MapTemplate getRef() { return ref; }

  public void setRef(MapTemplate tp){ 
    ref = tp; 
  }

  public void boundIdent(Ident id){
    this.id = id;

    // compute size of dimension size
    Xtype at = id.Type();
    for(int i = n_dim-1; i >= 0; i--){
      if(i == dist_dim){
	dist_dim_size = at.getArrayDim();
	break;
      }
      at = at.getRef();
    }
  }

  int t_scale,t_offset;

  /* finally reduce template */
  public void Reduce(){
    if(map_mode == TEA.MAP_CYCLIC) return; // reduced 
    if(map_mode == TEA.MAP_BLOCK){
      block_size = dist_dim_size;
      return;
    }
    t_scale = 1;
    t_offset = 0;
    reduceRec(this);
    scale = t_scale;
    offset = t_offset;
  }

  void reduceRec(MapTemplate tp){
    if(tp == null) return;  // fatal ???

    if(tp.map_mode == TEA.MAP_CYCLIC){
      map_mode = tp.map_mode;
      block_size = tp.block_size;
      ub = tp.ub;
      lb = tp.lb;
    } else if(tp.map_mode == TEA.MAP_BLOCK){
      map_mode = tp.map_mode;
      ub = tp.ub;
      lb = tp.lb;
      if(tp.id == null) block_size = tp.ub - tp.lb;
      else block_size = tp.dist_dim_size;
    } else if(tp.map_mode == TEA.MAP_EXPR){
      reduceRec(tp.ref);
    }
    t_scale = t_scale*tp.scale;
    t_offset = t_offset*tp.scale + tp.offset;
  }

  // for debug
  public String toString() {
    String s;
    if(name != null) s = name.getName()+"("+dist_dim+"/"+n_dim+")";
    else s = "???";

    switch(map_mode){
    case TEA.MAP_NONE:
      return "[MAP_NONE,"+s+"]";
    case TEA.MAP_EXPR:
      return "[MAP_EXPR,"+s+",index="+index
	+",scale="+scale+",offset="+offset
	+",ref="+(ref == null?"*":ref.getName())+"]";
    case TEA.MAP_BLOCK:
      return "[MAP_BLOCK,"+s+",index="+index
	+",scale="+scale+",offset="+offset+"]";
    case TEA.MAP_CYCLIC:
      return "[MAP_CYCLIC,"+s+",block_size="+block_size
	+",index="+index
	+",scale="+scale+",offset="+offset+"]";
    default:
      return "[MAP_???]";
    }
  }

  public static MapTemplate None(Xobject name,Xobject dim_info){
    MapTemplate tp = new MapTemplate(name,dim_info,TEA.MAP_NONE,0,0);
    return tp;
  }

  public static MapTemplate Block(Xobject name,Xobject dim_info,
				  int n_dim,int dist_dim){
    MapTemplate tp = new MapTemplate(name,dim_info,
				     TEA.MAP_BLOCK,n_dim,dist_dim);
    return tp;
  }

  public static MapTemplate Cyclic(Xobject name,Xobject dim_info,
				   int n_dim,int dist_dim,int block_size){
    MapTemplate tp = new MapTemplate(name,dim_info,
				     TEA.MAP_CYCLIC,n_dim,dist_dim);
    tp.block_size = block_size;
    return tp;
  }

  public static MapTemplate Expr(Xobject name,Xobject dim_info,
				 int n_dim,int dist_dim,
				 Xobject index,int scale,int offset){
    MapTemplate tp = new MapTemplate(name,dim_info,
				     TEA.MAP_EXPR,n_dim,dist_dim);
    tp.index = index;
    tp.scale = scale;
    tp.offset = offset;
    return tp;
  }
}






