mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-07-08 14:16:43 +02:00
+ transform for loop into equivalent while loop during pass 1 to simplify code generation
git-svn-id: trunk@34788 -
This commit is contained in:
parent
82e6e1eb34
commit
0610187878
@ -42,10 +42,7 @@ interface
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
tcgfornode = class(tfornode)
|
tcgfornode = class(tfornode)
|
||||||
usedregvars: tusedregvars;
|
|
||||||
|
|
||||||
procedure pass_generate_code;override;
|
procedure pass_generate_code;override;
|
||||||
procedure sync_regvars(checkusedregvars: boolean);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
tcgexitnode = class(texitnode)
|
tcgexitnode = class(texitnode)
|
||||||
@ -379,435 +376,10 @@ implementation
|
|||||||
SecondFor
|
SecondFor
|
||||||
*****************************************************************************}
|
*****************************************************************************}
|
||||||
|
|
||||||
procedure tcgfornode.sync_regvars(checkusedregvars: boolean);
|
|
||||||
begin
|
|
||||||
if (cs_opt_regvar in current_settings.optimizerswitches) and
|
|
||||||
not(pi_has_label in current_procinfo.flags) then
|
|
||||||
begin
|
|
||||||
if checkusedregvars then
|
|
||||||
begin
|
|
||||||
usedregvars.intregvars.init;
|
|
||||||
usedregvars.addrregvars.init;
|
|
||||||
usedregvars.fpuregvars.init;
|
|
||||||
usedregvars.mmregvars.init;
|
|
||||||
|
|
||||||
{ We have to synchronise the loop variable and loop body. }
|
|
||||||
{ The loop end is not necessary, unless it's a register }
|
|
||||||
{ variable. The start value also doesn't matter. }
|
|
||||||
|
|
||||||
{ loop var }
|
|
||||||
get_used_regvars(left,usedregvars);
|
|
||||||
{ loop body }
|
|
||||||
get_used_regvars(t2,usedregvars);
|
|
||||||
{ end value can't be a regvar, but may be a temp in register }
|
|
||||||
get_used_regvars(t1,usedregvars);
|
|
||||||
|
|
||||||
gen_sync_regvars(current_asmdata.CurrAsmList,usedregvars);
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
gen_sync_regvars(current_asmdata.CurrAsmList,usedregvars);
|
|
||||||
usedregvars.intregvars.done;
|
|
||||||
usedregvars.addrregvars.done;
|
|
||||||
usedregvars.fpuregvars.done;
|
|
||||||
usedregvars.mmregvars.done;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
procedure tcgfornode.pass_generate_code;
|
procedure tcgfornode.pass_generate_code;
|
||||||
var
|
|
||||||
l3,oldclabel,oldblabel : tasmlabel;
|
|
||||||
temptovalue : boolean;
|
|
||||||
hop : topcg;
|
|
||||||
hcond : topcmp;
|
|
||||||
opsize : tcgsize;
|
|
||||||
count_var_is_signed,do_loopvar_at_end : boolean;
|
|
||||||
cmp_const:Tconstexprint;
|
|
||||||
oldflowcontrol : tflowcontrol;
|
|
||||||
oldexecutionweight : longint;
|
|
||||||
begin
|
begin
|
||||||
location_reset(location,LOC_VOID,OS_NO);
|
{ for nodes are converted in pass_1 in a while loop }
|
||||||
|
internalerror(2015082501);
|
||||||
oldclabel:=current_procinfo.CurrContinueLabel;
|
|
||||||
oldblabel:=current_procinfo.CurrBreakLabel;
|
|
||||||
current_asmdata.getjumplabel(current_procinfo.CurrContinueLabel);
|
|
||||||
current_asmdata.getjumplabel(current_procinfo.CurrBreakLabel);
|
|
||||||
current_asmdata.getjumplabel(l3);
|
|
||||||
|
|
||||||
{ only calculate reference }
|
|
||||||
opsize := def_cgsize(left.resultdef);
|
|
||||||
count_var_is_signed:=is_signed(left.resultdef);
|
|
||||||
|
|
||||||
{ first set the to value
|
|
||||||
because the count var can be in the expression ! }
|
|
||||||
do_loopvar_at_end:=(lnf_dont_mind_loopvar_on_exit in loopflags)
|
|
||||||
{ if the loop is unrolled and there is a jump into the loop,
|
|
||||||
then we can't do the trick with incrementing the loop var only at the
|
|
||||||
end
|
|
||||||
}
|
|
||||||
and not(assigned(entrylabel));
|
|
||||||
|
|
||||||
secondpass(t1);
|
|
||||||
if t1.location.loc in [LOC_FLAGS,LOC_JUMP] then
|
|
||||||
hlcg.location_force_reg(current_asmdata.CurrAsmList,t1.location,t1.resultdef,t1.resultdef,false);
|
|
||||||
{ calculate pointer value and check if changeable and if so }
|
|
||||||
{ load into temporary variable }
|
|
||||||
if t1.nodetype<>ordconstn then
|
|
||||||
begin
|
|
||||||
do_loopvar_at_end:=false;
|
|
||||||
temptovalue:=true;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
temptovalue:=false;
|
|
||||||
|
|
||||||
{ load loopvar, prefer loopvar being a register variable }
|
|
||||||
oldexecutionweight:=cg.executionweight;
|
|
||||||
inc(cg.executionweight,8);
|
|
||||||
secondpass(left);
|
|
||||||
cg.executionweight:=oldexecutionweight;
|
|
||||||
|
|
||||||
{ load from value }
|
|
||||||
secondpass(right);
|
|
||||||
if right.location.loc in [LOC_FLAGS,LOC_JUMP] then
|
|
||||||
hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,false);
|
|
||||||
|
|
||||||
hlcg.maybe_change_load_node_reg(current_asmdata.CurrAsmList,left,false);
|
|
||||||
oldflowcontrol:=flowcontrol;
|
|
||||||
include(flowcontrol,fc_inflowcontrol);
|
|
||||||
exclude(flowcontrol,fc_unwind_loop);
|
|
||||||
{ produce start assignment }
|
|
||||||
case left.location.loc of
|
|
||||||
LOC_REFERENCE,
|
|
||||||
LOC_CREFERENCE :
|
|
||||||
hlcg.a_load_loc_ref(current_asmdata.CurrAsmList,right.resultdef,left.resultdef,right.location,left.location.reference);
|
|
||||||
LOC_REGISTER,
|
|
||||||
LOC_CREGISTER:
|
|
||||||
hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,right.resultdef,left.resultdef,right.location,left.location.register);
|
|
||||||
LOC_SUBSETREG,
|
|
||||||
LOC_CSUBSETREG :
|
|
||||||
hlcg.a_load_loc_subsetreg(current_asmdata.CurrAsmList,right.resultdef,left.resultdef,right.location,left.location.sreg);
|
|
||||||
else
|
|
||||||
internalerror(200501311);
|
|
||||||
end;
|
|
||||||
|
|
||||||
if lnf_backward in loopflags then
|
|
||||||
if count_var_is_signed then
|
|
||||||
hcond:=OC_LT
|
|
||||||
else
|
|
||||||
hcond:=OC_B
|
|
||||||
else
|
|
||||||
if count_var_is_signed then
|
|
||||||
hcond:=OC_GT
|
|
||||||
else
|
|
||||||
hcond:=OC_A;
|
|
||||||
|
|
||||||
sync_regvars(true);
|
|
||||||
{$ifdef OLDREGVARS}
|
|
||||||
load_all_regvars(current_asmdata.CurrAsmList);
|
|
||||||
{$endif OLDREGVARS}
|
|
||||||
|
|
||||||
if temptovalue then
|
|
||||||
begin
|
|
||||||
case t1.location.loc of
|
|
||||||
LOC_REGISTER,LOC_CREGISTER:
|
|
||||||
hlcg.a_cmp_reg_loc_label(current_asmdata.CurrAsmList,left.resultdef,hcond,
|
|
||||||
t1.location.register,left.location,current_procinfo.CurrBreakLabel);
|
|
||||||
LOC_REFERENCE,LOC_CREFERENCE:
|
|
||||||
hlcg.a_cmp_ref_loc_label(current_asmdata.CurrAsmList,left.resultdef,hcond,
|
|
||||||
t1.location.reference,left.location,current_procinfo.CurrBreakLabel);
|
|
||||||
else
|
|
||||||
InternalError(2013051601);
|
|
||||||
end;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
if lnf_testatbegin in loopflags then
|
|
||||||
begin
|
|
||||||
hlcg.a_cmp_const_loc_label(current_asmdata.CurrAsmList,left.resultdef,hcond,
|
|
||||||
tordconstnode(t1).value.svalue,
|
|
||||||
left.location,current_procinfo.CurrBreakLabel);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{If the loopvar doesn't mind on exit, we avoid this ugly
|
|
||||||
dec instruction and do the loopvar inc/dec after the loop
|
|
||||||
body.}
|
|
||||||
if not do_loopvar_at_end then
|
|
||||||
begin
|
|
||||||
if lnf_backward in loopflags then
|
|
||||||
hop:=OP_ADD
|
|
||||||
else
|
|
||||||
hop:=OP_SUB;
|
|
||||||
hlcg.a_op_const_loc(current_asmdata.CurrAsmList,hop,left.resultdef,1,left.location);
|
|
||||||
end;
|
|
||||||
|
|
||||||
if assigned(entrylabel) then
|
|
||||||
hlcg.a_jmp_always(current_asmdata.CurrAsmList,tcglabelnode(entrylabel).getasmlabel);
|
|
||||||
|
|
||||||
{ align loop target }
|
|
||||||
if not(cs_opt_size in current_settings.optimizerswitches) then
|
|
||||||
current_asmdata.CurrAsmList.concat(Tai_align.Create(current_settings.alignment.loopalign));
|
|
||||||
hlcg.a_label(current_asmdata.CurrAsmList,l3);
|
|
||||||
|
|
||||||
{If the loopvar doesn't mind on exit, we avoid the loopvar inc/dec
|
|
||||||
after the loop body instead of here.}
|
|
||||||
if not do_loopvar_at_end then
|
|
||||||
begin
|
|
||||||
{ according to count direction DEC or INC... }
|
|
||||||
if lnf_backward in loopflags then
|
|
||||||
hop:=OP_SUB
|
|
||||||
else
|
|
||||||
hop:=OP_ADD;
|
|
||||||
hlcg.a_op_const_loc(current_asmdata.CurrAsmList,hop,left.resultdef,1,left.location);
|
|
||||||
end;
|
|
||||||
|
|
||||||
if assigned(t2) then
|
|
||||||
begin
|
|
||||||
{ Calc register weight }
|
|
||||||
oldexecutionweight:=cg.executionweight;
|
|
||||||
cg.executionweight:=cg.executionweight*8;
|
|
||||||
secondpass(t2);
|
|
||||||
cg.executionweight:=oldexecutionweight;
|
|
||||||
{$ifdef OLDREGVARS}
|
|
||||||
load_all_regvars(current_asmdata.CurrAsmList);
|
|
||||||
{$endif OLDREGVARS}
|
|
||||||
end;
|
|
||||||
|
|
||||||
{If the loopvar doesn't mind on exit, we do the loopvar inc/dec
|
|
||||||
after the loop body instead of here.}
|
|
||||||
if do_loopvar_at_end then
|
|
||||||
begin
|
|
||||||
{ according to count direction DEC or INC... }
|
|
||||||
if lnf_backward in loopflags then
|
|
||||||
hop:=OP_SUB
|
|
||||||
else
|
|
||||||
hop:=OP_ADD;
|
|
||||||
hlcg.a_op_const_loc(current_asmdata.CurrAsmList,hop,left.resultdef,1,left.location);
|
|
||||||
end;
|
|
||||||
|
|
||||||
hlcg.a_label(current_asmdata.CurrAsmList,current_procinfo.CurrContinueLabel);
|
|
||||||
|
|
||||||
if do_loopvar_at_end then
|
|
||||||
if lnf_backward in loopflags then
|
|
||||||
if count_var_is_signed then
|
|
||||||
hcond:=OC_GTE
|
|
||||||
else
|
|
||||||
hcond:=OC_AE
|
|
||||||
else
|
|
||||||
if count_var_is_signed then
|
|
||||||
hcond:=OC_LTE
|
|
||||||
else
|
|
||||||
hcond:=OC_BE
|
|
||||||
else
|
|
||||||
if lnf_backward in loopflags then
|
|
||||||
if count_var_is_signed then
|
|
||||||
hcond:=OC_GT
|
|
||||||
else
|
|
||||||
hcond:=OC_A
|
|
||||||
else
|
|
||||||
if count_var_is_signed then
|
|
||||||
hcond:=OC_LT
|
|
||||||
else
|
|
||||||
hcond:=OC_B;
|
|
||||||
{$ifdef OLDREGVARS}
|
|
||||||
load_all_regvars(current_asmdata.CurrAsmList);
|
|
||||||
{$endif OLDREGVARS}
|
|
||||||
|
|
||||||
{ produce comparison and the corresponding }
|
|
||||||
{ jump }
|
|
||||||
if temptovalue then
|
|
||||||
begin
|
|
||||||
case t1.location.loc of
|
|
||||||
LOC_REGISTER,LOC_CREGISTER:
|
|
||||||
hlcg.a_cmp_reg_loc_label(current_asmdata.CurrAsmList,left.resultdef,hcond,t1.location.register,
|
|
||||||
left.location,l3);
|
|
||||||
LOC_REFERENCE,LOC_CREFERENCE:
|
|
||||||
hlcg.a_cmp_ref_loc_label(current_asmdata.CurrAsmList,left.resultdef,hcond,t1.location.reference,
|
|
||||||
left.location,l3);
|
|
||||||
else
|
|
||||||
InternalError(2013051602);
|
|
||||||
end;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
cmp_const:=Tordconstnode(t1).value;
|
|
||||||
if do_loopvar_at_end then
|
|
||||||
begin
|
|
||||||
{Watch out for wrap around 255 -> 0.}
|
|
||||||
{Ugly: This code is way to long... Use tables?}
|
|
||||||
case opsize of
|
|
||||||
OS_8:
|
|
||||||
begin
|
|
||||||
if lnf_backward in loopflags then
|
|
||||||
begin
|
|
||||||
if byte(cmp_const.svalue)=low(byte) then
|
|
||||||
begin
|
|
||||||
hcond:=OC_NE;
|
|
||||||
cmp_const:=high(byte);
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
if byte(cmp_const.svalue)=high(byte) then
|
|
||||||
begin
|
|
||||||
hcond:=OC_NE;
|
|
||||||
cmp_const:=low(byte);
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
OS_16:
|
|
||||||
begin
|
|
||||||
if lnf_backward in loopflags then
|
|
||||||
begin
|
|
||||||
if word(cmp_const.svalue)=high(word) then
|
|
||||||
begin
|
|
||||||
hcond:=OC_NE;
|
|
||||||
cmp_const:=low(word);
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
if word(cmp_const.svalue)=low(word) then
|
|
||||||
begin
|
|
||||||
hcond:=OC_NE;
|
|
||||||
cmp_const:=high(word);
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
OS_32:
|
|
||||||
begin
|
|
||||||
if lnf_backward in loopflags then
|
|
||||||
begin
|
|
||||||
if cardinal(cmp_const.svalue)=high(cardinal) then
|
|
||||||
begin
|
|
||||||
hcond:=OC_NE;
|
|
||||||
cmp_const:=low(cardinal);
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
if cardinal(cmp_const.svalue)=low(cardinal) then
|
|
||||||
begin
|
|
||||||
hcond:=OC_NE;
|
|
||||||
cmp_const:=high(cardinal);
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
OS_64:
|
|
||||||
begin
|
|
||||||
if lnf_backward in loopflags then
|
|
||||||
begin
|
|
||||||
if qword(cmp_const.uvalue)=high(qword) then
|
|
||||||
begin
|
|
||||||
hcond:=OC_NE;
|
|
||||||
cmp_const:=low(qword);
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
if qword(cmp_const.uvalue)=low(qword) then
|
|
||||||
begin
|
|
||||||
hcond:=OC_NE;
|
|
||||||
cmp_const:=high(qword);
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
OS_S8:
|
|
||||||
begin
|
|
||||||
if lnf_backward in loopflags then
|
|
||||||
begin
|
|
||||||
if shortint(cmp_const.svalue)=low(shortint) then
|
|
||||||
begin
|
|
||||||
hcond:=OC_NE;
|
|
||||||
cmp_const:=high(shortint);
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
if shortint(cmp_const.svalue)=high(shortint) then
|
|
||||||
begin
|
|
||||||
hcond:=OC_NE;
|
|
||||||
cmp_const:=int64(low(shortint));
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
OS_S16:
|
|
||||||
begin
|
|
||||||
if lnf_backward in loopflags then
|
|
||||||
begin
|
|
||||||
if integer(cmp_const.svalue)=high(smallint) then
|
|
||||||
begin
|
|
||||||
hcond:=OC_NE;
|
|
||||||
cmp_const:=int64(low(smallint));
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
if integer(cmp_const.svalue)=low(smallint) then
|
|
||||||
begin
|
|
||||||
hcond:=OC_NE;
|
|
||||||
cmp_const:=int64(high(smallint));
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
OS_S32:
|
|
||||||
begin
|
|
||||||
if lnf_backward in loopflags then
|
|
||||||
begin
|
|
||||||
if longint(cmp_const.svalue)=high(longint) then
|
|
||||||
begin
|
|
||||||
hcond:=OC_NE;
|
|
||||||
cmp_const:=int64(low(longint));
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
if longint(cmp_const.svalue)=low(longint) then
|
|
||||||
begin
|
|
||||||
hcond:=OC_NE;
|
|
||||||
cmp_const:=int64(high(longint));
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
OS_S64:
|
|
||||||
begin
|
|
||||||
if lnf_backward in loopflags then
|
|
||||||
begin
|
|
||||||
if int64(cmp_const.svalue)=high(int64) then
|
|
||||||
begin
|
|
||||||
hcond:=OC_NE;
|
|
||||||
cmp_const:=low(int64);
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
if int64(cmp_const.svalue)=low(int64) then
|
|
||||||
begin
|
|
||||||
hcond:=OC_NE;
|
|
||||||
cmp_const:=high(int64);
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
else
|
|
||||||
internalerror(200201021);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
hlcg.a_cmp_const_loc_label(current_asmdata.CurrAsmList,left.resultdef,hcond,
|
|
||||||
tcgint(cmp_const.svalue),left.location,l3);
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ this is the break label: }
|
|
||||||
hlcg.a_label(current_asmdata.CurrAsmList,current_procinfo.CurrBreakLabel);
|
|
||||||
|
|
||||||
sync_regvars(false);
|
|
||||||
|
|
||||||
current_procinfo.CurrContinueLabel:=oldclabel;
|
|
||||||
current_procinfo.CurrBreakLabel:=oldblabel;
|
|
||||||
{ a break/continue in a while/repeat block can't be seen outside }
|
|
||||||
flowcontrol:=oldflowcontrol+(flowcontrol-[fc_break,fc_continue,fc_inflowcontrol]);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,6 +72,9 @@ interface
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
twhilerepeatnode = class(tloopnode)
|
twhilerepeatnode = class(tloopnode)
|
||||||
|
{ l: condition; r: body; tab: test at begin; cn: negate condition
|
||||||
|
x,y,true,false: while loop
|
||||||
|
x,y,false,true: repeat until loop }
|
||||||
constructor create(l,r:Tnode;tab,cn:boolean);virtual;reintroduce;
|
constructor create(l,r:Tnode;tab,cn:boolean);virtual;reintroduce;
|
||||||
function pass_typecheck:tnode;override;
|
function pass_typecheck:tnode;override;
|
||||||
function pass_1 : tnode;override;
|
function pass_1 : tnode;override;
|
||||||
@ -101,7 +104,6 @@ interface
|
|||||||
loopiteration : tnode;
|
loopiteration : tnode;
|
||||||
loopvar_notid:cardinal;
|
loopvar_notid:cardinal;
|
||||||
constructor create(l,r,_t1,_t2 : tnode;back : boolean);virtual;reintroduce;
|
constructor create(l,r,_t1,_t2 : tnode;back : boolean);virtual;reintroduce;
|
||||||
function wrap_to_value:tnode;
|
|
||||||
function pass_typecheck:tnode;override;
|
function pass_typecheck:tnode;override;
|
||||||
function pass_1 : tnode;override;
|
function pass_1 : tnode;override;
|
||||||
function simplify(forinline : boolean) : tnode;override;
|
function simplify(forinline : boolean) : tnode;override;
|
||||||
@ -1475,29 +1477,6 @@ implementation
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
function tfornode.wrap_to_value:tnode;
|
|
||||||
var
|
|
||||||
statements: tstatementnode;
|
|
||||||
temp: ttempcreatenode;
|
|
||||||
begin
|
|
||||||
result:=internalstatements(statements);
|
|
||||||
temp:=ctempcreatenode.create(t1.resultdef,t1.resultdef.size,tt_persistent,true);
|
|
||||||
addstatement(statements,temp);
|
|
||||||
addstatement(statements,cassignmentnode.create(
|
|
||||||
ctemprefnode.create(temp),
|
|
||||||
t1));
|
|
||||||
{ create a new for node, it is cheaper than cloning entire loop body }
|
|
||||||
addstatement(statements,cfornode.create(
|
|
||||||
left,right,ctemprefnode.create(temp),t2,lnf_backward in loopflags));
|
|
||||||
addstatement(statements,ctempdeletenode.create(temp));
|
|
||||||
{ all child nodes are reused }
|
|
||||||
left:=nil;
|
|
||||||
right:=nil;
|
|
||||||
t1:=nil;
|
|
||||||
t2:=nil;
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
function tfornode.pass_typecheck:tnode;
|
function tfornode.pass_typecheck:tnode;
|
||||||
var
|
var
|
||||||
res : tnode;
|
res : tnode;
|
||||||
@ -1545,23 +1524,196 @@ implementation
|
|||||||
|
|
||||||
|
|
||||||
function tfornode.pass_1 : tnode;
|
function tfornode.pass_1 : tnode;
|
||||||
|
var
|
||||||
|
ifblock,whileblock,loopblock : tblocknode;
|
||||||
|
ifstatements,statements,loopstatements : tstatementnode;
|
||||||
|
fromtemp,totemp : ttempcreatenode;
|
||||||
|
do_loopvar_at_end : Boolean;
|
||||||
|
{ if the lower and/or upper bound are variable, we need a surrounding if }
|
||||||
|
needsifblock : Boolean;
|
||||||
|
cond : tnodetype;
|
||||||
|
fromexpr : tnode;
|
||||||
|
toexpr : tnode;
|
||||||
|
{ if the upper bound is not constant, it must be store in a temp initially }
|
||||||
|
usetotemp : boolean;
|
||||||
|
{ if the lower bound is not constant, it must be store in a temp before calculating the upper bound }
|
||||||
|
usefromtemp : boolean;
|
||||||
|
|
||||||
|
procedure iterate_counter(var s : tstatementnode;fw : boolean);
|
||||||
|
begin
|
||||||
|
if fw then
|
||||||
|
addstatement(s,
|
||||||
|
cassignmentnode.create_internal(left.getcopy,cinlinenode.createintern(in_succ_x,false,left.getcopy)))
|
||||||
|
else
|
||||||
|
addstatement(s,
|
||||||
|
cassignmentnode.create_internal(left.getcopy,cinlinenode.createintern(in_pred_x,false,left.getcopy)));
|
||||||
|
end;
|
||||||
|
|
||||||
|
function iterate_counter_func(arg : tnode;fw : boolean) : tnode;
|
||||||
|
begin
|
||||||
|
if fw then
|
||||||
|
result:=cinlinenode.createintern(in_succ_x,false,arg)
|
||||||
|
else
|
||||||
|
result:=cinlinenode.createintern(in_pred_x,false,arg);
|
||||||
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
result:=nil;
|
result:=nil;
|
||||||
expectloc:=LOC_VOID;
|
expectloc:=LOC_VOID;
|
||||||
|
fromtemp:=nil;
|
||||||
|
totemp:=nil;
|
||||||
|
|
||||||
firstpass(left);
|
firstpass(left);
|
||||||
firstpass(right);
|
firstpass(right);
|
||||||
firstpass(t1);
|
firstpass(t1);
|
||||||
|
|
||||||
if assigned(t2) then
|
if assigned(t2) then
|
||||||
|
begin
|
||||||
firstpass(t2);
|
firstpass(t2);
|
||||||
if codegenerror then
|
if codegenerror then
|
||||||
exit;
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
{ 'to' value must be evaluated once before loop, so its possible modifications
|
{ first set the to value
|
||||||
inside loop body do not affect the number of iterations (see webtbs/tw8883). }
|
because the count var can be in the expression ! }
|
||||||
if not (t1.nodetype in [ordconstn,temprefn]) then
|
do_loopvar_at_end:=(lnf_dont_mind_loopvar_on_exit in loopflags)
|
||||||
result:=wrap_to_value;
|
{ if the loop is unrolled and there is a jump into the loop,
|
||||||
|
then we can't do the trick with incrementing the loop var only at the
|
||||||
|
end
|
||||||
|
}
|
||||||
|
and not(assigned(entrylabel));
|
||||||
|
|
||||||
|
{ calculate pointer value and check if changeable and if so
|
||||||
|
load into temporary variable }
|
||||||
|
if (right.nodetype<>ordconstn) or (t1.nodetype<>ordconstn) then
|
||||||
|
begin
|
||||||
|
do_loopvar_at_end:=false;
|
||||||
|
needsifblock:=true;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
needsifblock:=false;
|
||||||
|
|
||||||
|
{ convert the for loop into a while loop }
|
||||||
|
result:=internalstatements(statements);
|
||||||
|
ifblock:=internalstatements(ifstatements);
|
||||||
|
loopblock:=internalstatements(loopstatements);
|
||||||
|
|
||||||
|
usefromtemp:=(might_have_sideeffects(t1) and not(is_const(right))) or (node_complexity(right)>1);
|
||||||
|
usetotemp:=not(is_const(t1));
|
||||||
|
|
||||||
|
if needsifblock then
|
||||||
|
begin
|
||||||
|
{ do not generate a temp. for the from node, if it is a const, it can be copied directly since
|
||||||
|
no side effect might change it }
|
||||||
|
if usefromtemp then
|
||||||
|
begin
|
||||||
|
fromtemp:=ctempcreatenode.create(right.resultdef,right.resultdef.size,tt_persistent,true);
|
||||||
|
{ the if block might be optimized out, so we put the deletetempnode after the if-block, however,
|
||||||
|
this causes a long life time of the fromtemp. If the final regsync is left away, the reg. allocator
|
||||||
|
figures out the needed life time. As their are no loops involved between the uses of the fromtemp,
|
||||||
|
this does no hurt }
|
||||||
|
fromtemp.includetempflag(ti_no_final_regsync);
|
||||||
|
addstatement(statements,fromtemp);
|
||||||
|
{ while it would be beneficial to fold the initial reverse succ/pred into this assignment, this is
|
||||||
|
not possible because it might wrap around and the if check later on goes wrong }
|
||||||
|
addstatement(statements,cassignmentnode.create_internal(ctemprefnode.create(fromtemp),right.getcopy));
|
||||||
|
end;
|
||||||
|
|
||||||
|
if usetotemp then
|
||||||
|
begin
|
||||||
|
totemp:=ctempcreatenode.create(t1.resultdef,t1.resultdef.size,tt_persistent,true);
|
||||||
|
addstatement(statements,totemp);
|
||||||
|
addstatement(statements,cassignmentnode.create_internal(ctemprefnode.create(totemp),t1.getcopy));
|
||||||
|
end;
|
||||||
|
|
||||||
|
if usefromtemp then
|
||||||
|
begin
|
||||||
|
addstatement(ifstatements,cassignmentnode.create_internal(left.getcopy,ctemprefnode.create(fromtemp)));
|
||||||
|
if not(do_loopvar_at_end) then
|
||||||
|
iterate_counter(ifstatements,lnf_backward in loopflags);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if not(do_loopvar_at_end) then
|
||||||
|
addstatement(ifstatements,cassignmentnode.create_internal(left.getcopy,
|
||||||
|
iterate_counter_func(right.getcopy,lnf_backward in loopflags)))
|
||||||
|
else
|
||||||
|
addstatement(ifstatements,cassignmentnode.create_internal(left.getcopy,right.getcopy));
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if not(do_loopvar_at_end) then
|
||||||
|
addstatement(ifstatements,cassignmentnode.create_internal(left.getcopy,
|
||||||
|
iterate_counter_func(right.getcopy,lnf_backward in loopflags)))
|
||||||
|
else
|
||||||
|
addstatement(ifstatements,cassignmentnode.create_internal(left.getcopy,right.getcopy));
|
||||||
|
end;
|
||||||
|
|
||||||
|
if assigned(entrylabel) then
|
||||||
|
addstatement(ifstatements,cgotonode.create(tlabelnode(entrylabel).labsym));
|
||||||
|
|
||||||
|
if not(do_loopvar_at_end) then
|
||||||
|
iterate_counter(loopstatements,not(lnf_backward in loopflags));
|
||||||
|
|
||||||
|
{ avoid copying t2, it is used only once and it might be big }
|
||||||
|
addstatement(loopstatements,t2);
|
||||||
|
t2:=nil;
|
||||||
|
|
||||||
|
if do_loopvar_at_end then
|
||||||
|
iterate_counter(loopstatements,not(lnf_backward in loopflags));
|
||||||
|
|
||||||
|
if do_loopvar_at_end then
|
||||||
|
begin
|
||||||
|
if lnf_backward in loopflags then
|
||||||
|
cond:=ltn
|
||||||
|
else
|
||||||
|
cond:=gtn;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if lnf_backward in loopflags then
|
||||||
|
cond:=lten
|
||||||
|
else
|
||||||
|
cond:=gten;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if needsifblock then
|
||||||
|
begin
|
||||||
|
if usetotemp then
|
||||||
|
toexpr:=ctemprefnode.create(totemp)
|
||||||
|
else
|
||||||
|
toexpr:=t1.getcopy;
|
||||||
|
|
||||||
|
addstatement(ifstatements,cwhilerepeatnode.create(caddnode.create(cond,left.getcopy,toexpr),loopblock,false,true));
|
||||||
|
|
||||||
|
if usefromtemp then
|
||||||
|
fromexpr:=ctemprefnode.create(fromtemp)
|
||||||
|
else
|
||||||
|
fromexpr:=right.getcopy;
|
||||||
|
|
||||||
|
if usetotemp then
|
||||||
|
toexpr:=ctemprefnode.create(totemp)
|
||||||
|
else
|
||||||
|
toexpr:=t1.getcopy;
|
||||||
|
|
||||||
|
if lnf_backward in loopflags then
|
||||||
|
addstatement(statements,cifnode.create(caddnode.create(gten,
|
||||||
|
fromexpr,toexpr),ifblock,nil))
|
||||||
|
else
|
||||||
|
addstatement(statements,cifnode.create(caddnode.create(lten,
|
||||||
|
fromexpr,toexpr),ifblock,nil));
|
||||||
|
|
||||||
|
if usetotemp then
|
||||||
|
addstatement(statements,ctempdeletenode.create(totemp));
|
||||||
|
if usefromtemp then
|
||||||
|
addstatement(statements,ctempdeletenode.create(fromtemp));
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
addstatement(ifstatements,cwhilerepeatnode.create(caddnode.create(cond,left.getcopy,t1.getcopy),loopblock,false,true));
|
||||||
|
addstatement(statements,ifblock);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user