// $Id: rangeExpr.java,v 1.5 2001/02/05 10:38:40 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.flow;

import exc.object.*;
import exc.openmp.*;

/* Xobject to express iteration and access pattern
 * { lb <= var < ub, with step}
 *  or 
 * { scale*i+b: lb <= var < ub, with step and OpenMP schedule }
 */
public class rangeExpr extends XobjList {
  public static final int FOR = Xobject.newCode();
  public static final int FORALL = Xobject.newCode();

  // Xobject lb,ub; /* 0,1 */
  // Xobject step; /* 2 */	/* must be integer expression. */

  boolean is_inc;

  // Xobject scale,offset; /* 3 */
  // Xobject chunk;	   /* 4 */
  int sched;

  public rangeExpr(int code, Xobject lb, Xobject ub,Xobject step,
		    int incOp, int chkOp, Xobject expr){
    super(code);
    /* check incOp */
    switch(incOp){
    case Xcode.MINUS_EXPR:
      step = Xcons.unaryOp(Xcode.UNARY_MINUS_EXPR,step);
    case Xcode.PLUS_EXPR:
      break;
    default:
      fatal("bad incOp");
    }
    /* check chkOp */
    switch(chkOp){
    case Xcode.LOG_GE_EXPR:
      ub = Xcons.binaryOp(Xcode.PLUS_EXPR,ub,step);
    case Xcode.LOG_GT_EXPR:
      is_inc = false;
      break;
    case Xcode.LOG_LE_EXPR:
      ub = Xcons.binaryOp(Xcode.PLUS_EXPR,ub,step);
    case Xcode.LOG_LT_EXPR:
      is_inc = true;
      break;
    default:
      fatal("bad chkOp");
    }
    add(Xcons.Reduce(lb));
    add(Xcons.Reduce(ub));
    add(Xcons.Reduce(step));
    add(expr);
  }

  public Xobject getLowerBound() { return getArg(0);  }
  public void setLowerBound(Xobject e) { setArg(0,e);  }
  public Xobject getUpperBound() { return getArg(1); }
  public void setUpperBound(Xobject e) { setArg(1,e); }
  public Xobject getStep() { return getArg(2);  }
  public boolean isInc() { return is_inc; }
  public Xobject getIncFlagValue() { return Xcons.IntConstant(is_inc? 1: 0); }

  public Xobject getExpr() { return getArg(3); }
  public void setExpr(Xobject e) { setArg(3,e); }

  public static Xobject exprScale(Xobject e){ 
    if(e.Opcode() == Xcode.LIST) return e.getArg(0); 
    return Xcons.IntConstant(1);
  }
  public static Xobject exprOffset(Xobject e){ 
    if(e.Opcode() == Xcode.LIST) return e.getArg(1); 
    return Xcons.IntConstant(0);
  }
  public static Xobject exprIndirectAddr(Xobject e) { 
    if(e.Opcode() == Xcode.LIST && e.Nargs() > 2)
      return e.getArg(2);
    return Xcons.IntConstant(0);
  }
  public static Xobject exprIndirectOffset(Xobject e) { 
    if(e.Opcode() == Xcode.LIST && e.Nargs() > 3)
      return e.getArg(3);
    return Xcons.IntConstant(0);
  }

  public Xobject getScale() { return getArg(3).getArg(0); }
  public Xobject getOffset() { return getArg(3).getArg(1); }

  public int getSched() { return sched; }
  public Xobject getChunk() { return getArg(4); }

  public static rangeExpr For(Xobject lb, Xobject ub,Xobject step,
			      int incOp, int chkOp, Xobject e){
    return new rangeExpr(FOR,lb,ub,step,incOp,chkOp,e);
  }
  
  public static rangeExpr ForAll(Xobject lb, Xobject ub,Xobject step,
				 int incOp, int chkOp, Xobject e,
				 int sched,Xobject chunk){
    rangeExpr r = new rangeExpr(FORALL,lb,ub,step,incOp,chkOp,e);
    r.add(chunk);
    r.sched = sched;
    return r;
  }

  public boolean isLoopInvariant(loopInfo info){
    if(!isLoopInvariant(info,getLowerBound())) return false;
    if(!isLoopInvariant(info,getUpperBound())) return false;
    if(!info.isLoopInvariantExpr(getStep())) return false;
    if(Opcode() == FOR) return true;

    if(!info.isLoopInvariantExpr(getChunk())) return false;
    if(!isLoopInvariant(info,getExpr())) return false;
    if(sched == OMP.SCHED_NONE || sched == OMP.SCHED_STATIC) return true;
    else return false;
  }
  
  boolean isLoopInvariant(loopInfo loop,Xobject e){
    if(e.Opcode() == Xcode.LIST){
      for(XobjArgs a = e.getArgs() ; a != null; a = a.nextArgs())
	if(!loop.isLoopInvariantExpr(a.getArg())) return false;
      return true;
    } else return loop.isLoopInvariantExpr(e);
  }

  public String toString(){
    if(Opcode() == FORALL)
      return "<FORALL "+getExpr()+" ("+sched+","+getChunk()+") "+
	"["+getLowerBound()+","+getUpperBound()+","+getStep()+","+is_inc+"]>";
    else 
      return "<FOR "+getExpr()+"["+getLowerBound()+","+getUpperBound()+","+
	getStep()+","+is_inc+"]>";
  }

  static void fatal(String msg){
    System.err.println("Fatal rangeExpr:"+msg);
    Thread.dumpStack();
    System.exit(1);
  }
}

