------------------------->  GNU Sather - sourcefile  <-------------------------
-- Copyright (C) 199x by International Computer Science Institute            --
-- This file is part of the GNU Sather package. It is free software; you may --
-- redistribute  and/or modify it under the terms of the  GNU General Public --
-- License (GPL)  as  published  by the  Free  Software  Foundation;  either --
-- version 2 of the license, or (at your option) any later version.          --
-- This  program  is distributed  in the  hope that it will  be  useful, but --
-- WITHOUT ANY WARRANTY without even the implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE. See Doc/GPL for more details.        --
-- The license text is also available from:  Free Software Foundation, Inc., --
-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                     --
-------------->  Please email comments to <bug-sather@gnu.org>  <--------------

class OPT_PREFETCH is
   include OPT_HELPER;

   prefetch(func:AM_ROUT_DEF) is
      prefetch_done::=false;
      if void(func.code) or ~cs_options.side_effects then return; end;
      if prog.opt_debug then
	 #OUT+"STARTING PREFETCH FUNCTION on\n";
	 AM_OUT::AM_out(func.code);
	 #OUT+"-----\n";
      end;
      c::=#AM_CURSOR(prog,func.code);
      c.ignore_pre:=true;
      c.ignore_post:=true;
      c.ignore_assert:=true;
      c.assign_in_order:=true;
      specul::=cs_options.specul_prefetch;
      loopp::=cs_options.loop_prefetch;
      if func.sig.is_iter or func.sig.get_se_context(prog).has_raise then
         loopp:=false;
	 specul:=false;
      end;
         
      loop
         am::=c.next!;
	 typecase am 
	 when AM_ROUT_CALL_EXPR then
	    if am.fun.get_se_context(prog).has_import then 
	       if prog.opt_debug then #OUT+"found import for routine "+am.fun.str+"\n"; end;
	       c.mark_stack; end;
	 when AM_ITER_CALL_EXPR then
	    if am.fun.get_se_context(prog).has_import or ~loopp or func.sig.is_iter then c.mark_stack; end;
	 when AM_BREAK_STMT then 	if ~loopp then c.mark_stack; end;
	 when AM_RAISE_STMT then 	if ~specul then c.mark_stack; end;
         when AM_IF_STMT then 		if ~specul then c.mark_stack; end;
         when AM_IF_EXPR then 		if ~specul then c.mark_stack; end;
         when AM_TYPECASE_STMT then	if ~specul then c.mark_stack; end;
         when AM_CASE_STMT then 	if ~specul then c.mark_stack; end;
         when AM_LOCK_STMT then 	if ~specul then c.mark_stack; end;
         when AM_WITH_NEAR_STMT then 	if ~specul then c.mark_stack; end;
	 when AM_RETURN_STMT then 	if ~specul then c.mark_stack; end;
	 when AM_YIELD_STMT then	c.mark_stack;
	 when AM_BND_ROUT_CALL_EXPR then c.mark_stack;
	 when AM_BND_ITER_CALL_EXPR then c.mark_stack;
	 else end;
	 typecase am when AM_ATTR_EXPR then
	    if ~c.is_current_lhs and void(c.prefetch_stmt) and void(c.waitfor_stmt) and ~c.in_iter_init and ~c.has_iter_call(am) then
	       p::=#AM_PREFETCH_STMT(am.source);
	       p.dest:=#AM_LOCAL_EXPR(am.source,void,am.tp);
	       p.prefetch:=#AM_LOCAL_EXPR(am.source,void,TP_BUILTIN::prefetch);
	       p.prefetch.is_volatile:=true;
	       p.comment:="prefetch of expression from "+am.source.str;
	       p.src:=am;
	       if c.insert_after_mark_after_prefetch(p,cs_options.prefetch_weight) then 
		  prog.stat.incr("O: # of prefetch statements");
		  prefetch_done:=true;
		  if prog.opt_debug then 
		     #OUT+"Inserting a prefetch statement for ";
		     AM_OUT::AM_out(am);
		     #OUT+"\n";
		  end;
		  func.locals:=func.locals.push(p.prefetch);
		  t::=p.dest;
		  typecase t when AM_LOCAL_EXPR then
		     func.locals:=func.locals.push(t);
		  end;
		  if void(func.specul_prefetch) and (specul or loopp) then
		     func.specul_prefetch:=#AM_LOCAL_EXPR(am.source,void,TP_BUILTIN::prefetch);
		     if prog.opt_debug then #OUT+"specul_prefetch=";AM_OUT::AM_out(func.specul_prefetch);#OUT+"\n";end;
		     func.specul_prefetch.is_volatile:=true;
		     func.locals:=func.locals.push(func.specul_prefetch);
		  end;
		     
	          w::=#AM_WAITFOR_STMT(am.source);
		  w.prefetch:=p.prefetch;
		  w.src:=p.src;
		  w.dest:=p.dest;
		  e::=#AM_STMT_EXPR(am.source);
		  e.expr:=w.dest;
		  e.stmts:=w;
		  c.replace_expr(e);
		  tam::=c.top;
		  typecase tam when $AM_STMT then func.code:=tam; end;
		  if prog.opt_debug then
		     #OUT+"function code after prefetching:\n";
		     AM_OUT::AM_out(func.code);
		     #OUT+"---\n";
		  end;
	       end;
	    end;
	 else end;
      end;
      tmp::=c.top;
      typecase tmp when $AM_STMT then
	 func.code:=tmp;
      end;
      if prefetch_done then 
	 assert_prefetch_in_order(func); -- call can go away, its just a test.
      end;
      if prog.opt_debug then 
	 #OUT+"PREFETCHING DONE\n";
	 #OUT+"********************************************************\n";
      end;
   end;

   assert_prefetch_in_order(func:AM_ROUT_DEF) is 
      c::=#AM_CURSOR(prog,func.code);
      c.assign_in_order:=true;
      m:FSET{AM_LOCAL_EXPR};
      error::=false;
      loop
	 t::=c.next!;
	 typecase t 
	 when AM_PREFETCH_STMT then
	    m:=m.insert(t.prefetch);
	 when AM_WAITFOR_STMT then
	    if ~m.test(t.prefetch) then
	       #OUT+"waitfor out of sync in func "+func.sig.str+"\n";
	       AM_OUT::AM_out(t);
	       error:=true;
	    end;
	    m:=m.delete(t.prefetch);
	 else end;
      end;
      -- if error then UNIX::exit(1); end;
   end;
end;

-- vim:sw=3:nosmartindent
