// $Id: optLoopTransform.java,v 1.7 2000/04/25 07:10:44 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.
//  
//  
//  $

// obsolute! it should be replaced with loopAnalyzer

package exc.flow;

import exc.object.*;
import exc.block.*;
import java.util.Vector;

public class optLoopTransform {
  static boolean debugFlag;

  final static String optLoopProp = "optLoop";
  optBodyEnv optEnv;

  // find optimizable loops and mark it.
  // Put Property "optLoopProp" with optLoopInfo at Loop landing_pad.
  public void run(optBodyEnv env){
    optEnv = env;

    ControlFlowGraph cfg = optEnv.getCFG();
    for(BasicBlock bb = cfg.getHead(); bb != null; bb = bb.topNext()){

      /* find backedge */
      Vector out_edges = bb.getCflowOut();
      for(int i = 0; i < out_edges.size(); i++){
	BasicBlock bp = (BasicBlock)out_edges.elementAt(i);
	if(bp.DFN() <= bb.DFN()) checkLoop(bp,bb);
      }
    }
  }

  /* check optimizable loop:
   * (1) single entry / single exit. 
   * (2) single landing pad
   * (3) single flow in exit block.
   */
  void checkLoop(BasicBlock header, BasicBlock tail){
    BasicBlock bb,exit_bb;

    if(debugFlag) System.out.println("checkLoop["+header+","+tail+"]");

    /* check single landing pad */
    if(header.getCflowIn().size() != 2){
      if(debugFlag) System.out.println("header In != 2, fail");
      return;
    }
      
    /* mark all loop block */
    ControlFlowGraph cfg = optEnv.getCFG();
    for(bb = cfg.getHead(); bb != null; bb = bb.topNext()) bb.resetMark();
    header.setMark();
    backwardMarkBasicBlock(tail);

    /* find exit basic block */
    exit_bb = null;
    for(bb = header; ; bb = bb.topNext()){
      if(!bb.isMarked()) break;
      Vector out_edges = bb.getCflowOut();
      for(int i = 0; i < out_edges.size(); i++){
	BasicBlock bp = (BasicBlock)out_edges.elementAt(i);
	if(!bp.isMarked()){
	  if(exit_bb != null){
	    if(debugFlag) System.out.println("multiple exit, fail");
	    return; /* fail */
	  }
	  exit_bb = bp;
	}
      }
      if(bb == tail) break;
    }
    if(exit_bb == null
       || exit_bb.getCflowIn() == null
       || exit_bb.getCflowIn().size() != 1){
      if(debugFlag) System.out.println("exit In != 1, fail");
      return;
    }

    BasicBlock landing_pad = header.getCflowIn(0);

    if(landing_pad.getCflowOut().size() != 1 ||
       landing_pad.isMarked()) return;

    landing_pad.setProp(optLoopProp,
			new optLoopInfo(header,tail,landing_pad,exit_bb));

    if(debugFlag) 
      System.out.println("success! landing_pad="+landing_pad+
			  ", exit_pad"+exit_bb);
  }

  void backwardMarkBasicBlock(BasicBlock bb){
    if(bb.isMarked()) return;
    bb.setMark();
    Vector in_edges = bb.getCflowIn();
    for(int i = 0; i < in_edges.size(); i++)
      backwardMarkBasicBlock((BasicBlock)in_edges.elementAt(i));
  }

  public void topdownVisit(optLoopVisitor visitor){
    ControlFlowGraph cfg = optEnv.getCFG();
    for(BasicBlock bb = cfg.getHead(); bb != null; bb = bb.topNext()){
      optLoopInfo info = (optLoopInfo)bb.getProp(optLoopProp);
      if(info != null){
	if(debugFlag) System.out.println("optLoopInfo="+info);
	visitor.visitLoop(info);
      }
    }
  }

  public void bottomupVisit(optLoopVisitor visitor){
    ControlFlowGraph cfg = optEnv.getCFG();
    for(BasicBlock bb = cfg.getTail(); bb != null; bb = bb.topPrev()){
      optLoopInfo info = (optLoopInfo)bb.getProp(optLoopProp);
      if(info != null){
	if(debugFlag) System.out.println("optLoopInfo="+info);
	visitor.visitLoop(info);
      }
    }
  }
}


