------------------------->  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 CSE_DOUBLE_EXPRS < $HASH is
   include COMPARABLE;
   readonly attr expr:FLIST{$AM_EXPR};
   readonly attr pos:FLIST{AM_CURSOR};
   readonly attr locals:FLIST{AM_LOCAL_EXPR};

   create(e:$AM_EXPR,c:AM_CURSOR):SAME is 
      r::=new;
      r.expr:=r.expr.push(e);
      r.pos:=r.pos.push(#(c));
      r.locals:=r.locals.push(void);
      return r;
   end;

   add_loc(e:$AM_EXPR,c:AM_CURSOR) is
      expr:=expr.push(e);
      pos:=pos.push(#(c));
      locals:=locals.push(void);
   end;

   hash:INT is return expr[0].hash; end;
   is_eq(e:CSE_DOUBLE_EXPRS):BOOL is return expr[0] = e.expr[0]; end;
end;

class OPT_CSE is
   include OPT_HELPER;

   remove_cse(func:AM_ROUT_DEF) is
      c::=#AM_CURSOR(prog,func.code);
      c.ignore_pre:=true;
      c.ignore_post:=true;
      c.ignore_assert:=true;
      c.assign_in_order:=true;
      exprs:FSET{CSE_DOUBLE_EXPRS};
      replacements:FLIST{TUP{AM_CURSOR,$AM_EXPR,$AM_STMT}};
      found_double::=false;

      loop
--	 if prog.opt_debug then
--	    #OUT+"O:CSE: current C: "+c.str;
--	 end;
         am::=c.next!;
--#	 if prog.opt_debug then
--#	    #OUT+"O_CSE: "+SYS::str_for_tp(SYS::tp(am))+"\n";
--#	    #OUT+"current C: "+c.str;
--#	 end;
	 typecase am
	 -- some expressions are never replaced with locals
	 when AM_LOCAL_EXPR then 
	 when AM_SHARED_EXPR then 
	 when AM_CLUSTER_EXPR then 
	 when AM_HERE_EXPR then 
	 when $AM_CONST then 
	 when $AM_EXPR then
	    if ~void(am.tp) and ~c.is_lhs_of_at_expr then
	       e:CSE_DOUBLE_EXPRS:=#(am,c);
	       ee::=exprs.get(e);
	       if void(ee) or c.is_current_lhs then
		  exprs:=exprs.insert(e);
--		  if prog.opt_debug then
--		     #OUT+"inserting into CSE stack: ";AM_OUT::AM_out(am);#OUT+"\n";
--		  end;
	       else
		  e:=ee;
		  done::=false;
		  loop
		     i::=e.pos.ind!;
		     if SYS::id(e.expr[i])/=SYS::id(am) and
		       c.is_exec_after_and_const_from_there(e.pos[i],am) then
			if void(e.locals[i]) then
			   e.locals[i]:=new_local(func,am.tp,am.source);
			   as::=#AM_ASSIGN_STMT(e.locals[i].source);
			   if e.pos[i].is_current_lhs then
			      as.dest:=e.expr[i];
			      as.src:=e.locals[i];
			      replacements:=replacements.push(#TUP{AM_CURSOR,$AM_EXPR,$AM_STMT}(e.pos[i],e.locals[i],as));
--			      if prog.opt_debug then
--				 #OUT+"replacing  ";
--				 AM_OUT::AM_out(am);
--				 #OUT+"  with ";AM_OUT::AM_out(e.locals[i]);
--				 #OUT+"  adding\n";AM_OUT::AM_out(as);
--			      end;
			   else
			      as.dest:=e.locals[i];
			      as.src:=e.expr[i];
			      st::=#AM_STMT_EXPR(e.locals[i].source);
			      st.stmts:=as;
			      st.expr:=e.locals[i];
			      replacements:=replacements.push(#TUP{AM_CURSOR,$AM_EXPR,$AM_STMT}(e.pos[i],st,void));
--			      if prog.opt_debug then
--				 #OUT+"replacing  ";
--				 AM_OUT::AM_out(am);
--				 #OUT+"  with ";AM_OUT::AM_out(e.locals[i]);
--				 #OUT+"\n";
--			      end;
			   end;
			end;
			prog.stat.incr("O: # of cse");
			replacements:=replacements.push(#TUP{AM_CURSOR,$AM_EXPR,$AM_STMT}(#(c),e.locals[i],void));
			done:=true;
			break!;
		     end;
		  end;
		  if ~done then
--		     if prog.opt_debug then #OUT+"add_loc CSE stack: ";AM_OUT::AM_out(am);#OUT+"\n"; end;
		     e.add_loc(am,c);
		  end;
	       end;
	    end;
	 else
	 end;
      end;
      if ~void(replacements) then
	 loop
	    tp::=replacements.elt!;
--	    if prog.opt_debug then
--	       #OUT+"replacing (lhs="+tp.t1.is_current_lhs+"):";
--	       AM_OUT::AM_out(tp.t1.cur);
--	       #OUT+"\nwith: ";
--	       AM_OUT::AM_out(tp.t2);
--	       #OUT+"\n";
--	    end;
	    assert(~void(tp.t2));
	    tp.t1.replace_expr(tp.t2);
	    if ~void(tp.t3) then
	       tp.t1.surr_stmt;
	       cur::=tp.t1.cur;
	       typecase cur when $AM_STMT then
	          tp.t3.next:=cur.next;
		  cur.next:=tp.t3;
	       end;
	    end;
	 end;
	 SYS::destroy(replacements);
      end;
      if ~void(exprs) then SYS::destroy(exprs); end;
   end;
end;

-- vim:sw=3:nosmartindent
