// $Id: OMPtransPragmaBlock.java,v 1.31 2002/02/27 16:05:04 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.openmp;

import java.io.*;
import exc.object.*;
import exc.block.*;

import java.util.*;

public class OMPtransPragmaBlock extends OMPtransPragma {

  public boolean moveAutoFlag;

  public String bcastCopy = "_ompc_bcast_copy";
  public String thdprvCopy = "_ompc_bcast_thdprv";
  public String lastCopy = "_ompc_last_copy";

  public OMPtransPragmaBlock(){
    /* nothing */
  }

  public Block transBarrier(PragmaBlock b,OMPinfo i){
    return OMPBlock.Barrier();
  }

  public Block transParallelRegion(PragmaBlock b, OMPinfo i){
    Xobject s;
    Block bp;

    // caller side setup
    int nargs = i.region_args.size();
    BasicBlock caller_setup_bb = new BasicBlock();
    for(int ii = 0; ii < nargs; ii++){
      s = (Xobject)i.region_args.elementAt(ii);
      s = Xcons.List(Xcode.OMP_SETARG,Xcons.IntConstant(ii),s);
      caller_setup_bb.add(s);
    }

    // callee side, move blocks to body
    BlockList body = Bcons.emptyBody(i.id_list,null);
    body.add(Bcons.COMPOUND(b.getBody())); // original body

    // insert data setup
    bp = dataSetupBlock(i);
    if(bp != null) body.insert(bp);

    // insert setup argument
    BasicBlock bblock = new BasicBlock();
    for(int ii = 0; ii < i.region_params.size(); ii++){
      s = ((Ident)i.region_params.elementAt(ii)).Ref();
      s = Xcons.Set(s,Xcons.List(Xcode.OMP_GETARG,s.Type(),
				 Xcons.IntConstant(ii)));
      bblock.add(s);
    }
    body.insert(bblock);

    // add update block
    bp = dataUpdateBlock(i);
    if(bp != null) body.add(bp);

    // check threadprivate
    threadprivateSetup(body,i);

    return OMPBlock.ParallelRegion(nargs,caller_setup_bb,body,i.getIfExpr());
  }

  public Block transFor(PragmaBlock b, OMPinfo i){
    ForBlock for_block = (ForBlock)b.getBody().getHead();
    for_block.Canonicalize();  // canonicalize again
    Block bp;

    if(!for_block.isCanonical())  OMP.fatal("transFor: not canonical");

    Xobject ind_var = for_block.getInductionVar();
    BlockList ret_body = Bcons.emptyBody(i.id_list,null);

    bp = dataSetupBlock(i);
    if(bp != null) ret_body.add(bp);

    BasicBlock bb = new BasicBlock();
    ret_body.add(bb);
    for(StatementIterator si = for_block.getInitBBlock().statements();
	si.hasMoreStatement(); ){
      Statement s = si.nextStatement();
      if(s.getNext() == null) break;
      s.remove();
      bb.add(s);
    }
    ret_body.add(OMPBlock.Forall(for_block.getLoopVar(),
				 for_block.getLowerBound(),
				 for_block.getUpperBound(),
				 for_block.getStep(),
				 for_block.getCheckOpcode(),
				 for_block.getBody(),
				 i.sched,i.sched_chunk,i.ordered));
    bp = dataUpdateBlock(i);
    if(bp != null) ret_body.add(bp);

    if(!i.no_wait)  ret_body.add(OMPBlock.Barrier());
    return Bcons.COMPOUND(ret_body);
  }

  public Block transSections(PragmaBlock b, OMPinfo i){
    Block bp;
    BlockList ret_body = Bcons.emptyBody(i.id_list,null);
    int n = 0;

    bp = dataSetupBlock(i);
    if(bp != null) ret_body.add(bp);

    n = 0;
    for(bp = b.getBody().getHead(); bp != null; bp = bp.getNext()) n++;

    ret_body.add(OMPBlock.Sections(n,b.getBody()));

    bp = dataUpdateBlock(i);
    if(bp != null) ret_body.add(bp);
	
    if(!i.no_wait) ret_body.add(OMPBlock.Barrier());
    return Bcons.COMPOUND(ret_body);
  }

  public Block transSingle(PragmaBlock b, OMPinfo i){
    BlockList body = Bcons.emptyBody(i.id_list,null);
    BlockList ret_body = Bcons.emptyBody();
    Block bp;

    bp = dataSetupBlock(i);
    if(bp != null) body.add(bp);
    body.add(Bcons.COMPOUND(b.getBody()));
    ret_body.add(OMPBlock.Single(body));
    if(!i.no_wait) ret_body.add(OMPBlock.Barrier());
    return Bcons.COMPOUND(ret_body);
  }

  public Block transMaster(PragmaBlock b, OMPinfo i){
    return OMPBlock.Master(b.getBody());
  }

  public Block transCritical(PragmaBlock b, OMPinfo i){
    return OMPBlock.Critical(i.arg,b.getBody());
  }
    
  public Block transAtomic(PragmaBlock b, OMPinfo i){
    BlockList body = b.getBody();
    BasicBlock bb = body.getHead().getBasicBlock();
    Statement s = bb.getHead();
    Xobject x = s.getExpr();  // atomic update statment
    if(x.Opcode() != Xcode.POST_INCR_EXPR &&
       x.Opcode() != Xcode.POST_DECR_EXPR){
      /* x op= rv */
      Xobject rv = x.right();
      Ident rv_var = Ident.Local(env.genSym("t"),rv.Type());
      body.addIdent(rv_var);
      s.insert(Xcons.Set(rv_var.Ref(),rv));
      x.setRight(rv_var.Ref());
    }
    Xobject lv = x.operand();
    Ident addr_var = Ident.Local(env.genSym("t"),Xtype.Pointer(lv.Type()));
    body.addIdent(addr_var);
    s.insert(Xcons.Set(addr_var.Ref(),Xcons.AddrOf(lv))); /* p = &lv */
    x.setOperand(Xcons.PointerRef(addr_var.Ref())); 	/* lv -> *p */
    s.insert(OMPfuncIdent(atomicLockFunc).Call(null));
    s.add(OMPfuncIdent(atomicUnlockFunc).Call(null));
    return Bcons.COMPOUND(body);
  }

  public Block transFlush(PragmaBlock b, OMPinfo i){
    return OMPBlock.Flush(i.flush_vars);
  }

  public Block transOrdered(PragmaBlock b, OMPinfo i){
    return OMPBlock.Ordered(b.getBody());
  }

  public Block dataSetupBlock(OMPinfo i){
    BasicBlock bb = new BasicBlock();

    for(OMPvar v = i.varlist; v != null; v = v.next){
      if(v.adj_array_size != null && v.private_addr != null) continue;
      if(v.is_first_private){
	bb.add(Xcons.List(Xcode.OMP_BCAST,v.private_addr,v.shared_addr,
			  v.getSize()));
      }
    }

    for(OMPvar v = i.varlist; v != null; v = v.next){

      if(v.adj_array_size != null && v.private_addr != null){  
	// adjustable array
	Ident alloca_f = OMPfuncIdent(allocaFunc);
	alloca_f.Declared();	// make already declared 
	bb.add(Xcons.Set(v.private_addr,
			 Xcons.Cast(v.private_addr.Type(),
				    alloca_f.Call(Xcons.List(v.adj_array_size)))));
			 
      }

      if(v.is_first_private) continue;
      
      if(v.is_reduction){
	// only scalar variable 
 	if(Xtype.isFComplex(v.id.Type())){
 	  int bt = Xtype.FComplexBasicType(v.id.Type());
 	  bb.add(OMPfuncIdent(doReductionInit).
 		 Call(Xcons.List(v.private_addr,
 				 Xcons.IntConstant(bt),
 				 Xcons.IntConstant(v.reduction_op))));
 	} else {
	  /* issue OMP_SHARE to protect this variable from optimize */
	  bb.add(Xcons.List(Xcode.OMP_SHARE,v.private_addr,null));
 	  bb.add(Xcons.Set(Xcons.PointerRef(v.private_addr),
 			   v.reductionInitValue()));
	}
      } else if(v.is_copyin){
	if(OMP.leaveThreadPrivateFlag){
	  Ident id = v.id;
	  bb.add(Xcons.List(Xcode.OMP_BCAST_THDPRV,
			    id.getAddr(),id.getAddr(),
			    Xcons.IntConstant(id.Type().getSize())));
	} else {
	  Ident thdprv_id = v.id;
	  int idx = i.thdprv_id_list.indexOf(thdprv_id);
	  if(idx < 0) OMP.fatal("bad copyin: "+thdprv_id.getName());
	  Ident local_id = (Ident)(i.thdprv_local_id_list.elementAt(idx));
	  bb.add(Xcons.List(Xcode.OMP_BCAST_THDPRV,
			    local_id.Ref(),thdprv_id.getAddr(),
			    Xcons.IntConstant(thdprv_id.Type().getSize())));
	}
      } else if(v.is_shared){
	Ident id = v.id;
	bb.add(Xcons.List(Xcode.OMP_SHARE,v.shared_addr,id));
      }
    }
    return Bcons.BasicBlock(bb);
  }

  public Block dataUpdateBlock(OMPinfo i){
    boolean reduction_flag = false;
    boolean lastprivate_flag = false;
    for(OMPvar v = i.varlist; v != null; v = v.next){
      if(v.is_last_private) lastprivate_flag = true;
      if(v.is_reduction) reduction_flag = true;
    }
    if(!lastprivate_flag && !reduction_flag) return null;

    BasicBlock bb = new BasicBlock();
    if(reduction_flag){
      for(OMPvar v = i.varlist; v != null; v = v.next){
	if(!v.is_reduction) continue;
	int bt;
	if(v.id.Type().isEnum()) bt = BasicType.INT;
	else if(v.id.Type().isScalar()) bt = v.id.Type().getBasicType();
 	else if(Xtype.isFComplex(v.id.Type()))
 	  bt = Xtype.FComplexBasicType(v.id.Type());
	else {
	  OMP.fatal("bad reduction variable type");
	  continue;
	}
	bb.add(Xcons.List(Xcode.OMP_REDUCTION,
			  v.private_addr,v.shared_addr,
			  Xcons.IntConstant(bt),
			  Xcons.IntConstant(v.reduction_op)));
      }
    } 
    if(lastprivate_flag){
      for(OMPvar v = i.varlist; v != null; v = v.next){
	if(!v.is_last_private) continue;
	bb.add(Xcons.List(Xcode.OMP_LAST_UPDATE,
			  v.shared_addr,v.private_addr,
			  v.getSize()));
      }
    }
    return Bcons.BasicBlock(bb);
  }

  public void threadprivateSetup(BlockList body,OMPinfo i){
    if(OMP.leaveThreadPrivateFlag) return;
    if(i.thdprv_local_id_list.isEmpty()) return;
    BasicBlock bb = new BasicBlock();
    Enumeration ee = i.thdprv_id_list.elements();
    for(Enumeration e = i.thdprv_local_id_list.elements();
	e.hasMoreElements(); ){
      Ident id = (Ident)e.nextElement();
      body.addIdent(id);
      Ident thdprv_id = (Ident)ee.nextElement();
      Xobject x = OMPfuncIdent(getThdprvFunc).
	Call(Xcons.List(Xcons.Symbol(Xcode.VAR_ADDR,
				     "_thdprv_"+thdprv_id.getName()),
			Xcons.IntConstant(thdprv_id.Type().getSize()),
			thdprv_id.getAddr()));
      bb.add(Xcons.Set(id.Ref(),Xcons.Cast(id.Type(),x)));
    }
    body.insert(bb);
  }


  /* 
   * transform OMPBlock
   */
  public void transBlock(FuncDefBlock def){
    Block b;
    Block fblock = def.getBlock();
    current_def = def.getDef();
    env = current_def.getFile();

    if(OMP.debugFlag) System.out.println("pass3-transBlock:");

    cleanupOMPcode(fblock);

    BlockIterator i = new bottomupBlockIterator(fblock);
    for(i.init(); !i.end(); i.next()){
      b = i.getBlock();
      switch(b.Opcode()){
      case Xcode.OMP_PARALLEL:
	i.setBlock(transParallelBlock((OMPparallelBlock)b));
	break;
      case Xcode.OMP_FORALL:
	i.setBlock(transForallBlock((OMPforallBlock)b));
	break;
      case Xcode.OMP_SECTIONS:
	i.setBlock(transSectionsBlock((OMPBlock)b));
	break;
      case Xcode.OMP_CRITICAL:
	i.setBlock(transCriticalBlock((OMPBlock)b));
	break;
      case Xcode.OMP_SINGLE:
	i.setBlock(transSingleBlock((OMPBlock)b));
	break;
      case Xcode.OMP_MASTER:
	i.setBlock(transMasterBlock((OMPBlock)b));
	break;
      case Xcode.OMP_ORDERED:
	i.setBlock(transOrderedBlock((OMPBlock)b));
	break;
      case Xcode.OMP_ATOMIC:
	i.setBlock(transAtomicBlock((OMPBlock)b));
	break;
      case Xcode.OMP_FLUSH:
	i.setBlock(transFlushBlock((OMPBlock)b));
	break;
      case Xcode.OMP_BARRIER:
	i.setBlock(transBarrierBlock((OMPBlock)b));
	break;
      } 
    }
  }

  void cleanupOMPcode(Block fblock){
    for(BasicBlockExprIterator i = new BasicBlockExprIterator(fblock);
	!i.end(); i.next()){
      Xobject x = i.getExpr();
      if(x == null) continue;
      switch(x.Opcode()){
      case Xcode.OMP_BCAST:
	i.setExpr(OMPfuncIdent(bcastCopy).Call(x));
	break;
      case Xcode.OMP_BCAST_THDPRV:
	i.setExpr(OMPfuncIdent(thdprvCopy).Call(x));
	break;
      case Xcode.OMP_SHARE:	// ingore as default
	i.setExpr(null);
	break;
      case Xcode.OMP_REDUCTION:
	i.setExpr(OMPfuncIdent(doReduction).Call(x));
	break;
      case Xcode.OMP_LAST_UPDATE:
	i.setExpr(OMPfuncIdent(lastCopy).Call(x));
	break;
      }
    }

  }

  public Block transParallelBlock(OMPparallelBlock b){
    Ident func_id = 
      env.declStaticIdent(env.genSym(OMPfuncPrefix),
			  Xtype.Function(Xtype.voidType));
    BlockList ret_body = Bcons.emptyBody();

    BasicBlock setup_bb = b.setupBasicBlock();
    BasicBlock end_bb = b.endBasicBlock();

    int nargs = b.getNarg();
    if(nargs != 0){
      Xtype voidP_t = Xtype.Pointer(Xtype.voidType);
      Ident av = 
	Ident.Local("__ompc_argv",Xtype.Array(voidP_t,nargs));
      ret_body.addIdent(av);
      for(StatementIterator is = setup_bb.statements();
	  is.hasMoreStatement(); ){
	Statement s = is.nextStatement();
	Xobject x = s.getExpr();
	if(x.Opcode() == Xcode.OMP_SETARG){
	  Xobject av_idx = av.Index(x.getArg(0));
	  Xobject v = x.getArg(1);
	  if(OMP.moveAutoFlag && 
	     (v.Opcode() == Xcode.LVAR_ADDR ||
	      v.Opcode() == Xcode.LARRAY_ADDR ||
	      v.Opcode() == Xcode.PARAM_ADDR ||
	      v.Opcode() == Xcode.FPARAM_VAR_ADDR ||
	      v.Opcode() == Xcode.FPARAM_ARRAY_ADDR)){
	    Xobject size;
	    if(v.Type().isArray()){
	      if(v.Type().getArrayDim() == -1)
		size = v.Type().getArrayAdjSize().copy();
	      else
		size = Xcons.IntConstant(v.Type().getSize());
	    } else 
	      size = Xcons.IntConstant(v.Type().getRef().getSize());
	    Xobject vv = OMPfuncIdent(allocShared).Call(Xcons.List(v,size));
	    end_bb.insert(OMPfuncIdent(freeShared).
			  Call(Xcons.List(av_idx,v,size)));
	    v = vv;
	  }
	  s.setExpr(Xcons.Set(av_idx,Xcons.Cast(voidP_t,v)));
	}
      }
      if(b.getIfExpr() != null)
	setup_bb.add(OMPfuncIdent(doParallelIfFunc).
		     Call(Xcons.List(b.getIfExpr(),func_id.Ref(),
				     av.Ref(),Xcons.IntConstant(nargs))));
      else
	setup_bb.add(OMPfuncIdent(doParallelFunc).
		     Call(Xcons.List(func_id.Ref(),
				     av.Ref(),Xcons.IntConstant(nargs))));
    } else {
      if(b.getIfExpr() != null)
	setup_bb.add(OMPfuncIdent(doParallelIfFunc).
		     Call(Xcons.List(b.getIfExpr(),func_id.Ref(),
				     Xcons.IntConstant(0),
				     Xcons.IntConstant(0))));
      else 
	setup_bb.add(OMPfuncIdent(doParallelFunc).
		     Call(Xcons.List(func_id.Ref(),
				     Xcons.IntConstant(0),
				     Xcons.IntConstant(0))));
    }
    ret_body.add(setup_bb);
    ret_body.add(end_bb);

    // make parallel region fuction body
    BlockList body = b.getBody();
    Xobject param_id_list = Xcons.emptyIdList();
    if(nargs != 0){
      Xtype voidP_t = Xtype.Pointer(Xtype.voidType);
      Ident pv = Ident.Param("__ompc_args",Xtype.Pointer(voidP_t));
      param_id_list.add(pv);
      BasicBlock bb = body.getHead().getBasicBlock();
      for(StatementIterator is = bb.statements();
	  is.hasMoreStatement(); ){
	Statement s = is.nextStatement();
	Xobject x = s.getExpr();
	if(x.isSet() && x.right().Opcode() == Xcode.OMP_GETARG){
	  x.setRight(Xcons.Cast(x.left().Type(),
				pv.Index(x.right().operand())));
	}
      }
    }

    // make prototype for func_id
    ((FunctionType)func_id.Type()).setFuncParamIdList(param_id_list);

    FuncDefBlock para_fd = 
      new FuncDefBlock(func_id.getName(),param_id_list,null,body,env);
    current_def.insert(para_fd.getDef());
    return Bcons.COMPOUND(ret_body);
  }

  public Block transForallBlock(OMPforallBlock b){

      
    BlockList ret_body = Bcons.emptyBody();
    Xobject ind_var = b.getLoopVar();
    Ident lb_var = 
      Ident.Local(env.genSym(ind_var.getName()),ind_var.Type());
    Ident ub_var = 
      Ident.Local(env.genSym(ind_var.getName()),ind_var.Type());
    Ident step_var = 
      Ident.Local(env.genSym(ind_var.getName()),ind_var.Type());
    ret_body.addIdent(lb_var);
    ret_body.addIdent(ub_var);
    ret_body.addIdent(step_var);

    BasicBlock bb = new BasicBlock();

    // move statement before iter_info into bb
    for(StatementIterator is = b.beginBasicBlock().statements();
	is.hasMoreStatement(); ){
      Statement s = is.nextStatement();
      s.remove();
      if(s == b.iter_info) break;
      bb.add(s);
    }

    bb.add(Xcons.Set(lb_var.Ref(),b.getLowerBound()));
    bb.add(Xcons.Set(ub_var.Ref(),b.getUpperBound()));
    bb.add(Xcons.Set(step_var.Ref(),b.getStep()));

    if(b.isOrdered()){
      bb.add(OMPfuncIdent(orderedInitFunc).
		    Call(Xcons.List(lb_var.Ref(),step_var.Ref())));
      b.getBody().insert(OMPfuncIdent(orderedSetLoopIdFunc).
				 Call(Xcons.List(ind_var)));
    }
    
    Block loop_block = 
      Bcons.FOR(Xcons.Set(ind_var,lb_var.Ref()),
		Xcons.binaryOp(b.getCheckOpcode(),ind_var,ub_var.Ref()),
		Xcons.asgOp(Xcode.ASG_PLUS_EXPR,ind_var,step_var.Ref()),
		Bcons.COMPOUND(b.getBody()));

    /* add pre&end basic block if any */
    if(!b.beginBasicBlock().isEmpty() || !b.endBasicBlock().isEmpty()){
      BlockList body = Bcons.emptyBody();
      body.add(b.beginBasicBlock());
      body.add(loop_block);
      body.add(b.endBasicBlock());
      loop_block = Bcons.COMPOUND(body);
    }

    Xobject sched_chunk = b.getChunk();
    switch(b.getSched()){
    case OMP.SCHED_STATIC:
      if(sched_chunk != null){  /* same as SCHED_NONE */
	if(sched_chunk.Opcode() == Xcode.INT_CONSTANT &&
	   sched_chunk.getInt() == 1){
	  /* cyclic schedule */
	  bb.add(OMPfuncIdent(cyclicShedFunc).
		 Call(Xcons.List(lb_var.getAddr(),ub_var.getAddr(),
				 step_var.getAddr())));
	  break;
	}
	/* otherwise, block scheduling */
	bb.add(OMPfuncIdent(staticShedInitFunc).
	       Call(Xcons.List(lb_var.Ref(),ub_var.Ref(),step_var.Ref(),
			       sched_chunk)));
	if(loop_block.Opcode() != Xcode.FOR_STATEMENT){
	  BlockList body = Bcons.emptyBody();
	  body.add(loop_block.getBody().getHead().remove());
	  body.add(Bcons.WHILE(OMPfuncIdent(staticShedNextFunc).
			       Call(Xcons.List(lb_var.getAddr(),
					       ub_var.getAddr())),
			       loop_block.getBody().getHead().remove()));
	  body.add(loop_block.getBody().getHead().remove());
	  loop_block = Bcons.COMPOUND(body);
	} else 
	  loop_block = Bcons.WHILE(OMPfuncIdent(staticShedNextFunc).
				Call(Xcons.List(lb_var.getAddr(),
						ub_var.getAddr())),
				loop_block);
	break;
      }
      /* fall through */
    case OMP.SCHED_NONE:
      bb.add(OMPfuncIdent(defaultShedFunc).
	     Call(Xcons.List(lb_var.getAddr(),ub_var.getAddr(),
			       step_var.getAddr())));
      break;

    case OMP.SCHED_AFFINITY0:
      Xobject arg = Xcons.List(lb_var.Ref(),ub_var.Ref(),step_var.Ref());
      arg.add(sched_chunk.getArg(0));
      arg.add(sched_chunk.getArg(1));
      arg.add(sched_chunk.getArg(2));
      arg.add(sched_chunk.getArg(3));
      bb.add(OMPfuncIdent(affinityShedInitFunc).Call(arg));
      loop_block = Bcons.WHILE(OMPfuncIdent(affinityShedNextFunc).
			       Call(Xcons.List(lb_var.getAddr(),
					       ub_var.getAddr())),
			       loop_block);
      break;

    case OMP.SCHED_DYNAMIC:
      if(sched_chunk == null) sched_chunk = Xcons.IntConstant(1);
      bb.add(OMPfuncIdent(dynamicShedInitFunc).
	     Call(Xcons.List(lb_var.Ref(),ub_var.Ref(),step_var.Ref(),
			     sched_chunk)));
      loop_block = Bcons.WHILE(OMPfuncIdent(dynamicShedNextFunc).
			       Call(Xcons.List(lb_var.getAddr(),
					       ub_var.getAddr())),
			       loop_block);
      break;
    case OMP.SCHED_GUIDED:
      if(sched_chunk == null) sched_chunk = Xcons.IntConstant(1);
      bb.add(OMPfuncIdent(guidedShedInitFunc).
	     Call(Xcons.List(lb_var.Ref(),ub_var.Ref(),step_var.Ref(),
			     sched_chunk)));
      loop_block = Bcons.WHILE(OMPfuncIdent(guidedShedNextFunc).
			       Call(Xcons.List(lb_var.getAddr(),
					       ub_var.getAddr())),
			       loop_block);
      break;
    case OMP.SCHED_RUNTIME:
      bb.add(OMPfuncIdent(runtimeShedInitFunc).
	     Call(Xcons.List(lb_var.Ref(),ub_var.Ref(),step_var.Ref())));
      loop_block = Bcons.WHILE(OMPfuncIdent(runtimeShedNextFunc).
			       Call(Xcons.List(lb_var.getAddr(),
					       ub_var.getAddr())),
			       loop_block);
      break;
    default:
      OMP.fatal("unknown schedule: "+b.getSched());
    }

    ret_body.add(bb);
    ret_body.add(loop_block);
    return Bcons.COMPOUND(ret_body);
  }

  public Block transSectionsBlock(OMPBlock b){
    Block bp;
    Xobject label = Xcons.Symbol(Xcode.IDENT,env.genSym("L"));
    BlockList ret_body = Bcons.emptyBody();
    BasicBlock bb = b.beginBasicBlock();
    bb.add(OMPfuncIdent(sectionInitFunc).
	   Call(Xcons.List(Xcons.IntConstant(b.getNarg()))));
    ret_body.add(bb);
    ret_body.add(Bcons.LABEL(label));

    BlockList body = Bcons.emptyBody();
    int n = 0;
    while((bp = b.getBody().getHead()) != null){
      bp.remove();
      body.add(Bcons.CASE(Xcons.IntConstant(n++)));
      body.add(bp);
      body.add(Bcons.GOTO(label));
    }
    ret_body.add(Bcons.SWITCH(OMPfuncIdent(sectionIdFunc).Call(null),
			      Bcons.COMPOUND(body)));
    return Bcons.COMPOUND(ret_body);
  }

  public Block transCriticalBlock(OMPBlock b){
    String critical_lock_name = criticalLockPrefix;
    if(b.getInfoExpr() != null) 
      critical_lock_name += "_"+b.getInfoExpr().getName();
    Ident lock_id = 
      env.declGlobalIdent(critical_lock_name,Xtype.Pointer(Xtype.voidType));
    BlockList body = b.getBody();
    body.insert(OMPfuncIdent(enterCriticalFunc).
		Call(Xcons.List(lock_id.getAddr())));
    body.add(OMPfuncIdent(exitCriticalFunc).
	     Call(Xcons.List(lock_id.getAddr())));
    return Bcons.COMPOUND(body);
  }

  public Block transSingleBlock(OMPBlock b){
    BlockList body = Bcons.emptyBody();
    body.add(b.beginBasicBlock());
    body.add(Bcons.IF(BasicBlock.Cond(OMPfuncIdent(doSingleFunc).
				      Call(null)),b.getBody(),null));
    body.add(b.endBasicBlock());
    return Bcons.COMPOUND(body);
  }

  public Block transMasterBlock(OMPBlock b){
    BlockList body = Bcons.emptyBody();
    body.add(b.beginBasicBlock());
    body.add(Bcons.IF(BasicBlock.Cond(OMPfuncIdent(isMasterFunc).
				      Call(null)),b.getBody(),null));
    body.add(b.endBasicBlock());
    return Bcons.COMPOUND(body);
  }

  public Block transOrderedBlock(OMPBlock b){
    BlockList body = b.getBody();
    body.insert(OMPfuncIdent(orderedBeginFunc).Call(null));
    body.insert(b.beginBasicBlock());
    body.add(OMPfuncIdent(orderedEndFunc).Call(null));
    body.add(b.endBasicBlock());
    return Bcons.COMPOUND(body);
  }

  public Block transAtomicBlock(OMPBlock b){
    BlockList body = b.getBody();
    body.insert(OMPfuncIdent(atomicLockFunc).Call(null));
    body.insert(b.beginBasicBlock());
    body.add(OMPfuncIdent(atomicUnlockFunc).Call(null));
    body.add(b.endBasicBlock());
    return Bcons.COMPOUND(body);
  }

  public Block transFlushBlock(OMPBlock b){
    BlockList body = Bcons.emptyBody();
    body.add(b.beginBasicBlock());
    Xobject flush_vars = b.getInfoExpr();
    if(flush_vars == null){
      body.add(Bcons.Statement(OMPfuncIdent(flushFunc).
			       Call(Xcons.List(Xcons.IntConstant(0),
					       Xcons.IntConstant(0)))));
    } else {
      BasicBlock bb = new BasicBlock();
      for(XobjArgs a = flush_vars.getArgs(); a != null; a = a.nextArgs()){
	Xobject v = a.getArg();
	bb.add(OMPfuncIdent(flushFunc). Call(v));
      }
      body.add(bb);
    }
    body.add(b.endBasicBlock());
    return Bcons.COMPOUND(body);
  }

  public Block transBarrierBlock(OMPBlock b){
    BlockList body = Bcons.emptyBody();
    body.add(b.beginBasicBlock());
    body.add(OMPfuncIdent(barrierFunc).Call(null));
    body.add(b.endBasicBlock());
    return Bcons.COMPOUND(body);
  }
}


