// $Id: relocateGlobalData.java,v 1.16 2001/01/09 05:16:42 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 shm;

import exc.object.*;
import exc.block.*;
import exc.openmp.*;
import exc.tea.*;

//
// relocate global data to dynamically allocated in shared memory area
//
public class relocateGlobalData implements XobjectDefVisitor {
  static boolean defaultBlockMap = true;

  final static String relProp = "shm.relocated";
  final static String initProp = "shm.initialized";
  final static String grefProp = "shm.global_reference";

  String dataInitFunc = "_shm_data_init";
  String init_fname = "__G_DATA_INIT";
  String mapInitFunc = "_map_data_init";
  String mapDimFunc = "_map_data_dim";
  String mapDistFunc = "_map_data_dist";
  String mapDistDefaultFunc = "_map_data_dist_default";

  Xobject g_init_decls;

  XobjectFile env;

  public void init(XobjectFile env){
    this.env = env;
    g_init_decls = null;
  }

  public void doDef(XobjectDef d){
    if(d.isFuncDef())
      rewriteGlobalExpr(d);
    else
      d.setDef(removeDecl(d.getDef()));
  }

  Ident init_f;
  Ident initdata_f;
  Ident mapinit_f;
  Ident mapdim_f;
  Ident mapdist_f;
  Ident mapdefault_f;
  Xobject init_func_body;

  void add_init(Ident f,Xobject args){
    init_func_body.add(Xcons.List(Xcode.EXPR_STATEMENT,f.Call(args)));
  }

  boolean isFCommUnion(Ident id){
    return id.Type().isUnion() && id.getName().endsWith("_COMMON");
  }


  // store global initializer
  public void Finalize(){
    MapTemplate tp;

    init_f = env.declStaticIdent(init_fname,Xtype.Function(Xtype.intType));
    initdata_f=env.declExternIdent(dataInitFunc,Xtype.Function(Xtype.intType));
    mapinit_f = env.declExternIdent(mapInitFunc,Xtype.Function(Xtype.intType));
    mapdim_f =  env.declExternIdent(mapDimFunc,Xtype.Function(Xtype.intType));
    mapdist_f = env.declExternIdent(mapDistFunc,Xtype.Function(Xtype.intType));
    mapdefault_f =
      env.declExternIdent(mapDistDefaultFunc,Xtype.Function(Xtype.intType));

    init_func_body = Xcons.List(Xcode.LIST);

    if(g_init_decls != null) env.add(g_init_decls);

    for(XobjArgs a = env.getGlobalIdentList().getArgs();
	a != null; a = a.nextArgs()){
      Ident id = (Ident)(a.getArg());
      if(id.getStorageClass() == StorageClass.EXTERN) continue;
      if(OMP.isThreadPrivate(id)) continue;
      
      relocateIdent(id);	// check and make relocate id
      Ident gid = (Ident)(id.getProp(relProp));
      if(gid == null) continue;
      if(id.getProp(initProp) != null)
	add_init(initdata_f,
		       Xcons.List(gid.getAddr(),
				  Xcons.IntConstant(id.Type().getSize()),
				  id.getAddr()));
      else
	add_init(initdata_f,
		 Xcons.List(gid.getAddr(),
			    Xcons.IntConstant(id.Type().getSize()),
			    Xcons.IntConstant(0)));

      /* check mapping information */
      if(isFCommUnion(id))
	generateFCommMapping(id,gid);
      else if((tp = (MapTemplate)id.getProp(TEA.mapProp)) != null)
	generateMapping(id,gid,tp,Xcons.IntConstant(0));
      else if(defaultBlockMap && id.Type().isArray())
	generateDefaultMapping(id,gid,Xcons.IntConstant(0));
    }
    env.add(XobjectDef.Func(init_fname,null,null,
			    Xcons.List(Xcode.COMPOUND_STATEMENT,
				       (Xobject)null,null,
				       init_func_body)));
  }

  Xobject FCommOffset(Ident id,Ident comm_no_id, Ident comm_id){
    Xobject off = Xcons.Cast(Xtype.Pointer(id.Type()),Xcons.IntConstant(0));
    off = Xcons.memberAddr(Xcons.memberAddr(off,comm_no_id),comm_id);
    return off;
  }
  
  void generateFCommMapping(Ident id, Ident gid){
    MapTemplate tp;
    Xobject mem_list = id.Type().getMemberList();
    if(!mem_list.getArg(0).getName().equals("_0")) return;
    boolean first_common = true;
    for(XobjArgs aa = mem_list.getArgs().nextArgs();
	aa != null; aa = aa.nextArgs()){
      Ident comm_no_id = (Ident)aa.getArg();
      for(XobjArgs a = comm_no_id.Type().getMemberList().getArgs();
	  a!=null; a=a.nextArgs()){
	Ident cid = (Ident)a.getArg();
	if((tp = (MapTemplate)cid.getProp(TEA.mapProp)) != null)
	  generateMapping(cid,gid,tp,FCommOffset(id,comm_no_id,cid));
	else if(first_common && defaultBlockMap && cid.Type().isArray())
	  generateDefaultMapping(cid,gid,FCommOffset(id,comm_no_id,cid));
      }
      first_common = false;
    }
  }

  void generateDefaultMapping(Ident id, Ident gid, Xobject offset){
    add_init(mapdefault_f,
	     Xcons.List(gid.getAddr(),offset,
			Xcons.IntConstant(id.Type().getSize())));
  }

  void generateMapping(Ident id,Ident gid, MapTemplate tp,Xobject off){
    // System.out.println("tp="+tp);
    /* output dimension information */
    Xtype t = id.Type();
    int n = t.getNumDimensions();
    add_init(mapinit_f,
	     Xcons.List(gid.getAddr(),off,
			Xcons.IntConstant(id.Type().getSize()),
			Xcons.IntConstant(n)));
    Xtype at = t;
    for(int i = n; i > 0; i--){
      add_init(mapdim_f,Xcons.List(Xcons.IntConstant(i),
				   Xcons.IntConstant(at.getArrayDim())));
      at = at.getRef();
    }
    add_init(mapdim_f,Xcons.List(Xcons.IntConstant(0),
				 Xcons.IntConstant(at.getSize())));
    tp.Reduce();
    add_init(mapdist_f,Xcons.List(Xcons.IntConstant(tp.getDistDim()+1),
				  Xcons.IntConstant(tp.getMode()),
				  Xcons.IntConstant(tp.getBlockSize()),
				  Xcons.IntConstant(tp.getScale()),
				  Xcons.IntConstant(tp.getOffset())));
  } 

  Xobject removeDecl(Xobject d){
    switch(d.Opcode()){
    case Xcode.LIST:	// check recursively
      Xobject l = Xcons.emptyList();
      for(XobjArgs a = d.getArgs(); a != null; a = a.nextArgs()){
	Xobject dd = removeDecl(a.getArg());
	if(dd != null) l.add(dd);
      }
      return l;
    case Xcode.VAR_DECL:
      Ident id = env.findIdent(d.getArg(0).getName());
      if(OMP.isThreadPrivate(id)) return d;
      if(d.getArg(1) == null) return null;
      id.setProp(initProp,d.getArg(1));
      return d;
    case Xcode.EXT_DECL:  // if external, don't care
    default:
      return d;
    }
  }

  void  checkLocalStaticVar(BlockList body){
    if(body == null) return;
    Xobject id_list = body.getIdentList();
    Xobject decls = body.getDecls();
    if(id_list == null) return;

    for(XobjArgs a = id_list.getArgs(); a != null; a = a.nextArgs()){
      Ident id = (Ident) a.getArg();
      if(id.getStorageClass() == StorageClass.STATIC &&
	 id.getProp(relProp) == null &&
	 !id.Type().isFunction()){
	/* move it to "privatized" global */
	Xtype t = id.Type();
	String name = id.getName();
	String gname = env.genSym("__L_"+name);
	Ident gid = env.declStaticIdent(gname,t);

	/* remove original id */
	id.setStorageClass(StorageClass.SNULL);

	/* check initialization */
	Xobject init_decl = null;
	if(decls != null){
	  for(XobjArgs aa = decls.getArgs(); 
	      aa != null; aa = aa.nextArgs()){
	    Xobject decl = aa.getArg();
	    if(decl.Opcode() == Xcode.VAR_DECL &&
	       name.equals(decl.getArg(0).getName()) &&
	       decl.getArg(1) != null){
		init_decl = decl;
		break;
	    }
	  }
	}

	if(init_decl != null){
	    if(g_init_decls == null) g_init_decls = Xcons.emptyList();
	    Xobject d = Xcons.List(Xcode.VAR_DECL,
				   Xcons.Symbol(Xcode.IDENT,gname),
				   init_decl.getArg(1));
	    g_init_decls.add(d);
	    id.setProp(initProp,init_decl.getArg(1));
	} else {
	    /* remove "privatied" global id */
	    gid.setStorageClass(StorageClass.SNULL);
	}

	Ident rel_id = env.declStaticIdent("__G"+gname,Xtype.Pointer(t));
	id.setProp(relProp,rel_id);
	gid.setProperties(id.getProperties());  // move property
      }
    }
  }

  Block current_block;

  void rewriteGlobalExpr(XobjectDef d){
    FuncDefBlock fd = new FuncDefBlock(d);

    // check local static to relocate "privatized" static in global scope
    for(BlockIterator ii = new topdownBlockIterator(fd.getBlock());
	!ii.end(); ii.next()){
      current_block = ii.getBlock();
      checkLocalStaticVar(current_block.getParent());
      rewriteExpr(current_block.getInfoExpr());
    }

    // relocate Variable in statements
    for(BasicBlockExprIterator i = new BasicBlockExprIterator(fd.getBlock());
	!i.end(); i.next()){
      current_block = i.getBasicBlock().getParent();
      i.setExpr(rewriteExpr(i.getExpr()));
    }
  }

  Xobject rewriteExpr(Xobject e){
    Ident id;
    if(e == null) return null;
    // System.out.println("rewriteGlobalExpr:"+e);
    XobjectIterator i = new bottomupXobjectIterator(e);
    for(i.init();!i.end(); i.next()){
      Xobject x = i.getXobject();
      if(x == null) continue;
      switch(x.Opcode()){
      case Xcode.VAR:
      case Xcode.VAR_ADDR:
      case Xcode.ARRAY_ADDR:
	id = current_block.findIdent(x.getName());
	if(id == null || id.getProp(grefProp) != null) break;
	if(OMP.isThreadPrivate(id)) break;
	if(x.Opcode() == Xcode.VAR)
	    i.setXobject(Xcons.PointerRef(relocateIdent(id).Ref()));
	else
	    i.setXobject(relocateIdent(id).Ref());
	break;
      case Xcode.FCOMM_VAR:
      case Xcode.FCOMM_ARRAY_ADDR:
      case Xcode.FCOMM_VAR_ADDR:
	x = x.getArg(1);
	if(x.getArg(0).Opcode() != Xcode.IDENT) break;
	id = env.findIdent(x.getArg(0).getName());
	if(id == null) break;
	if(OMP.isThreadPrivate(id)) break;
	x.setArg(0,Xcons.PointerRef(relocateIdent(id).Ref()));
      }
    }
    return i.topXobject();
  }
  
  Ident relocateIdent(Ident id){
    Ident rel_id = (Ident)(id.getProp(relProp));
    if(rel_id != null) return rel_id;  // found
    Xtype t = id.Type();
    if(t.isFunction()) return id;
    else t = Xtype.Pointer(t);
    String name = id.getName();
    if(name == null) return id;
    if(name.startsWith("__G_")) return id; // don't relcate relcate it
    switch(id.getStorageClass()){
    case StorageClass.EXTERN:
      rel_id = env.declExternIdent("__G_"+name,t);
      break;
    case StorageClass.EXTDEF:
      rel_id = env.declGlobalIdent("__G_"+name,t);
      break;
    case StorageClass.STATIC:
      rel_id = env.declStaticIdent("__G_"+name,t);
      break;
    default:
      return id;
    }
    id.setProp(relProp,rel_id);
    rel_id.setProp(grefProp,id);
    return rel_id;
  }
}


