o_const.sa
Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
---------------------------> Sather 1.1 source file <--------------------------
class OPT_CONST
class OPT_CONST is
include OPT_HELPER;
-- moves constant expressions out of the loop, and moves while! and until!
-- iters from the beginning of the loop to the end. This may help in hoisting
-- either constants or iter initializations.
const_hoisting(func:AM_ROUT_DEF,pass:INT) is
d::=const_hoisting(func,pass);-- OPT_CONST::const_hoisting
end;
const_hoisting(func:AM_ROUT_DEF,pass:INT):BOOL is
c::=#AM_CURSOR(prog,func.code);-- AM_CURSOR::create OPT_CONST::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
res:BOOL:=false;
after_loop_break:ARRAY{BOOL}:=#(30); -- not more than 30 loop recursions-- ARRAY{1}::create
loop
am::=c.next!;-- AM_CURSOR::next!
typecase am
when AM_RAISE_STMT then
after_loop_break[c.loops]:=true;-- ARRAY{1}::aset AM_CURSOR::loops
when AM_BREAK_STMT then
after_loop_break[c.loops]:=true;-- ARRAY{1}::aset AM_CURSOR::loops
when AM_ITER_CALL_EXPR then -- we don't hoist iter expressions anyway, so
-- there is no need to handle this case specially
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_LOOP_STMT then
after_loop_break[c.loops+1]:=false;-- ARRAY{1}::aset AM_CURSOR::loops INT::plus
if prog.move_while and pass <=2 then-- OPT_CONST::prog PROG::move_while INT::is_lt BOOL::not
b::=am.body;-- AM_LOOP_STMT::body
typecase b when AM_IF_STMT then -- move a first while! or until! out of and to
-- the end of the loop
if (void(b.if_true) or void(b.if_false)) and has_no_iter(b.test) -- AM_IF_STMT::if_true AM_IF_STMT::if_false OPT_CONST::has_no_iter AM_IF_STMT::test
and (void(am.first_while_moved) or SYS::id(am.first_while_moved)/=SYS::id(b)) then-- AM_LOOP_STMT::first_while_moved SYS::id AM_LOOP_STMT::first_while_moved INT::is_eq SYS::id BOOL::not
if void(am.first_while_moved) then am.first_while_moved:=b; end;-- AM_LOOP_STMT::first_while_moved AM_LOOP_STMT::first_while_moved
br:$AM_STMT;
if void(b.if_true) then-- AM_IF_STMT::if_true
br:=b.if_false;-- AM_IF_STMT::if_false
else
br:=b.if_true;-- AM_IF_STMT::if_true
end;
typecase br when AM_BREAK_STMT then
nif::=#AM_IF_STMT(am.source);-- AM_IF_STMT::create AM_LOOP_STMT::source
nif.test:=b.test.copy;-- AM_IF_STMT::test AM_IF_STMT::test
c.replace_stmt(nif);-- AM_CURSOR::replace_stmt
if void(b.if_true) then -- AM_IF_STMT::if_true
nif.if_true:=am;-- AM_IF_STMT::if_true
else
nif.if_false:=am;-- AM_IF_STMT::if_false
end;
am.next:=void;-- AM_LOOP_STMT::next
am.body:=am.body.next;-- AM_LOOP_STMT::body AM_LOOP_STMT::body
last::=am.body;-- AM_LOOP_STMT::body
if void(last) then
am.body:=b;-- AM_LOOP_STMT::body
else
loop
while!(~void(last.next));-- BOOL::not
last:=last.next;
end;
last.next:=b;
end;
b.next:=void;-- AM_IF_STMT::next
prog.stat.incr("O: # of while!/until! moved to the end of the loop");-- OPT_CONST::prog PROG::stat
res:=true;
if prog.opt_debug then-- OPT_CONST::prog PROG::opt_debug
#OUT+"moved a while!/until! iter to the end of the loop\n";-- OUT::create OUT::plus
end;
else end;
end;
else end;
end;
when AM_LOCAL_EXPR then -- we don't want to hoist local variables.
when $AM_CONST then -- we don't want to hoist consts either.
when AM_GLOBAL_EXPR then -- same is true for global expressions
when $AM_EXPR then
if c.loops>0 and prog.hoist_const and c.not_in_a_case_in_a_loop and c.not_prefetch_attr and -- AM_CURSOR::loops INT::is_lt OPT_CONST::prog PROG::hoist_const AM_CURSOR::not_in_a_case_in_a_loop AM_CURSOR::not_prefetch_attr
((pass>1 and ~func.is_iter) or ~c.in_iter_init) then-- INT::is_lt AM_ROUT_DEF::is_iter BOOL::not AM_CURSOR::in_iter_init BOOL::not
in_conditional::= ~c.not_in_a_conditional_in_loop;-- AM_CURSOR::not_in_a_conditional_in_loop
need_safe_attr::=after_loop_break[c.loops] or in_conditional;-- ARRAY{1}::aget AM_CURSOR::loops
if (~need_safe_attr or ~prog.void_checks or ~has_attr_expr(am))-- BOOL::not OPT_CONST::prog PROG::void_checks BOOL::not OPT_CONST::has_attr_expr BOOL::not
and hoistable(am,c,need_safe_attr,in_conditional) then-- OPT_CONST::hoistable
prog.stat.incr("O: # of expressions hoisted");-- OPT_CONST::prog PROG::stat
res:=true;
if void(am.tp) then
se::=#AM_EXPR_STMT(am.source);-- AM_EXPR_STMT::create
se.expr:=am;-- AM_EXPR_STMT::expr
c.delete_current;-- AM_CURSOR::delete_current
if need_safe_attr then make_safe_attr(se); end;-- OPT_CONST::make_safe_attr
c.insert_in_loop_init(se);-- AM_CURSOR::insert_in_loop_init
if prog.opt_debug then-- OPT_CONST::prog PROG::opt_debug
#OUT+"expression stmt hoisted:\n";-- OUT::create OUT::plus
AM_OUT::AM_out(am);#OUT+" (need_safe_attr="+need_safe_attr+")\n";-- AM_OUT::AM_out OUT::create OUT::plus OUT::plus OUT::plus
end;
else
e::=c.loop_stmt.hoisted;-- AM_CURSOR::loop_stmt AM_LOOP_STMT::hoisted
found_expr::=false;
if ~void(e) then-- BOOL::not
loop
i::=e.ind!;-- FLIST{1}::ind!
if am=e[i].expr then-- FLIST{1}::aget EXPR_HOISTED::expr
prog.stat.incr("O: # of double hoisted expressions");-- OPT_CONST::prog PROG::stat
if prog.opt_debug then-- OPT_CONST::prog PROG::opt_debug
#OUT+"double expression stmt hoisted:\n";-- OUT::create OUT::plus
AM_OUT::AM_out(am);#OUT+" (need_safe_attr="+need_safe_attr+")\n";-- AM_OUT::AM_out OUT::create OUT::plus OUT::plus OUT::plus
end;
res:=true;
found_expr:=true;
if e[i].is_safe and ~need_safe_attr then-- FLIST{1}::aget EXPR_HOISTED::is_safe BOOL::not
make_unsafe_attr(e[i].expr);-- OPT_CONST::make_unsafe_attr FLIST{1}::aget EXPR_HOISTED::expr
end;
c.replace_expr(e[i].local);-- AM_CURSOR::replace_expr FLIST{1}::aget EXPR_HOISTED::local
break!;
end;
end;
end;
if ~found_expr then-- BOOL::not
l::=new_local(func,am.tp);-- OPT_CONST::new_local
as::=#AM_ASSIGN_STMT(am.source);-- AM_ASSIGN_STMT::create
as.dest:=l;-- AM_ASSIGN_STMT::dest
as.src:=am;-- AM_ASSIGN_STMT::src
comment::=#AM_COMMENT_STMT(am.source);-- AM_COMMENT_STMT::create
comment.comment:="hoisted expression comming from "+am.source.str;-- AM_COMMENT_STMT::comment STR::plus SFILE_ID::str
if need_safe_attr then make_safe_attr(am); end;-- OPT_CONST::make_safe_attr
c.insert_in_loop_init(comment);-- AM_CURSOR::insert_in_loop_init
c.insert_in_loop_init(as);-- AM_CURSOR::insert_in_loop_init
c.replace_expr(l);-- AM_CURSOR::replace_expr
c.loop_stmt.hoisted:=e.push(#EXPR_HOISTED(am,need_safe_attr,l));-- AM_CURSOR::loop_stmt AM_LOOP_STMT::hoisted FLIST{1}::push EXPR_HOISTED::create
if prog.opt_debug then-- OPT_CONST::prog PROG::opt_debug
#OUT+"expression hoisted:\n";-- OUT::create OUT::plus
AM_OUT::AM_out(am);-- AM_OUT::AM_out
#OUT+" (need_safe_attr="+need_safe_attr+")\n"-- OUT::create OUT::plus OUT::plus
end;-- OUT::plus
end;
end;
end;
end;
typecase am when AM_ROUT_CALL_EXPR then
-- there coud be a raise in this routine cal. If we are unable to
-- know this (because we compile without side effects), we assume
-- the worst.
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 OPT_CONST::prog BOOL::not AM_ROUT_CALL_EXPR::fun SIG::get_se_context OPT_CONST::prog SE_CONTEXT::has_raise
else end;
when AM_ASSIGN_STMT then
if c.loops>0 and prog.hoist_const and c.not_in_a_case_in_a_loop and -- AM_CURSOR::loops INT::is_lt OPT_CONST::prog PROG::hoist_const AM_CURSOR::not_in_a_case_in_a_loop
((pass>1 and ~func.is_iter) or ~c.in_iter_init) then-- INT::is_lt AM_ROUT_DEF::is_iter BOOL::not AM_CURSOR::in_iter_init BOOL::not
in_conditional::= ~c.not_in_a_conditional_in_loop;-- AM_CURSOR::not_in_a_conditional_in_loop
need_safe_attr::=after_loop_break[c.loops] or in_conditional;-- ARRAY{1}::aget AM_CURSOR::loops
if (~need_safe_attr or ~prog.void_checks or ~has_attr_expr(am))-- BOOL::not OPT_CONST::prog PROG::void_checks BOOL::not OPT_CONST::has_attr_expr BOOL::not
and hoistable_dest(am,c,need_safe_attr,in_conditional)-- OPT_CONST::hoistable_dest
and hoistable(am.src,c,need_safe_attr,in_conditional) then-- OPT_CONST::hoistable AM_ASSIGN_STMT::src
if need_safe_attr then make_safe_attr(am.src); end;-- OPT_CONST::make_safe_attr AM_ASSIGN_STMT::src
if prog.opt_debug then-- OPT_CONST::prog PROG::opt_debug
#OUT+"assignment hoisted: (need_safe_attr="+need_safe_attr+")\n";-- OUT::create OUT::plus OUT::plus OUT::plus
AM_OUT::AM_one_stmt(am);-- AM_OUT::AM_one_stmt
end;
c.delete_current;-- AM_CURSOR::delete_current
comment::=#AM_COMMENT_STMT(am.source);-- AM_COMMENT_STMT::create AM_ASSIGN_STMT::source
comment.comment:="hoisted assignment comming from "+am.source.str;-- AM_COMMENT_STMT::comment STR::plus AM_ASSIGN_STMT::source SFILE_ID::str
c.insert_in_loop_init(comment);-- AM_CURSOR::insert_in_loop_init
c.insert_in_loop_init(am);-- AM_CURSOR::insert_in_loop_init
prog.stat.incr("O: # of assignments hoisted");-- OPT_CONST::prog PROG::stat
res:=true;
-- else
-- if prog.opt_debug then
-- #OUT+"assignment NOT hoisted: need_safe_attr="+need_safe_attr+" ";
-- #OUT+"prog.void_checks="+prog.void_checks;
-- #OUT+" has_attr_expr="+has_attr_expr(am)+"\n";
-- -- #OUT+"hoistable_dest="+hoistable_dest(am,c,need_safe_attr,in_conditional)+
-- -- "hoistable="+hoistable(am.src,c,need_safe_attr,in_conditional)+"\n";
-- AM_OUT::AM_one_stmt(am);
-- end;
end;
end;
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;
return res;
end;
end;