// $Id: ForBlock.java,v 1.10 2001/10/18 09:02:29 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.block;
import exc.object.*;

public class ForBlock extends CondBlock {
  BasicBlock init_part,iter_part;

  // for cannonical shaped for-loop
  boolean is_canonical;
  Xobject ind_var;
  Xobject ub,lb,step;

  public ForBlock(BasicBlock init,
		  BasicBlock cond,
		  BasicBlock iter,
		  BlockList body){
    super(Xcode.FOR_STATEMENT,cond,body);
    this.init_part = init;
    this.iter_part = iter;
    if(init_part != null) init_part.parent = this;
    if(iter_part != null) iter_part.parent = this;
  }

  public BasicBlock getInitBBlock() { return init_part; }
  public BasicBlock getIterBBlock() { return iter_part; }

  public void setInitBlock(BasicBlock s){
    init_part = s;
    s.parent = this;
  }
  public void setIterBlock(BasicBlock s){
    iter_part = s;
    s.parent = this;
  }

  public void visitBasicBlock(BasicBlockVisitor v){
    v.visit(init_part);
    v.visit(bblock); 
    v.visit(iter_part);
  }

  // check the canonical form, "for(..., v = lb; v < up; v++)"
  public void Canonicalize(){
    Xobject e,ind_var,ub,lb,step;
    Statement s;
    BasicBlock cond = getCondBBlock();

    // check condition part
    if(cond.getHead() != null) return;
    if((e = cond.getExpr()) == null) return;
    switch(e.Opcode()){
    case Xcode.LOG_LE_EXPR:
    case Xcode.LOG_LT_EXPR:
    case Xcode.LOG_GE_EXPR:
    case Xcode.LOG_GT_EXPR:
      break;
    default:
      return;
    }
    ind_var = e.left();
    if(!ind_var.isVariable()) return;
    if(!ind_var.Type().isIntegral()) return;
    ub = e.right();

    // check init part. the tail must be v=lb
    if(init_part.getHead() == null) return;
    e = init_part.getHead().getExpr();
    if(e.Opcode() == Xcode.COMMA_EXPR){
      // expand comma expression
      s = init_part.getHead();
      for(XobjArgs a = e.getArgs(); a != null; a = a.nextArgs())
	s = s.add(a.getArg());
      init_part.getHead().remove();  // remove original comma expr
    } 
    e = init_part.getTail().getExpr();
    if(e.Opcode() != Xcode.ASSIGN_EXPR) return;
    if(!e.left().equals(ind_var)) return;
    lb = e.right();

    // check iteration expression, and canonicalize
    // only first expression is recognized as iteration expression
    // if(!iter_part.isSingle()) return;

    e = iter_part.getHead().getExpr();
    switch(e.Opcode()){
    case Xcode.POST_INCR_EXPR:
      if(!e.operand().equals(ind_var)) return;
      step = Xcons.IntConstant(1);
      break;
    case Xcode.POST_DECR_EXPR:
      if(!e.operand().equals(ind_var)) return;
      step = Xcons.IntConstant(-1);
      break;
    case Xcode.ASG_PLUS_EXPR:
      if(!e.left().equals(ind_var)) return;
      step = e.right();
      break;
    case Xcode.ASG_MINUS_EXPR:
      if(!e.left().equals(ind_var)) return;
      step = Xcons.unaryOp(Xcode.UNARY_MINUS_EXPR,e.right());
      break;
    case Xcode.ASSIGN_EXPR:
      if(!e.left().equals(ind_var)) return;
      switch(e.right().Opcode()){
      case Xcode.PLUS_EXPR:
	if(e.right().left().equals(ind_var)) {
	  step = e.right().right();
	} else if(e.right().right().equals(ind_var)){
	  step = e.right().left();
	} else return;
	break;
      case Xcode.MINUS_EXPR:
	if(e.right().left().equals(ind_var)){
	  step = Xcons.unaryOp(Xcode.UNARY_MINUS_EXPR,
			       e.right().right());
	} else return;
	break;
      default:
	return;
      }
      break;
    default:
      return;
    }
    // canonicalize iteration expression
    if(e.Opcode() != Xcode.ASG_PLUS_EXPR){
      iter_part.getHead().
	setExpr(Xcons.asgOp(Xcode.ASG_PLUS_EXPR,ind_var,step));
    }
    if(!iter_part.isSingle()){
      BasicBlock bb = new BasicBlock();
      while((s = iter_part.getHead().getNext()) != null){
	s.remove();
	bb.add(s);
      }
      body.add(bb);
    }

    // canonicalize conditional expression
    e = cond.getExpr();
    if(e.Opcode() == Xcode.LOG_LE_EXPR){
      ub = Xcons.binaryOp(Xcode.PLUS_EXPR,ub,/*step*/Xcons.IntConstant(1));
      cond.setExpr(Xcons.binaryOp(Xcode.LOG_LT_EXPR,ind_var,ub));
    } else if(e.Opcode() == Xcode.LOG_GE_EXPR){
      ub = Xcons.binaryOp(Xcode.PLUS_EXPR,ub,/*step*/Xcons.IntConstant(-1));
      cond.setExpr(Xcons.binaryOp(Xcode.LOG_GT_EXPR,ind_var,ub));
    } 
	
    this.ind_var = ind_var;
    this.ub = ub;
    this.lb = lb;
    this.step = step;
    is_canonical = true;
  }

  public boolean isCanonical() { return is_canonical; }
  public Xobject getInductionVar(){ return ind_var; }
  public Xobject getLoopVar() { return ind_var; } // same as IndictionVar
  public Xobject getLowerBound(){ return lb; }
  public Xobject getUpperBound(){ return ub; }
  public Xobject getStep(){ return step; }
  public int getCheckOpcode() { return getCondBBlock().getExpr().Opcode(); }

  public void setLowerBound(Xobject x){ 
    init_part.getTail().getExpr().setRight(x);
  }

  public void setUpperBound(Xobject x){ 
    BasicBlock cond = getCondBBlock();
    cond.getExpr().setRight(x);
  }

  public void setStep(Xobject x){ 
    iter_part.getHead().getExpr().setRight(x);
  }

  public Xobject toXobject(){
    Xobject init_x = null, cond_x = null, iter_x = null;
    if(getInitBBlock() != null) init_x = getInitBBlock().toXobject();
    if(getCondBBlock() != null) cond_x = getCondBBlock().toXobject();
    if(getIterBBlock() != null) iter_x = getIterBBlock().toXobject();
    Xobject x = new XobjList(Opcode(),init_x,cond_x,iter_x,
			     getBody().toXobject());
    x.setLineNo(getLineNo());
    return x;
  }
}

