optimize.sa


Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
 
---------------------------> Sather 1.1 source file <--------------------------
-- Copyright (C) International Computer Science Institute, 1995.  COPYRIGHT  --
-- NOTICE: This code is provided "AS IS" WITHOUT ANY WARRANTY and is subject --
-- to the terms of the SATHER LIBRARY GENERAL PUBLIC LICENSE contained in    --
-- the file "Doc/License" of the Sather distribution.  The license is also   --
-- available from ICSI, 1947 Center St., Suite 600, Berkeley CA 94704, USA.  --
--------> Please email comments to sather-bugs@icsi.berkeley.edu. <----------


class EXPR_HOISTED

class EXPR_HOISTED is -- helper class to hoist expressions out of loops attr expr:$AM_EXPR; attr is_safe:BOOL; -- true if expr has only safe attr expressions attr local:AM_LOCAL_EXPR; -- local used to store the hoisted expression create(e:$AM_EXPR,s:BOOL,l:AM_LOCAL_EXPR):SAME is r::=new; r.expr:=e;-- EXPR_HOISTED::expr r.is_safe:=s;-- EXPR_HOISTED::is_safe r.local:=l;-- EXPR_HOISTED::local return r; end; end;

class OPT_CONSTANTS

class OPT_CONSTANTS is shared prog:PROG; shared tp_int:$TP; shared tp_bool:$TP; shared tp_char:$TP; shared zero:AM_INT_CONST; shared one:AM_INT_CONST; shared two:AM_INT_CONST; shared m_one:AM_INT_CONST; shared m_two:AM_INT_CONST; shared cs_options:CS_OPTIONS; end;

class OPT_HELPER

class OPT_HELPER is prog:PROG is return OPT_CONSTANTS::prog ; end;-- OPT_CONSTANTS::prog tp_int:$TP is return OPT_CONSTANTS::tp_int ; end;-- OPT_CONSTANTS::tp_int tp_bool:$TP is return OPT_CONSTANTS::tp_bool ; end; tp_char:$TP is return OPT_CONSTANTS::tp_char ; end; zero:AM_INT_CONST is return OPT_CONSTANTS::zero ; end;-- OPT_CONSTANTS::zero one:AM_INT_CONST is return OPT_CONSTANTS::one ; end;-- OPT_CONSTANTS::one two:AM_INT_CONST is return OPT_CONSTANTS::two ; end; m_one:AM_INT_CONST is return OPT_CONSTANTS::m_one ; end; m_two:AM_INT_CONST is return OPT_CONSTANTS::m_two ; end; cs_options:CS_OPTIONS is return OPT_CONSTANTS::cs_options ; end;-- OPT_CONSTANTS::cs_options private has_no_iter(am:$AM):BOOL is c::=#AM_CURSOR(prog,am);-- AM_CURSOR::create OPT_CONST::prog c.ignore_pre:=true;-- AM_CURSOR::ignore_pre c.ignore_post:=true;-- AM_CURSOR::ignore_post c.ignore_assert:=true;-- AM_CURSOR::ignore_assert loop a::=c.next!;-- AM_CURSOR::next! typecase a when AM_ITER_CALL_EXPR then return false; else end; end; return true; end; private has_attr_expr(am:$AM):BOOL is c::=#AM_CURSOR(prog,am);-- AM_CURSOR::create OPT_CONST::prog c.ignore_pre:=true;-- AM_CURSOR::ignore_pre c.ignore_post:=true;-- AM_CURSOR::ignore_post c.ignore_assert:=true;-- AM_CURSOR::ignore_assert loop a::=c.next!;-- AM_CURSOR::next! typecase a when AM_ATTR_EXPR then return true; else end; end; return false; end; -- check if the given AM_EXPR, which is a destination in an -- assignment, may be moved to the beginning of the loop. private hoistable_dest(desta:AM_ASSIGN_STMT,c:AM_CURSOR,need_safe_attr:BOOL,in_conditional:BOOL):BOOL is dest::=desta.dest;-- AM_ASSIGN_STMT::dest if in_conditional then return false; else -- we have to hide the dest. in this assignment desta.dest:=void;-- AM_ASSIGN_STMT::dest r::=c.is_const_in_loop(dest) and c.is_not_used_in_loop_before_eval_cur_expr(dest);-- AM_CURSOR::is_const_in_loop AM_CURSOR::is_not_used_in_loop_before_eval_cur_expr desta.dest:=dest;-- AM_ASSIGN_STMT::dest if r and need_safe_attr then -- this means, that there could be a break! -- before executing this assignment, therefore -- we have to be sure that the early assignment -- is not visible outside the loop. typecase dest when AM_LOCAL_EXPR then return c.is_not_used_outside_innermost_loop(dest);-- AM_CURSOR::is_not_used_outside_innermost_loop else return false; end; end; return r; end; end; -- check if the given AM_EXPR may be moved to the beginning of the loop. private hoistable(src:$AM_EXPR,c:AM_CURSOR,need_safe_attr:BOOL,in_conditional:BOOL):BOOL is if c.is_current_lhs then return false; end;-- AM_CURSOR::is_current_lhs if in_conditional then return c.is_non_fatal_and_const_in_loop(src);-- AM_CURSOR::is_non_fatal_and_const_in_loop else if need_safe_attr then return c.is_non_fatal_and_const_in_loop(src);-- AM_CURSOR::is_non_fatal_and_const_in_loop else return c.is_const_in_loop(src);-- AM_CURSOR::is_const_in_loop end; end; end; -- check if the given AM_EXPR, which is a destination in an -- assignment, may be moved to the beginning of the loop. The function -- assumes that the code will only be executed once as an initialization for -- an iter. private hoistable_init_dest(dest:$AM_EXPR,c:AM_CURSOR,need_safe_attr:BOOL,in_conditional:BOOL):BOOL is if in_conditional then return false; else if c.is_not_used_in_loop_before_eval_cur_expr(dest) then-- AM_CURSOR::is_not_used_in_loop_before_eval_cur_expr if need_safe_attr then -- this means, that there could be a break! -- before executing this assignment, therefore -- we have to be sure that the early assignment -- is not visible outside the loop. typecase dest when AM_LOCAL_EXPR then return c.is_not_used_outside_innermost_loop(dest);-- AM_CURSOR::is_not_used_outside_innermost_loop else return false; end; else return c.is_const_in_loop_before_eval_cur_expr(dest);-- AM_CURSOR::is_const_in_loop_before_eval_cur_expr end; else return false; end; end; end; -- check if the given AM_EXPR may be moved to the beginning of the loop. The -- function assumes that the code will only be executed once as an -- initialization for an iter. private hoistable_init(src:$AM_EXPR,c:AM_CURSOR,need_safe_attr:BOOL,in_conditional:BOOL):BOOL is if in_conditional then return c.is_non_fatal_and_const_in_loop(src);-- AM_CURSOR::is_non_fatal_and_const_in_loop else if need_safe_attr then return c.is_non_fatal_and_const_in_loop_before_eval_cur_expr(src);-- AM_CURSOR::is_non_fatal_and_const_in_loop_before_eval_cur_expr else return c.is_const_in_loop_before_eval_cur_expr(src);-- AM_CURSOR::is_const_in_loop_before_eval_cur_expr end; end; end; make_sure_emitted(s:SIG) is cgen::=prog.back_end;-- OPTIMIZE::prog PROG::back_end typecase cgen when CGEN then cgen.make_sure_emitted(s);-- CGEN::make_sure_emitted end; end; check_leftover_functions(am:$AM_EXPR) is c::=#AM_CURSOR(prog,am);-- AM_CURSOR::create OPTIMIZE::prog loop a::=c.next!;-- AM_CURSOR::next! typecase a when AM_ITER_CALL_EXPR then make_sure_emitted(a.fun);-- OPTIMIZE::make_sure_emitted AM_ITER_CALL_EXPR::fun when AM_ROUT_CALL_EXPR then make_sure_emitted(a.fun);-- OPTIMIZE::make_sure_emitted AM_ROUT_CALL_EXPR::fun else end; end; end; new_local(func:AM_ROUT_DEF,tp:$TP,source:SFILE_ID):AM_LOCAL_EXPR is lc::=#AM_LOCAL_EXPR(source,void,tp);-- AM_LOCAL_EXPR::create func.locals:=func.locals.push(lc);-- AM_ROUT_DEF::locals AM_ROUT_DEF::locals FLIST{1}::push return lc; end; new_local(func:AM_ROUT_DEF,tp:$TP):AM_LOCAL_EXPR is lc::=#AM_LOCAL_EXPR(func.code.source,void,tp);-- AM_LOCAL_EXPR::create AM_ROUT_DEF::code func.locals:=func.locals.push(lc);-- AM_ROUT_DEF::locals AM_ROUT_DEF::locals FLIST{1}::push return lc; end; is_local(am:$AM):BOOL is typecase am when AM_LOCAL_EXPR then return true; else end; return false; end; private make_unsafe_attr(a:$AM) is c::=#AM_CURSOR(prog,a);-- AM_CURSOR::create OPT_CONST::prog loop am::=c.next!;-- AM_CURSOR::next! typecase am when AM_ATTR_EXPR then am.secure:=false;-- AM_ATTR_EXPR::secure else end; end; end; private make_safe_attr(a:$AM) is c::=#AM_CURSOR(prog,a);-- AM_CURSOR::create OPT_CONST::prog loop am::=c.next!;-- AM_CURSOR::next! typecase am when AM_ATTR_EXPR then am.secure:=true;-- AM_ATTR_EXPR::secure else end; end; end; private move_init_stmts(func:AM_ROUT_DEF,am:AM_ITER_CALL_EXPR,c:AM_CURSOR) is prog.stat.incr("O: # of initializations of iters moved outside the loop");-- OPT_ITER::prog PROG::stat if ~func.is_iter then -- if we are not in an iter we can safely move the initialization-- AM_ROUT_DEF::is_iter BOOL::not -- out of the loop. We do this to allow const_hoisting of those -- expression out of a possible existing outer loop c.insert_in_loop_init(am.init);-- AM_CURSOR::insert_in_loop_init AM_ITER_CALL_EXPR::init am.init:=void;-- AM_ITER_CALL_EXPR::init am.init_before_loop:=true;-- AM_ITER_CALL_EXPR::init_before_loop end; end; private inline_func(func:AM_ROUT_DEF,am:AM_ROUT_CALL_EXPR,c:AM_CURSOR):BOOL is if ~prog.inline_routs then return false; end;-- OPTIMIZE::prog PROG::inline_routs BOOL::not if c.is_lhs_of_at_expr then-- AM_CURSOR::is_lhs_of_at_expr make_sure_emitted(am.fun);-- OPTIMIZE::make_sure_emitted AM_ROUT_CALL_EXPR::fun return false; end; ok::=false; if prog.opt_debug then -- OPTIMIZE::prog PROG::opt_debug #OUT+"Trying to inline the func call " + -- OUT::create OUT::plus am.fun.str+":";-- OUT::plus AM_ROUT_CALL_EXPR::fun SIG::str OUT::plus end; n::=prog.inliner.general_inline(func,am);-- OPTIMIZE::prog PROG::inliner if ~SYS::ob_eq(n,am) then-- SYS::ob_eq BOOL::not prog.stat.incr("O: # of func calls inlined");-- OPTIMIZE::prog PROG::stat if prog.opt_debug then -- OPTIMIZE::prog PROG::opt_debug #OUT+" done\n";-- OUT::create OUT::plus end; typecase n when AM_STMT_EXPR then n.replaced:=am;-- AM_STMT_EXPR::replaced else #ERR+"huch, inlined should only return a AM_STMT_EXPR?\n";-- ERR::create ERR::plus end; c.replace_expr(n);-- AM_CURSOR::replace_expr ok:=true; else if prog.opt_debug then-- OPTIMIZE::prog PROG::opt_debug #OUT+"no way\n";-- OUT::create OUT::plus end; end; return ok; end; end;

class OPTIMIZE < $OPTIMIZE

class OPTIMIZE < $OPTIMIZE is -- This optimizer moves as many expressions as possible out of loops. An expression -- is movable if it is either -- * a constant -- * a constant from the beginning of the loop to its first call -- and it is not in a conditional expression. We have to check two cases: -- if it is possible that the expression is never evaluated, because the loop -- terminates early (iter call, return, raise), we have to make sure that -- during the evaluation of the code there is no fatal error. Hence we -- move only local, global and attr expressions out of the loop. Attr expressions -- are guarded against void accesses. -- * if the code is in a conditional expression, we check that all it consists only of -- local, global or attr expressions that are constant during the whole loop -- Attr expressions have to be guarded against void accesses. -- NOTE: if an attr expression is guarded against void accesses, the program -- will not stop with an "void access" but silently continue. Therefore -- you should not use -O if you need to check all accesses. include OPT_HELPER; create(p:PROG):SAME is r::=new; OPT_CONSTANTS::prog:=p;-- OPT_CONSTANTS::prog OPT_CONSTANTS::tp_int:=TP_BUILTIN::int;-- OPT_CONSTANTS::tp_int TP_BUILTIN::int OPT_CONSTANTS::tp_bool:=TP_BUILTIN::bool;-- OPT_CONSTANTS::tp_bool TP_BUILTIN::bool OPT_CONSTANTS::tp_char:=TP_BUILTIN::char;-- OPT_CONSTANTS::tp_char TP_BUILTIN::char asint ::= #AS_INT_LIT_EXPR;-- AS_INT_LIT_EXPR::create asint.val := #INTI(0);-- AS_INT_LIT_EXPR::val INTI::create OPT_CONSTANTS::zero:=#AM_INT_CONST(asint);-- OPT_CONSTANTS::zero AM_INT_CONST::create OPT_CONSTANTS::zero.tp_at:=r.tp_int; -- OPT_CONSTANTS::zero AM_INT_CONST::tp_at OPTIMIZE::tp_int asint := #AS_INT_LIT_EXPR;-- AS_INT_LIT_EXPR::create asint.val := #INTI(1);-- AS_INT_LIT_EXPR::val INTI::create OPT_CONSTANTS::one:=#AM_INT_CONST(asint);-- OPT_CONSTANTS::one AM_INT_CONST::create OPT_CONSTANTS::one.tp_at:=r.tp_int; -- OPT_CONSTANTS::one AM_INT_CONST::tp_at OPTIMIZE::tp_int asint := #AS_INT_LIT_EXPR;-- AS_INT_LIT_EXPR::create asint.val := #INTI(2);-- AS_INT_LIT_EXPR::val INTI::create OPT_CONSTANTS::two:=#AM_INT_CONST(asint);-- OPT_CONSTANTS::two AM_INT_CONST::create OPT_CONSTANTS::two.tp_at:=r.tp_int; -- OPT_CONSTANTS::two AM_INT_CONST::tp_at OPTIMIZE::tp_int asint := #AS_INT_LIT_EXPR;-- AS_INT_LIT_EXPR::create asint.val := #INTI(-1);-- AS_INT_LIT_EXPR::val INTI::create OPT_CONSTANTS::m_one:=#AM_INT_CONST(asint);-- OPT_CONSTANTS::m_one AM_INT_CONST::create OPT_CONSTANTS::m_one.tp_at:=r.tp_int; -- OPT_CONSTANTS::m_one AM_INT_CONST::tp_at OPTIMIZE::tp_int asint := #AS_INT_LIT_EXPR;-- AS_INT_LIT_EXPR::create asint.val := #INTI(-2);-- AS_INT_LIT_EXPR::val INTI::create OPT_CONSTANTS::m_two:=#AM_INT_CONST(asint);-- OPT_CONSTANTS::m_two AM_INT_CONST::create OPT_CONSTANTS::m_two.tp_at:=r.tp_int; -- OPT_CONSTANTS::m_two AM_INT_CONST::tp_at OPTIMIZE::tp_int return r; end; init is prog.back_end.init;-- OPTIMIZE::prog PROG::back_end -- extract the typesafe options from the program temp::=prog.get_options;-- OPTIMIZE::prog PROG::get_options typecase temp when CS_OPTIONS then OPT_CONSTANTS::cs_options := temp;-- OPT_CONSTANTS::cs_options end; end; -- set the is_hot attr of AM_LOCAL_EXPR mark_hot_args(func:AM_ROUT_DEF) is if void(func.sig.hot) then return; end; loop i::=func.ind!; if i>0 then -- ignore self if func.sig.hot[i-1] then -- self is not included in sig func[i].expr.is_hot:=true; end; end; end; end; do_loop_opt(func:AM_ROUT_DEF) is -- if func.sig.is_iter then mark_hot_args(func); end; -- unfortunatly it is very hard to do any optimizations within iters. -- The problem is that it not possible to move code or evaluate -- expressions before or after the yield statement where they were. -- It is for example impossible to move the expression 'a*b' out -- of a loop, as you don't know if the caller may change it or not: -- loop yield 1.up!*a*b; end; -- This assumes that either a or b are attributes, and not locals -- of course. As it seems not worth the trouble, iters are not -- optimized at all (but we do inlining in iters, of course); has_locks::=false; after_loop_break:ARRAY{BOOL}:=#(30); -- not more than 30 loop recursions-- ARRAY{1}::create if ~func.is_iter and (prog.hoist_const or prog.move_while) then OPT_CONST::const_hoisting(func,1); end;-- AM_ROUT_DEF::is_iter BOOL::not OPTIMIZE::prog PROG::hoist_const OPTIMIZE::prog PROG::move_while OPT_CONST::const_hoisting c::=#AM_CURSOR(prog,func.code);-- AM_CURSOR::create OPTIMIZE::prog AM_ROUT_DEF::code c.ignore_pre:=true;-- AM_CURSOR::ignore_pre c.ignore_post:=true;-- AM_CURSOR::ignore_post c.ignore_assert:=true;-- AM_CURSOR::ignore_assert loop am::=c.next!;-- AM_CURSOR::next! typecase am when AM_PRE_STMT then -- PRE, POST, ASSERT are not inlined, therefore we have to be sure that -- all functions are emitted. check_leftover_functions(am.test);-- OPTIMIZE::check_leftover_functions AM_PRE_STMT::test when AM_POST_STMT then check_leftover_functions(am.test);-- OPTIMIZE::check_leftover_functions AM_POST_STMT::test when AM_ASSERT_STMT then check_leftover_functions(am.test);-- OPTIMIZE::check_leftover_functions AM_ASSERT_STMT::test when AM_ATTACH_STMT then make_sure_emitted(am.rout);-- OPTIMIZE::make_sure_emitted AM_ATTACH_STMT::rout when AM_LOOP_STMT then am.no_begin_loop:=cs_options.side_effects;-- AM_LOOP_STMT::no_begin_loop OPTIMIZE::cs_options CS_OPTIONS::side_effects after_loop_break[c.loops+1]:=false;-- ARRAY{1}::aset AM_CURSOR::loops INT::plus when AM_YIELD_STMT then if has_locks then l::=c.lock_stmt;-- AM_CURSOR::lock_stmt if ~void(l) then l.manual_unlock:=false; end;-- BOOL::not AM_LOCK_STMT::manual_unlock end; after_loop_break[c.loops]:=true;-- ARRAY{1}::aset AM_CURSOR::loops when AM_RAISE_STMT then if has_locks then l::=c.lock_stmt;-- AM_CURSOR::lock_stmt if ~void(l) then l.manual_unlock:=false; end;-- BOOL::not AM_LOCK_STMT::manual_unlock end; after_loop_break[c.loops]:=true;-- ARRAY{1}::aset AM_CURSOR::loops when AM_BREAK_STMT then c.loop_stmt.breaks:=c.loop_stmt.breaks+1;-- AM_CURSOR::loop_stmt AM_LOOP_STMT::breaks AM_CURSOR::loop_stmt AM_LOOP_STMT::breaks INT::plus after_loop_break[c.loops]:=true;-- ARRAY{1}::aset AM_CURSOR::loops when AM_RETURN_STMT then after_loop_break[c.loops]:=true;-- ARRAY{1}::aset AM_CURSOR::loops when AM_BND_ROUT_CALL_EXPR then if prog.psather and has_locks and cs_options.side_effects then-- OPTIMIZE::prog PROG::psather OPTIMIZE::cs_options CS_OPTIONS::side_effects l::=c.lock_stmt;-- AM_CURSOR::lock_stmt if ~void(l) then l.manual_unlock:=false; end;-- BOOL::not AM_LOCK_STMT::manual_unlock end; when AM_ROUT_CALL_EXPR then if cs_options.side_effects and prog.psather and has_locks then-- OPTIMIZE::cs_options CS_OPTIONS::side_effects OPTIMIZE::prog PROG::psather l::=c.lock_stmt;-- AM_CURSOR::lock_stmt if ~void(l) then-- BOOL::not con::=am.fun.get_se_context(prog);-- AM_ROUT_CALL_EXPR::fun SIG::get_se_context OPTIMIZE::prog if con.has_raise then l.manual_unlock:=false; end;-- SE_CONTEXT::has_raise AM_LOCK_STMT::manual_unlock end; end; if ~inline_func(func,am,c) then-- OPTIMIZE::inline_func BOOL::not -- there could be a raise in this routine cal. If we are unable to -- know this (because we compile without side effects), we assume -- the worst. We only need to check that if we don't inline the call -- of course. after_loop_break[c.loops]:=after_loop_break[c.loops] -- ARRAY{1}::aset AM_CURSOR::loops ARRAY{1}::aget AM_CURSOR::loops or ~c.with_side_effects or (~void(am.fun.get_se_context(prog)) and am.fun.get_se_context(prog).has_raise);-- AM_CURSOR::with_side_effects BOOL::not AM_ROUT_CALL_EXPR::fun SIG::get_se_context OPTIMIZE::prog BOOL::not AM_ROUT_CALL_EXPR::fun SIG::get_se_context OPTIMIZE::prog SE_CONTEXT::has_raise end; when AM_BND_ITER_CALL_EXPR then if prog.psather and has_locks and cs_options.side_effects then-- OPTIMIZE::prog PROG::psather OPTIMIZE::cs_options CS_OPTIONS::side_effects l::=c.lock_stmt;-- AM_CURSOR::lock_stmt if ~void(l) then l.manual_unlock:=false; end;-- BOOL::not AM_LOCK_STMT::manual_unlock end; am.lp.no_begin_loop:=false;-- AM_BND_ITER_CALL_EXPR::lp AM_LOOP_STMT::no_begin_loop when AM_ITER_CALL_EXPR then if cs_options.side_effects then-- OPTIMIZE::cs_options CS_OPTIONS::side_effects con::=am.fun.get_se_context(prog);-- AM_ITER_CALL_EXPR::fun SIG::get_se_context OPTIMIZE::prog if prog.psather and has_locks then-- OPTIMIZE::prog PROG::psather l::=c.loop_or_lock_stmt;-- AM_CURSOR::loop_or_lock_stmt if ~void(l) then-- BOOL::not typecase l when AM_LOCK_STMT then if con.has_raise then l.manual_unlock:=false; end;-- SE_CONTEXT::has_raise AM_LOCK_STMT::manual_unlock else end; end; end; if con.has_yield_in_lock then-- SE_CONTEXT::has_yield_in_lock am.lp.no_begin_loop:=false;-- AM_ITER_CALL_EXPR::lp AM_LOOP_STMT::no_begin_loop end; end; OPT_ITER::work_on_iter(func,am,c,after_loop_break);-- OPT_ITER::work_on_iter after_loop_break[c.loops]:=true;-- ARRAY{1}::aset AM_CURSOR::loops when AM_LOCK_STMT then if prog.locks_on_stack then-- OPTIMIZE::prog PROG::locks_on_stack if has_locks then l::=c.lock_stmt; -- returns the enclosing lock, if it exists-- AM_CURSOR::lock_stmt if ~void(l) then l.manual_unlock:=false; end;-- BOOL::not AM_LOCK_STMT::manual_unlock end; am.manual_unlock:=cs_options.side_effects;-- AM_LOCK_STMT::manual_unlock OPTIMIZE::cs_options CS_OPTIONS::side_effects has_locks:=true; end; when AM_UNLOCK_STMT then l::=c.lock_stmt;-- AM_CURSOR::lock_stmt assert(~void(l)); -- there has to be a lock stmt-- BOOL::not l.manual_unlock:=false;-- AM_LOCK_STMT::manual_unlock else end; end; if ~void(c.top) then -- there may be some new statements at the beginning,-- AM_CURSOR::top BOOL::not -- so we have to adjust func.code. tam::=c.top;-- AM_CURSOR::top typecase tam when $AM_STMT then func.code:=tam; end;-- AM_ROUT_DEF::code end; -- after inlining we may find some more loop constants to hoist if ~func.is_iter and (prog.hoist_const or prog.move_while) then -- AM_ROUT_DEF::is_iter BOOL::not OPTIMIZE::prog PROG::hoist_const OPTIMIZE::prog PROG::move_while loop if prog.opt_debug then #OUT+"HOISTING\n"; end;-- OPTIMIZE::prog PROG::opt_debug OUT::create OUT::plus while!(OPT_CONST::const_hoisting(func,2.upto!(10))); -- OPT_CONST::const_hoisting INT::upto! if prog.opt_debug then #OUT+"AFTER HOISTING\n";-- OPTIMIZE::prog PROG::opt_debug OUT::create OUT::plus AM_OUT::AM_out(func.code);-- AM_OUT::AM_out AM_ROUT_DEF::code end; end; end; end; optimize(func:AM_ROUT_DEF) is if prog.opt_verbose then-- OPTIMIZE::prog PROG::opt_verbose #OUT+"working on "+func.sig.str+"\n";-- OUT::create OUT::plus OUT::plus AM_ROUT_DEF::sig SIG::str OUT::plus end; if ~void(prog.opt_debug_func) then-- OPTIMIZE::prog PROG::opt_debug_func BOOL::not prog.opt_debug:=false;-- OPTIMIZE::prog PROG::opt_debug loop if func.sig.str.search(prog.opt_debug_func.elt!)>=0 then-- AM_ROUT_DEF::sig SIG::str STR::search OPTIMIZE::prog PROG::opt_debug_func FLIST{1}::elt! INT::is_lt BOOL::not prog.opt_debug:=true;-- OPTIMIZE::prog PROG::opt_debug break!; end; end; end; if prog.opt_debug then -- or func.sig.str="TRANS::last_declared_helper:AM_LOCAL_EXPR" then-- OPTIMIZE::prog PROG::opt_debug #OUT+"Optimizing function "+func.sig.str;-- OUT::create OUT::plus OUT::plus AM_ROUT_DEF::sig SIG::str if ~void(func.srcsig) then-- AM_ROUT_DEF::srcsig BOOL::not #OUT+" "+func.srcsig.str;-- OUT::create OUT::plus OUT::plus AM_ROUT_DEF::srcsig SIG::str end; #OUT+"\n";-- OUT::create OUT::plus #OUT+"non optimized code {\n";-- OUT::create OUT::plus am::=func.code;-- AM_ROUT_DEF::code AM_OUT::AM_out(am);-- AM_OUT::AM_out #OUT+"}\n";-- OUT::create OUT::plus c::=#AM_CURSOR(prog,func.code);-- AM_CURSOR::create OPTIMIZE::prog AM_ROUT_DEF::code c.test_am_cursor;-- AM_CURSOR::test_am_cursor end; if cs_options.cse and cs_options.side_effects-- OPTIMIZE::cs_options CS_OPTIONS::cse OPTIMIZE::cs_options CS_OPTIONS::side_effects then OPT_CSE::remove_cse(func); end;-- OPT_CSE::remove_cse do_loop_opt(func);-- OPTIMIZE::do_loop_opt -- there may be some more cs to e after inlining if cs_options.cse and cs_options.side_effects-- OPTIMIZE::cs_options CS_OPTIONS::cse OPTIMIZE::cs_options CS_OPTIONS::side_effects then OPT_CSE::remove_cse(func); end;-- OPT_CSE::remove_cse -- and some more prefetching too if cs_options.prefetch and cs_options.side_effects and prog.distributed then-- OPTIMIZE::cs_options CS_OPTIONS::prefetch OPTIMIZE::cs_options CS_OPTIONS::side_effects OPTIMIZE::prog PROG::distributed OPT_PREFETCH::prefetch(func); end;-- OPT_PREFETCH::prefetch if prog.opt_debug then -- or func.sig.str="TRANS::last_declared_helper:AM_LOCAL_EXPR" then-- OPTIMIZE::prog PROG::opt_debug #OUT+"optimized code {\n";-- OUT::create OUT::plus am::=func.code;-- AM_ROUT_DEF::code AM_OUT::AM_out(am);-- AM_OUT::AM_out #OUT+"}\n";-- OUT::create OUT::plus #OUT+"Optimizing function "+func.sig.str+" DONE\n";-- OUT::create OUT::plus OUT::plus AM_ROUT_DEF::sig SIG::str OUT::plus end; prog.back_end.emit(func);-- OPTIMIZE::prog PROG::back_end end; no_optimize(func:AM_ROUT_DEF) is -- if no optimization option is on, but opt_debug is on -- the compiler dumps the AM form of all functions. -- Handy to get them, but definitly the wrong place -- for this code. This will most certainly be deleted -- in future versions of the optimizer. if prog.opt_verbose then-- OPTIMIZE::prog PROG::opt_verbose #OUT+"working on "+func.sig.str+"\n";-- OUT::create OUT::plus OUT::plus AM_ROUT_DEF::sig SIG::str OUT::plus end; if ~void(prog.opt_debug_func) then-- OPTIMIZE::prog PROG::opt_debug_func BOOL::not prog.opt_debug:=false;-- OPTIMIZE::prog PROG::opt_debug loop if func.sig.str.search(prog.opt_debug_func.elt!)>=0 then-- AM_ROUT_DEF::sig SIG::str STR::search OPTIMIZE::prog PROG::opt_debug_func FLIST{1}::elt! INT::is_lt BOOL::not prog.opt_debug:=true;-- OPTIMIZE::prog PROG::opt_debug break!; end; end; end; if prog.opt_debug then -- OPTIMIZE::prog PROG::opt_debug #OUT+"Optimizing function "+func.sig.str;-- OUT::create OUT::plus OUT::plus AM_ROUT_DEF::sig SIG::str if ~void(func.srcsig) then-- AM_ROUT_DEF::srcsig BOOL::not #OUT+" "+func.srcsig.str;-- OUT::create OUT::plus OUT::plus AM_ROUT_DEF::srcsig SIG::str end; #OUT+"\n";-- OUT::create OUT::plus c::=#AM_CURSOR(prog,func.code);-- AM_CURSOR::create OPTIMIZE::prog AM_ROUT_DEF::code loop am::=c.next!;-- AM_CURSOR::next! loop (c.indent+1).times!;-- AM_CURSOR::indent INT::plus INT::times! #OUT+"-";-- OUT::create OUT::plus end; #OUT+"* "+SYS::str_for_tp(SYS::tp(am))+"\n";-- OUT::create OUT::plus OUT::plus SYS::str_for_tp SYS::tp OUT::plus end; #OUT+"AM_OUT {\n";-- OUT::create OUT::plus AM_OUT::AM_out(func.code);-- AM_OUT::AM_out AM_ROUT_DEF::code #OUT+"}\n";-- OUT::create OUT::plus #OUT+"Optimizing function "+func.sig.str+" DONE\n";-- OUT::create OUT::plus OUT::plus AM_ROUT_DEF::sig SIG::str OUT::plus end; prog.back_end.emit(func);-- OPTIMIZE::prog PROG::back_end end; finalize is prog.back_end.finalize;-- OPTIMIZE::prog PROG::back_end end; end; -- vim:sw=3:nosmartindent