{ $Id$ 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,aasmcpu, node, symsym, cpubase, cginfo, tgobj, rgobj; procedure assign_regvars(p: tnode); procedure load_regvars(asml: TAAsmoutput; p: tnode); procedure cleanup_regvars(asml: TAAsmoutput); procedure store_regvar(asml: TAAsmoutput; reg: tregister); procedure load_regvar(asml: TAAsmoutput; vsym: tvarsym); procedure load_regvar_reg(asml: TAAsmoutput; reg: tregister); procedure load_all_regvars(asml: TAAsmoutput); procedure free_regvars(list: taasmoutput); procedure translate_regvars(list: taasmoutput; const table:Ttranstable); {$ifdef i386} procedure sync_regvars_other(list1, list2: taasmoutput; const regvarsloaded1, regvarsloaded2: regvarother_booleanarray); procedure sync_regvars_int(list1, list2: taasmoutput; const regvarsloaded1, regvarsloaded2: Tsuperregisterset); {$endif i386} implementation uses globtype,systems,comphook, cutils,cclasses,verbose,globals, psub, symconst,symbase,symtype,symdef,paramgr,defutil, cpuinfo,cgbase,cgobj,rgcpu; procedure searchregvars(p : tnamedindexitem;arg:pointer); var i,j,k : longint; parasym : boolean; begin parasym:=pboolean(arg)^; if (tsym(p).typ=varsym) and (vo_regable in tvarsym(p).varoptions) then begin j:=tvarsym(p).refs; { parameter get a less value } if parasym then begin if cs_littlesize in aktglobalswitches then dec(j,1) else dec(j,100); end; { 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]:=tvarsym(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 (vo_fpuregable in tvarsym(p).varoptions) then begin j:=tvarsym(p).refs; { parameter get a less value } if parasym then begin if cs_littlesize in aktglobalswitches then dec(j,1) else dec(j,100); end; { 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]:=tvarsym(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_regvars in aktglobalswitches) and {$ifndef i386} { we have to store regvars back to memory in this case! } (tcgprocinfo(current_procinfo).nestedprocs.count = 0) and {$endif i386} not(pi_uses_asm 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.registers32 100)) then begin { register is no longer available for } { expressions } { search the register which is the most } { unused } { call by reference/const ? } if (regvarinfo^.regvars[i].varspez in [vs_var,vs_out]) or ((regvarinfo^.regvars[i].varspez=vs_const) and paramanager.push_addr_param(regvarinfo^.regvars[i].vartype.def,current_procinfo.procdef.proccalloption)) then siz:=OS_32 else if (regvarinfo^.regvars[i].vartype.def.deftype in [orddef,enumdef]) and (regvarinfo^.regvars[i].vartype.def.size=1) then siz:=OS_8 else if (regvarinfo^.regvars[i].vartype.def.deftype in [orddef,enumdef]) and (regvarinfo^.regvars[i].vartype.def.size=2) then siz:=OS_16 else siz:=OS_32; { allocate a register for this regvar } regvarinfo^.regvars[i].reg:=rg.getregisterint(exprasmlist,siz); { and make sure it can't be freed } rg.makeregvarint(getsupreg(regvarinfo^.regvars[i].reg)); end else begin regvarinfo^.regvars[i] := nil; regvarinfo^.regvars_para[i] := false; end; end; end; if ((p.registersfpu+1) tvarsym(current_procinfo.procdef.funcretsym))} then begin { make sure the unget isn't just a nop } exclude(rg.is_reg_var_int,getsupreg(regvars[i].reg)); rg.ungetregisterint(list,regvars[i].reg); end; end; procedure translate_regvars(list: taasmoutput; const table:Ttranstable); var i: longint; r: tregister; begin if not assigned(current_procinfo.procdef.regvarinfo) then exit; with pregvarinfo(current_procinfo.procdef.regvarinfo)^ do for i := 1 to maxvarregs do if assigned(regvars[i]) { and (regvars[i] <> tvarsym(current_procinfo.procdef.funcretsym))} then begin setsupreg(regvars[i].reg,getsupreg(table[getsupreg(regvars[i].reg)])); r:=regvars[i].reg; if cs_asm_source in aktglobalswitches then list.insert(tai_comment.Create(strpnew(regvars[i].name+ ' with weight '+tostr(regvars[i].refs)+' assigned to register '+ std_regname(r)))); Message3(cg_d_register_weight,std_regname(r), tostr(regvars[i].refs),regvars[i].name); end; end; end. { $Log$ Revision 1.63 2003-09-03 15:55:01 peter * NEWRA branch merged Revision 1.62.2.2 2003/08/29 17:28:59 peter * next batch of updates Revision 1.62.2.1 2003/08/28 18:35:08 peter * tregister changed to cardinal Revision 1.62 2003/08/17 20:47:47 daniel * Notranslation changed into -sr functionality Revision 1.61 2003/08/17 16:59:20 jonas * fixed regvars so they work with newra (at least for ppc) * fixed some volatile register bugs + -dnotranslation option for -dnewra, which causes the registers not to be translated from virtual to normal registers. Requires support in the assembler writer as well, which is only implemented in aggas/ agppcgas currently Revision 1.60 2003/08/11 21:18:20 peter * start of sparc support for newra Revision 1.59 2003/08/09 18:56:54 daniel * cs_regalloc renamed to cs_regvars to avoid confusion with register allocator * Some preventive changes to i386 spillinh code Revision 1.58 2003/07/02 22:18:04 peter * paraloc splitted in callerparaloc,calleeparaloc * sparc calling convention updates Revision 1.57 2003/06/13 21:19:31 peter * current_procdef removed, use current_procinfo.procdef instead Revision 1.56 2003/06/07 18:57:04 jonas + added freeintparaloc * ppc get/freeintparaloc now check whether the parameter regs are properly allocated/deallocated (and get an extra list para) * ppc a_call_* now internalerrors if pi_do_call is not yet set * fixed lot of missing pi_do_call's Revision 1.55 2003/06/03 21:11:09 peter * cg.a_load_* get a from and to size specifier * makeregsize only accepts newregister * i386 uses generic tcgnotnode,tcgunaryminus Revision 1.54 2003/06/03 13:01:59 daniel * Register allocator finished Revision 1.53 2003/05/31 20:33:57 jonas * temp fix/hack for nested procedures (disable regvars in all procedures that have nested procedures) * leave register parameters in their own register (instead of storing them to memory or assigning them to another register) if the current procedure doesn't call any other procedures Revision 1.52 2003/05/30 18:55:21 jonas * fixed several regvar related bugs for non-i386. make cycle with -Or now works for ppc Revision 1.51 2003/05/23 14:27:35 peter * remove some unit dependencies * current_procinfo changes to store more info Revision 1.50 2003/05/16 14:33:31 peter * regvar fixes Revision 1.49 2003/05/15 18:58:53 peter * removed selfpointer_offset, vmtpointer_offset * tvarsym.adjusted_address * address in localsymtable is now in the real direction * removed some obsolete globals Revision 1.48 2003/05/12 17:22:00 jonas * fixed (last?) remaining -tvarsym(X).address to tg.direction*tvarsym(X).address... Revision 1.47 2003/04/27 11:21:34 peter * aktprocdef renamed to current_procinfo.procdef * procinfo renamed to current_procinfo * procinfo will now be stored in current_module so it can be cleaned up properly * gen_main_procsym changed to create_main_proc and release_main_proc to also generate a tprocinfo structure * fixed unit implicit initfinal Revision 1.46 2003/03/28 19:16:57 peter * generic constructor working for i386 * remove fixed self register * esi added as address register for i386 Revision 1.45 2003/02/19 22:00:14 daniel * Code generator converted to new register notation - Horribily outdated todo.txt removed Revision 1.44 2003/01/08 18:43:57 daniel * Tregister changed into a record Revision 1.43 2002/11/25 17:43:24 peter * splitted defbase in defutil,symutil,defcmp * merged isconvertable and is_equal into compare_defs(_ext) * made operator search faster by walking the list only once Revision 1.42 2002/11/18 17:31:59 peter * pass proccalloption to ret_in_xxx and push_xxx functions Revision 1.41 2002/08/25 19:25:20 peter * sym.insert_in_data removed * symtable.insertvardata/insertconstdata added * removed insert_in_data call from symtable.insert, it needs to be called separatly. This allows to deref the address calculation * procedures now calculate the parast addresses after the procedure directives are parsed. This fixes the cdecl parast problem * push_addr_param has an extra argument that specifies if cdecl is used or not Revision 1.40 2002/08/18 20:06:25 peter * inlining is now also allowed in interface * renamed write/load to ppuwrite/ppuload * tnode storing in ppu * nld,ncon,nbas are already updated for storing in ppu Revision 1.39 2002/08/17 09:23:41 florian * first part of procinfo rewrite Revision 1.38 2002/08/06 20:55:22 florian * first part of ppc calling conventions fix Revision 1.37 2002/07/20 11:57:57 florian * types.pas renamed to defbase.pas because D6 contains a types unit so this would conflicts if D6 programms are compiled + Willamette/SSE2 instructions to assembler added Revision 1.36 2002/07/11 14:41:30 florian * start of the new generic parameter handling Revision 1.35 2002/07/01 18:46:25 peter * internal linker * reorganized aasm layer Revision 1.34 2002/06/24 12:43:00 jonas * fixed errors found with new -CR code from Peter when cycling with -O2p3r Revision 1.33 2002/05/18 13:34:17 peter * readded missing revisions Revision 1.32 2002/05/16 19:46:44 carl + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand + try to fix temp allocation (still in ifdef) + generic constructor calls + start of tassembler / tmodulebase class cleanup Revision 1.30 2002/05/12 16:53:10 peter * moved entry and exitcode to ncgutil and cgobj * foreach gets extra argument for passing local data to the iterator function * -CR checks also class typecasts at runtime by changing them into as * fixed compiler to cycle with the -CR option * fixed stabs with elf writer, finally the global variables can be watched * removed a lot of routines from cga unit and replaced them by calls to cgobj * u32bit-s32bit updates for and,or,xor nodes. When one element is u32bit then the other is typecasted also to u32bit without giving a rangecheck warning/error. * fixed pascal calling method with reversing also the high tree in the parast, detected by tcalcst3 test Revision 1.29 2002/04/21 15:23:34 carl + changeregsize -> makeregsize Revision 1.28 2002/04/19 15:46:03 peter * mangledname rewrite, tprocdef.mangledname is now created dynamicly in most cases and not written to the ppu * add mangeledname_prefix() routine to generate the prefix of manglednames depending on the current procedure, object and module * removed static procprefix since the mangledname is now build only on demand from tprocdef.mangledname Revision 1.27 2002/04/15 19:44:19 peter * fixed stackcheck that would be called recursively when a stack error was found * generic changeregsize(reg,size) for i386 register resizing * removed some more routines from cga unit * fixed returnvalue handling * fixed default stacksize of linux and go32v2, 8kb was a bit small :-) Revision 1.26 2002/04/15 19:04:04 carl + reg2str -> std_reg2str() Revision 1.25 2002/04/06 18:13:01 jonas * several powerpc-related additions and fixes Revision 1.24 2002/04/02 17:11:29 peter * tlocation,treference update * LOC_CONSTANT added for better constant handling * secondadd splitted in multiple routines * location_force_reg added for loading a location to a register of a specified size * secondassignment parses now first the right and then the left node (this is compatible with Kylix). This saves a lot of push/pop especially with string operations * adapted some routines to use the new cg methods Revision 1.23 2002/03/31 20:26:36 jonas + a_loadfpu_* and a_loadmm_* methods in tcg * register allocation is now handled by a class and is mostly processor independent (+rgobj.pas and i386/rgcpu.pas) * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas) * some small improvements and fixes to the optimizer * some register allocation fixes * some fpuvaroffset fixes in the unary minus node * push/popusedregisters is now called rg.save/restoreusedregisters and (for i386) uses temps instead of push/pop's when using -Op3 (that code is also better optimizable) * fixed and optimized register saving/restoring for new/dispose nodes * LOC_FPU locations now also require their "register" field to be set to R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only) - list field removed of the tnode class because it's not used currently and can cause hard-to-find bugs }