diff options
Diffstat (limited to 'closures/compiler/regvars.pas')
-rw-r--r-- | closures/compiler/regvars.pas | 666 |
1 files changed, 666 insertions, 0 deletions
diff --git a/closures/compiler/regvars.pas b/closures/compiler/regvars.pas new file mode 100644 index 0000000000..1576d25536 --- /dev/null +++ b/closures/compiler/regvars.pas @@ -0,0 +1,666 @@ +{ + Copyright (c) 1998-2002 by Florian Klaempfl and Jonas Maebe + + This unit handles register variable allocation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + **************************************************************************** +} +unit regvars; + +{$i fpcdefs.inc} + +interface + + uses + aasmbase,aasmtai,aasmdata,aasmcpu, + node, + symsym, + cpubase, cgbase, tgobj; + +{$ifdef OLDREGVARS} + procedure assign_regvars(p: tnode); + procedure load_regvars(asml: TAsmList; p: tnode); + procedure cleanup_regvars(asml: TAsmList); + procedure store_regvar(asml: TAsmList; reg: tregister); + procedure load_regvar(asml: TAsmList; vsym: tvarsym); + procedure load_regvar_reg(asml: TAsmList; reg: tregister); + procedure load_all_regvars(asml: TAsmList); + procedure free_regvars(list: TAsmList); +{ procedure translate_regvars(list: TAsmList); } +{$endif OLDREGVARS} + +{$ifdef i386} +(* + procedure sync_regvars_other(list1, list2: TAsmList; const regvarsloaded1, + regvarsloaded2: regvarother_booleanarray); + procedure sync_regvars_int(list1, list2: TAsmList; const regvarsloaded1, + regvarsloaded2: Tsuperregisterset); +*) +{$endif i386} + +implementation + + uses + globtype,systems,comphook, + cutils,cclasses,verbose,globals, + psub, + symconst,symbase,symtype,symdef,paramgr,defutil, + cpuinfo,cgobj,procinfo; + +{$ifdef OLDREGVARS} + procedure searchregvars(p : tnamedindexitem;arg:pointer); + var + i,j,k : longint; + parasym : boolean; + begin + parasym:=pboolean(arg)^; + if (tsym(p).typ=varsym) and ((tvarsym(p).varregable <> vr_none) or + ((tvarsym(p).varspez in [vs_var,vs_const,vs_out,vs_constref]) and + paramanager.push_addr_param(tvarsym(p).varspez,tvarsym(p).vardef,current_procinfo.procdef.proccalloption))) and + not tvarsym(p).vardef.needs_inittable then + begin + j:=tvarsym(p).refs; + { walk through all momentary register variables } + for i:=1 to maxvarregs do + begin + with pregvarinfo(current_procinfo.procdef.regvarinfo)^ do + if ((regvars[i]=nil) or (j>regvars_refs[i])) and (j>0) then + begin + for k:=maxvarregs-1 downto i do + begin + regvars[k+1]:=regvars[k]; + regvars_para[k+1]:=regvars_para[k]; + regvars_refs[k+1]:=regvars_refs[k]; + end; + { calc the new refs + tvarsym(p).refs:=j; } + regvars[i]:=tsym(p); + regvars_para[i]:=parasym; + regvars_refs[i]:=j; + break; + end; + end; + end; + end; + + + procedure searchfpuregvars(p : tnamedindexitem;arg:pointer); + var + i,j,k : longint; + parasym : boolean; + begin + parasym:=pboolean(arg)^; + if (tsym(p).typ=varsym) and (tvarsym(p).varregable <> vr_none) then + begin + j:=tvarsym(p).refs; + { parameter get a less value } + { walk through all momentary register variables } + for i:=1 to maxfpuvarregs do + begin + with pregvarinfo(current_procinfo.procdef.regvarinfo)^ do + if ((fpuregvars[i]=nil) or (j>fpuregvars_refs[i])) and (j>0) then + begin + for k:=maxfpuvarregs-1 downto i do + begin + fpuregvars[k+1]:=fpuregvars[k]; + fpuregvars_para[k+1]:=fpuregvars_para[k]; + fpuregvars_refs[k+1]:=fpuregvars_refs[k]; + end; + { calc the new refs + tvarsym(p).refs:=j; } + fpuregvars[i]:=tsym(p); + fpuregvars_para[i]:=parasym; + fpuregvars_refs[i]:=j; + break; + end; + end; + end; + end; + + procedure assign_regvars(p: tnode); + { register variables } + var +{$ifndef i386} + hp: tparaitem; +{$endif i386} + regvarinfo: pregvarinfo; + i: longint; + parasym : boolean; + siz : tcgsize; + begin + { max. optimizations } + { only if no asm is used } + { and no try statement } + if (cs_opt_regvar in current_settings.optimizerswitches) and + { we have to store regvars back to memory in this case (the nested } + { procedures can access the variables of the parent) } + (not current_procinfo.has_nestedprocs) and + not(pi_has_assembler_block in current_procinfo.flags) and + not(pi_uses_exceptions in current_procinfo.flags) then + begin + new(regvarinfo); + fillchar(regvarinfo^,sizeof(regvarinfo^),0); + current_procinfo.procdef.regvarinfo := regvarinfo; + if (p.registersint<maxvarregs) then + begin + parasym:=false; + symtablestack.foreach_static(searchregvars,@parasym); + { copy parameter into a register ? } + parasym:=true; + symtablestack.next.foreach_static(searchregvars,@parasym); + { hold needed registers free } + for i:=maxvarregs downto maxvarregs-p.registersint+1 do + begin + regvarinfo^.regvars[i]:=nil; + regvarinfo^.regvars_para[i] := false; + end; + { now assign register } + for i:=1 to maxvarregs-p.registersint do + begin + if assigned(regvarinfo^.regvars[i]) and + { currently we assume we can use registers for all } + { regvars if procedure does no call } + (not(pi_do_call in current_procinfo.flags) or + { otherwise, demand some (arbitrary) minimum usage } + (tvarsym(regvarinfo^.regvars[i]).refs > 100)) then + begin + { register is no longer available for } + { expressions } + { search the register which is the most } + { unused } + + { call by reference/const ? } + if paramanager.push_addr_param(tvarsym(regvarinfo^.regvars[i]).varspez,tvarsym(regvarinfo^.regvars[i]).vardef,current_procinfo.procdef.proccalloption) then + siz:=OS_32 + else + if (tvarsym(regvarinfo^.regvars[i]).vardef.typ in [orddef,enumdef]) and + (tvarsym(regvarinfo^.regvars[i]).vardef.size=1) then + siz:=OS_8 + else + if (tvarsym(regvarinfo^.regvars[i]).vardef.typ in [orddef,enumdef]) and + (tvarsym(regvarinfo^.regvars[i]).vardef.size=2) then + siz:=OS_16 + else + siz:=OS_32; + + { allocate a register for this regvar } + tvarsym(regvarinfo^.regvars[i]).localloc.register:=cg.getintregister(current_asmdata.CurrAsmList,siz); + tvarsym(regvarinfo^.regvars[i]).localloc.loc:=LOC_REGISTER; + { and make sure it can't be freed } +{ rg.makeregvarint(getsupreg(regvarinfo^.regvars[i].localloc.register));} + end + else + begin + regvarinfo^.regvars[i] := nil; + regvarinfo^.regvars_para[i] := false; + end; + end; + end; + if ((p.registersfpu+1)<maxfpuvarregs) then + begin + parasym:=false; + symtablestack.foreach_static(searchfpuregvars,@parasym); +{$ifndef i386} + { this code should be never enabled because } + { 1. the caller loads parameters into registers } + { 2. (later) the CSE loads a parameter into a } + { register, if necessary } + { (FK) } + { copy parameter into a register ? } + parasym:=true; + symtablestack.next.foreach_static(searchregvars,@parasym); +{$endif i386} + { hold needed registers free } + + { in non leaf procedures we must be very careful } + { with assigning registers } +{$ifdef i386} + if current_settings.maxfpuregisters=-1 then + begin + if (pi_do_call in current_procinfo.flags) then + begin + for i:=maxfpuvarregs downto 2 do + regvarinfo^.fpuregvars[i]:=nil; + end + else +{$endif i386} + begin + for i:=maxfpuvarregs downto maxfpuvarregs-p.registersfpu do + regvarinfo^.fpuregvars[i]:=nil; + end; +{$ifdef i386} + end + else + begin + for i:=current_settings.maxfpuregisters+1 to maxfpuvarregs do + regvarinfo^.fpuregvars[i]:=nil; + end; +{$endif i386} + { now assign register } + for i:=1 to maxfpuvarregs do + begin + if assigned(regvarinfo^.fpuregvars[i]) then + begin +{$ifdef i386} + { reserve place on the FPU stack } + {$error fixme x86 fpuregvars} +{ regvarinfo^.fpuregvars[i].localloc.register:=trgcpu(rg).correct_fpuregister(NR_ST0,i);} +{$else i386} +{$ifdef x86_64} +{$endif x86_64} + begin + tvarsym(regvarinfo^.fpuregvars[i]).localloc.register:=cg.getfpuregister(current_asmdata.CurrAsmList,OS_F64); + tvarsym(regvarinfo^.fpuregvars[i]).localloc.loc:=LOC_FPUREGISTER; +{ rg.makeregvarother(regvarinfo^.fpuregvars[i].localloc.register);} + end; +{$endif i386} + end; + end; + end; + end; + end; + + + + procedure store_regvar(asml: TAsmList; reg: tregister); + var + i: longint; + cgsize : tcgsize; + r : tregister; + hr: treference; + regvarinfo: pregvarinfo; + vsym: tvarsym; + regidx : tregisterindex; + supreg : tsuperregister; + begin +{$ifdef i386} + regvarinfo := pregvarinfo(current_procinfo.procdef.regvarinfo); + if not assigned(regvarinfo) then + exit; + if getregtype(reg)=R_INTREGISTER then + begin + supreg:=getsupreg(reg); + for i := 1 to maxvarregs do + if assigned(regvarinfo^.regvars[i]) and + (getsupreg(tvarsym(regvarinfo^.regvars[i]).localloc.register)=supreg) then + begin + { TODO: fixme regvar_loaded_int} +(* if supreg in rg.regvar_loaded_int then + begin + vsym := tvarsym(regvarinfo^.regvars[i]); + { we only have to store the regvar back to memory if it's } + { possible that it's been modified (JM) } + if not(vsym.varspez in [vs_const,vs_var,vs_out]) then + begin +{ TODO: FIXME Check vsym.localloc for regvars} +// reference_reset_base(hr,current_procinfo.framepointer,vsym.adjusted_address); + cgsize:=def_cgsize(vsym.vardef); + cg.a_load_reg_ref(asml,cgsize,cgsize,vsym.localloc.register,hr); + end; + asml.concat(tai_regalloc.dealloc(vsym.localloc.register)); + exclude(rg.regvar_loaded_int,supreg); + end; +*) + break; + end; + end + else + begin + for i := 1 to maxvarregs do + if assigned(regvarinfo^.regvars[i]) then + begin + { TODO: fixme regvars} +(* + r:=rg.makeregsize(regvarinfo^.regvars[i].localloc.register,OS_INT); + if (r = reg) then + begin + regidx:=findreg_by_number(r); + if rg.regvar_loaded_other[regidx] then + begin + vsym := tvarsym(regvarinfo^.regvars[i]); + { we only have to store the regvar back to memory if it's } + { possible that it's been modified (JM) } + if not(vsym.varspez in [vs_const,vs_var,vs_out]) then + begin +{ TODO: FIXME Check vsym.localloc for regvars} +// reference_reset_base(hr,current_procinfo.framepointer,vsym.adjusted_address); + cgsize:=def_cgsize(vsym.vardef); + cg.a_load_reg_ref(asml,cgsize,cgsize,vsym.localloc.register,hr); + end; + asml.concat(tai_regalloc.dealloc(vsym.localloc.register)); + rg.regvar_loaded_other[regidx] := false; + end; + break; + end; +*) + end; + end; +{$endif i386} + end; + + procedure load_regvar(asml: TAsmList; vsym: tvarsym); + var + hr: treference; + opsize: tcgsize; + r, + reg : tregister; + regidx : tregisterindex; + begin +{$ifndef i386} + exit; +{$endif i386} + reg:=vsym.localloc.register; + { TODO: fixme regvars} +(* + if getregtype(reg)=R_INTREGISTER then + begin + + if not(getsupreg(reg) in rg.regvar_loaded_int) then + begin + asml.concat(tai_regalloc.alloc(reg)); +{ TODO: FIXME Check vsym.localloc for regvars} +// reference_reset_base(hr,current_procinfo.framepointer,vsym.adjusted_address); + if paramanager.push_addr_param(vsym.varspez,vsym.vardef,current_procinfo.procdef.proccalloption) then + opsize := OS_ADDR + else + opsize := def_cgsize(vsym.vardef); + cg.a_load_ref_reg(asml,opsize,opsize,hr,reg); + include(rg.regvar_loaded_int,getsupreg(reg)); + end; + end + else + begin + r:=rg.makeregsize(reg,OS_INT); + regidx:=findreg_by_number(r); + if not rg.regvar_loaded_other[regidx] then + begin + asml.concat(tai_regalloc.alloc(reg)); +{ TODO: FIXME Check vsym.localloc for regvars} +// reference_reset_base(hr,current_procinfo.framepointer,vsym.adjusted_address); + if paramanager.push_addr_param(vsym.varspez,vsym.vardef,current_procinfo.procdef.proccalloption) then + opsize := OS_ADDR + else + opsize := def_cgsize(vsym.vardef); + cg.a_load_ref_reg(asml,opsize,opsize,hr,reg); + rg.regvar_loaded_other[regidx] := true; + end; + end; +*) + end; + + procedure load_regvar_reg(asml: TAsmList; reg: tregister); + var + i: longint; + regvarinfo: pregvarinfo; + reg_spare : tregister; + supreg : tsuperregister; + begin +{ + regvarinfo := pregvarinfo(current_procinfo.procdef.regvarinfo); + if not assigned(regvarinfo) then + exit; + if getregtype(reg)=R_INTREGISTER then + begin + supreg:=getsupreg(reg); + for i := 1 to maxvarregs do + if assigned(regvarinfo^.regvars[i]) and + (getsupreg(regvarinfo^.regvars[i].localloc.register) = supreg) then + load_regvar(asml,tvarsym(regvarinfo^.regvars[i])) + end + else + begin + reg_spare := cg.makeregsize(reg,OS_INT); + for i := 1 to maxvarregs do + if assigned(regvarinfo^.regvars[i]) and + (cg.makeregsize(regvarinfo^.regvars[i].localloc.register,OS_INT) = reg_spare) then + load_regvar(asml,tvarsym(regvarinfo^.regvars[i])) + end; +} + end; + + procedure load_all_regvars(asml: TAsmList); +{ + var + i: longint; + regvarinfo: pregvarinfo; +} + begin +{ + regvarinfo := pregvarinfo(current_procinfo.procdef.regvarinfo); + if not assigned(regvarinfo) then + exit; + for i := 1 to maxvarregs do + if assigned(regvarinfo^.regvars[i]) then + load_regvar(asml,tvarsym(regvarinfo^.regvars[i])) +} + end; + + + procedure load_regvars(asml: TAsmList; p: tnode); + var + i: longint; + regvarinfo: pregvarinfo; + begin + if (cs_opt_regvar in current_settings.optimizerswitches) and + not(pi_has_assembler_block in current_procinfo.flags) and + not(pi_uses_exceptions in current_procinfo.flags) then + begin + regvarinfo := pregvarinfo(current_procinfo.procdef.regvarinfo); + { can happen when inlining assembler procedures (JM) } + if not assigned(regvarinfo) then + exit; + for i:=1 to maxfpuvarregs do + begin + if assigned(regvarinfo^.fpuregvars[i]) then + begin +{$ifdef i386} + { reserve place on the FPU stack } + { TODO: fixme fpustack} +(* + regvarinfo^.fpuregvars[i].localloc.register:=trgcpu(rg).correct_fpuregister(NR_ST0,i-1); +*) + asml.concat(Taicpu.op_none(A_FLDZ,S_NO)); +{$endif i386} + end; + end; +{$ifdef i386} + if assigned(p) then + if cs_asm_source in current_settings.globalswitches then + asml.insert(tai_comment.Create(strpnew(tostr(p.registersfpu)+ + ' registers on FPU stack used by temp. expressions'))); +{$endif i386} +{ + for i:=1 to maxfpuvarregs do + begin + if assigned(regvarinfo^.fpuregvars[i]) then + begin + if cs_asm_source in current_settings.globalswitches then + asml.insert(tai_comment.Create(strpnew(regvarinfo^.fpuregvars[i].name+ + ' with weight '+tostr(regvarinfo^.fpuregvars[i].refs)+' assigned to register '+ + std_regname(regvarinfo^.fpuregvars[i].localloc.register)))); + if (status.verbosity and v_debug)=v_debug then + Message3(cg_d_register_weight,std_regname(regvarinfo^.fpuregvars[i].localloc.register), + tostr(regvarinfo^.fpuregvars[i].refs),regvarinfo^.fpuregvars[i].name); + end; + end; + if cs_asm_source in current_settings.globalswitches then + asml.insert(tai_comment.Create(strpnew('Register variable assignment:'))); +} + end; + end; + +{$ifdef i386} +(* + procedure sync_regvars_other(list1, list2: TAsmList; const regvarsloaded1, + regvarsloaded2: regvarother_booleanarray); + var + counter: tregisterindex; + begin + for counter := low(rg.regvar_loaded_other) to high(rg.regvar_loaded_other) do + begin + rg.regvar_loaded_other[counter] := regvarsloaded1[counter] and + regvarsloaded2[counter]; + if regvarsloaded1[counter] xor regvarsloaded2[counter] then + if regvarsloaded1[counter] then + load_regvar_reg(list2,counter) + else + load_regvar_reg(list1,counter); + end; + end; + + + procedure sync_regvars_int(list1, list2: TAsmList; const regvarsloaded1, + regvarsloaded2: Tsuperregisterset); + var + i : longint; + r : tregister; + begin + for i:=1 to maxvarregs do + begin + r:=newreg(R_INTREGISTER,varregs[i],R_SUBWHOLE); + if (varregs[i] in regvarsloaded1) and + not(varregs[i] in regvarsloaded2) then + load_regvar_reg(list2,r) + else + if (varregs[i] in regvarsloaded2) and + not(varregs[i] in regvarsloaded1) then + load_regvar_reg(list1,r); + end; + end; +*) +{$endif i386} + + + procedure cleanup_regvars(asml: TAsmList); + var + i: longint; + reg : tregister; + regidx : tregisterindex; + begin + { can happen when inlining assembler procedures (JM) } + if not assigned(current_procinfo.procdef.regvarinfo) then + exit; + if (cs_opt_regvar in current_settings.optimizerswitches) and + not(pi_has_assembler_block in current_procinfo.flags) and + not(pi_uses_exceptions in current_procinfo.flags) then + with pregvarinfo(current_procinfo.procdef.regvarinfo)^ do + begin +{$ifdef i386} + for i:=1 to maxfpuvarregs do + if assigned(fpuregvars[i]) then + { ... and clean it up } + asml.concat(Taicpu.op_reg(A_FSTP,S_NO,NR_ST0)); +{$endif i386} +(* + for i := 1 to maxvarregs do + begin + if assigned(regvars[i]) then + begin + reg:=regvars[i].localloc.register; + if getregtype(reg)=R_INTREGISTER then + begin + end + else + begin + reg:=cg.makeregsize(reg,OS_INT); + regidx:=findreg_by_number(reg); + { TODO: fixme regvar dealloc} +{ + if (rg.regvar_loaded_other[regidx]) then + asml.concat(tai_regalloc.dealloc(reg)); +} + end; + end; + end; +*) + end; + end; + +{ + + Note: this one can't really be "fixed": register colouring happens after + stabs generation. It could still be useful to generate the "var X is + assigned to register Y with weight ZZZ" messages though + + procedure translate_regvars(list: TAsmList); + var + i: longint; + r: tregister; + begin + if not assigned(current_procinfo.procdef.regvarinfo) then + exit; + with pregvarinfo(current_procinfo.procdef.regvarinfo)^ do + begin + for i := 1 to maxvarregs do + if assigned(regvars[i]) then + begin + cg.rg[R_INTREGISTER].translate_register(tvarsym(regvars[i]).localloc.register); + r:=tvarsym(regvars[i]).localloc.register; + if cs_asm_source in current_settings.globalswitches then + list.insert(tai_comment.Create(strpnew(tvarsym(regvars[i]).name+ + ' with weight '+tostr(tvarsym(regvars[i]).refs)+' assigned to register '+ + std_regname(r)))); + Message3(cg_d_register_weight,std_regname(r), + tostr(tvarsym(regvars[i]).refs),tvarsym(regvars[i]).name); + end; + for i := 1 to maxfpuvarregs do + if assigned(fpuregvars[i]) then + begin + cg.rg[R_FPUREGISTER].translate_register(tvarsym(regvars[i]).localloc.register); + r:=tvarsym(fpuregvars[i]).localloc.register; + if cs_asm_source in current_settings.globalswitches then + list.insert(tai_comment.Create(strpnew(tvarsym(fpuregvars[i]).name+ + ' with weight '+tostr(tvarsym(fpuregvars[i]).refs)+' assigned to register '+ + std_regname(r)))); + Message3(cg_d_register_weight,std_regname(r), + tostr(tvarsym(fpuregvars[i]).refs),tvarsym(fpuregvars[i]).name); + end; + end; + end; +} + + procedure free_regvars(list: TAsmList); + var + i: longint; + reg: tregister; + size: tcgsize; + begin + if not assigned(current_procinfo.procdef.regvarinfo) then + exit; + with pregvarinfo(current_procinfo.procdef.regvarinfo)^ do + begin + for i := 1 to maxvarregs do + if assigned(regvars[i]) then + begin + reg:=cg.makeregsize(list,tvarsym(regvars[i]).localloc.register,OS_INT); + cg.a_load_reg_reg(list,OS_INT,OS_INT,reg,reg); + end; + for i := 1 to maxfpuvarregs do + if assigned(fpuregvars[i]) then + begin + reg:=tvarsym(fpuregvars[i]).localloc.register; + size:=reg_cgsize(reg); + cg.a_loadfpu_reg_reg(list,size,reg,reg); + end; + end; + end; + + +{$endif OLDREGVARS} + + +end. |