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