diff --git a/compiler/ncgflw.pas b/compiler/ncgflw.pas index 54bc26041b..42e98e107f 100644 --- a/compiler/ncgflw.pas +++ b/compiler/ncgflw.pas @@ -148,6 +148,7 @@ implementation oldflowcontrol:=flowcontrol; oldclabel:=current_procinfo.CurrContinueLabel; oldblabel:=current_procinfo.CurrBreakLabel; + include(flowcontrol,fc_inflowcontrol); sync_regvars(true); {$ifdef OLDREGVARS} @@ -199,7 +200,7 @@ implementation 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]); + flowcontrol:=oldflowcontrol+(flowcontrol-[fc_break,fc_continue,fc_inflowcontrol]); end; @@ -211,6 +212,7 @@ implementation var hl,otlabel,oflabel : tasmlabel; + oldflowcontrol: tflowcontrol; (* org_regvar_loaded_other, then_regvar_loaded_other, @@ -226,6 +228,8 @@ implementation begin location_reset(location,LOC_VOID,OS_NO); + oldflowcontrol := flowcontrol; + include(flowcontrol,fc_inflowcontrol); otlabel:=current_procinfo.CurrTrueLabel; oflabel:=current_procinfo.CurrFalseLabel; current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel); @@ -359,6 +363,7 @@ implementation current_procinfo.CurrTrueLabel:=otlabel; current_procinfo.CurrFalseLabel:=oflabel; + flowcontrol := oldflowcontrol + (flowcontrol - [fc_inflowcontrol]); end; @@ -416,6 +421,7 @@ implementation begin location_reset(location,LOC_VOID,OS_NO); oldflowcontrol:=flowcontrol; + include(flowcontrol,fc_inflowcontrol); oldclabel:=current_procinfo.CurrContinueLabel; oldblabel:=current_procinfo.CurrBreakLabel; current_asmdata.getjumplabel(current_procinfo.CurrContinueLabel); @@ -759,7 +765,7 @@ implementation 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]); + flowcontrol:=oldflowcontrol+(flowcontrol-[fc_break,fc_continue,fc_inflowcontrol]); end; @@ -830,6 +836,7 @@ implementation begin location_reset(location,LOC_VOID,OS_NO); + include(flowcontrol,fc_gotolabel); {$ifdef OLDREGVARS} load_all_regvars(current_asmdata.CurrAsmList); {$endif OLDREGVARS} @@ -853,6 +860,7 @@ implementation begin location_reset(location,LOC_VOID,OS_NO); + include(flowcontrol,fc_gotolabel); {$ifdef OLDREGVARS} load_all_regvars(current_asmdata.CurrAsmList); {$endif OLDREGVARS} diff --git a/compiler/ncgld.pas b/compiler/ncgld.pas index 94b7df066f..31ca36a100 100644 --- a/compiler/ncgld.pas +++ b/compiler/ncgld.pas @@ -557,6 +557,8 @@ implementation end else begin + { SSA support } + maybechangeloadnodereg(left); case right.location.loc of LOC_CONSTANT : begin diff --git a/compiler/ncgset.pas b/compiler/ncgset.pas index 9188001785..557ec2cab8 100644 --- a/compiler/ncgset.pas +++ b/compiler/ncgset.pas @@ -683,6 +683,7 @@ implementation procedure tcgcasenode.pass_2; var + oldflowcontrol: tflowcontrol; i : longint; lv,hv, max_label: tconstexprint; @@ -695,6 +696,8 @@ implementation begin location_reset(location,LOC_VOID,OS_NO); + oldflowcontrol := flowcontrol; + include(flowcontrol,fc_inflowcontrol); { Allocate labels } current_asmdata.getjumplabel(endlabel); current_asmdata.getjumplabel(elselabel); @@ -862,6 +865,7 @@ implementation { Reset labels } for i:=0 to blocks.count-1 do pcaseblock(blocks[i])^.blocklabel:=nil; + flowcontrol := oldflowcontrol + (flowcontrol - [fc_inflowcontrol]); end; diff --git a/compiler/ncgutil.pas b/compiler/ncgutil.pas index 7da4769824..24e69b4460 100644 --- a/compiler/ncgutil.pas +++ b/compiler/ncgutil.pas @@ -101,6 +101,9 @@ interface // procedure get_used_regvars_common(n: tnode; var rv: tusedregvarscommon); procedure gen_sync_regvars(list:TAsmList; var rv: tusedregvars); + { if the result of n is a LOC_C(..)REGISTER, try to find the corresponding } + { loadn and change its location to a new register (= SSA) } + procedure maybechangeloadnodereg(var n: tnode); {# Allocate the buffers for exception management and setjmp environment. @@ -167,6 +170,9 @@ implementation {$ifdef powerpc64} , cpupi {$endif} +{$ifdef SUPPORT_MMX} + , cgx86 +{$endif SUPPORT_MMX} ; @@ -2240,6 +2246,135 @@ implementation end; +{***************************************************************************** + SSA support +*****************************************************************************} + + type + preplaceregrec = ^treplaceregrec; + treplaceregrec = record + old, new: tregister; +{$ifndef cpu64bit} + oldhi, newhi: tregister; +{$endif cpu64bit} + ressym: tsym; + end; + + + function doreplace(var n: tnode; para: pointer): foreachnoderesult; + var + rr: preplaceregrec absolute para; + begin + result := fen_false; + case n.nodetype of + loadn: + begin + if (tabstractvarsym(tloadnode(n).symtableentry).varoptions * [vo_is_dll_var, vo_is_thread_var] = []) and + not assigned(tloadnode(n).left) and + (((tloadnode(n).symtableentry <> rr^.ressym) and + not(vo_is_funcret in tabstractvarsym(tloadnode(n).symtableentry).varoptions)) or + not(fc_exit in flowcontrol)) and + (tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.loc in [LOC_CREGISTER,LOC_CFPUREGISTER,LOC_CMMXREGISTER,LOC_CMMREGISTER]) and + (tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.register = rr^.old) then + begin +{$ifndef cpu64bit} + { it's possible a 64 bit location was shifted and/xor typecasted } + { in a 32 bit value, so only 1 register was left in the location } + if (tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.size in [OS_64,OS_S64]) then + if (tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.register64.reghi = rr^.oldhi) then + tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.register64.reghi := rr^.newhi + else + exit; +{$endif cpu64bit} + tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.register := rr^.new; + result := fen_norecurse_true; + end; + end; + temprefn: + begin + if (ttemprefnode(n).tempinfo^.valid) and + (ttemprefnode(n).tempinfo^.location.loc in [LOC_CREGISTER,LOC_CFPUREGISTER,LOC_CMMXREGISTER,LOC_CMMREGISTER]) and + (ttemprefnode(n).tempinfo^.location.register = rr^.old) then + begin +{$ifndef cpu64bit} + { it's possible a 64 bit location was shifted and/xor typecasted } + { in a 32 bit value, so only 1 register was left in the location } + if (ttemprefnode(n).tempinfo^.location.size in [OS_64,OS_S64]) then + if (ttemprefnode(n).tempinfo^.location.register64.reghi = rr^.oldhi) then + ttemprefnode(n).tempinfo^.location.register64.reghi := rr^.newhi + else + exit; +{$endif cpu64bit} + ttemprefnode(n).tempinfo^.location.register := rr^.new; + result := fen_norecurse_true; + end; + end; + end; + end; + + + procedure maybechangeloadnodereg(var n: tnode); + var + rr: treplaceregrec; + begin + if not (n.location.loc in [LOC_CREGISTER,LOC_CFPUREGISTER,LOC_CMMXREGISTER,LOC_CMMREGISTER]) or + ([fc_inflowcontrol,fc_gotolabel] * flowcontrol <> []) then + exit; + rr.old := n.location.register; + rr.ressym := nil; + {$ifndef cpu64bit} + rr.oldhi := NR_NO; + {$endif cpu64bit} + case n.location.loc of + LOC_CREGISTER: + begin + {$ifndef cpu64bit} + if (n.location.size in [OS_64,OS_S64]) then + begin + rr.oldhi := n.location.register64.reghi; + rr.new := cg.getintregister(current_asmdata.CurrAsmList,OS_INT); + rr.newhi := cg.getintregister(current_asmdata.CurrAsmList,OS_INT); + end + else + {$endif cpu64bit} + rr.new := cg.getintregister(current_asmdata.CurrAsmList,n.location.size); + end; + LOC_CFPUREGISTER: + rr.new := cg.getfpuregister(current_asmdata.CurrAsmList,n.location.size); + {$ifdef SUPPORT_MMX} + LOC_CMMXREGISTER: + rr.new := tcgx86(cg).getmmxregister(current_asmdata.CurrAsmList); + {$endif SUPPORT_MMX} + LOC_CMMREGISTER: + rr.new := cg.getmmregister(current_asmdata.CurrAsmList,n.location.size); + else + exit; + end; + + if (current_procinfo.procdef.funcretloc[calleeside].loc<>LOC_VOID) and + assigned(current_procinfo.procdef.funcretsym) and + (tabstractvarsym(current_procinfo.procdef.funcretsym).refs <> 0) then + if (current_procinfo.procdef.proctypeoption=potype_constructor) then + rr.ressym:=tsym(current_procinfo.procdef.parast.search('self')) + else + rr.ressym:=current_procinfo.procdef.funcretsym; + + if not foreachnodestatic(n,@doreplace,@rr) then + exit; + + { now that we've change the loadn/temp, also change the node result location } + {$ifndef cpu64bit} + if (n.location.size in [OS_64,OS_S64]) then + begin + n.location.register64.reglo := rr.new; + n.location.register64.reghi := rr.newhi; + end + else + {$endif cpu64bit} + n.location.register := rr.new; + end; + + procedure gen_free_symtable(list:TAsmList;st:tsymtable); var sym : tsym; diff --git a/compiler/pass_2.pas b/compiler/pass_2.pas index f6361eeb02..b6c4754b1f 100644 --- a/compiler/pass_2.pas +++ b/compiler/pass_2.pas @@ -29,7 +29,7 @@ uses node; type - tenumflowcontrol = (fc_exit,fc_break,fc_continue); + tenumflowcontrol = (fc_exit,fc_break,fc_continue,fc_inflowcontrol,fc_gotolabel); tflowcontrol = set of tenumflowcontrol; var