{ $Id$ Copyright (c) 2000-2002 by Florian Klaempfl This unit implements some basic nodes 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 ncgbas; {$i fpcdefs.inc} interface uses cpubase, node,nbas; type tcgnothingnode = class(tnothingnode) procedure pass_2;override; end; tcgasmnode = class(tasmnode) procedure pass_2;override; end; tcgstatementnode = class(tstatementnode) procedure pass_2;override; end; tcgblocknode = class(tblocknode) procedure pass_2;override; end; tcgtempcreatenode = class(ttempcreatenode) procedure pass_2;override; end; tcgtemprefnode = class(ttemprefnode) procedure pass_2;override; { Changes the location of this temp to ref. Useful when assigning } { another temp to this one. The current location will be freed. } { Can only be called in pass 2 (since earlier, the temp location } { isn't known yet) } procedure changelocation(const ref: treference); end; tcgtempdeletenode = class(ttempdeletenode) procedure pass_2;override; end; implementation uses globtype,systems, cutils,verbose,cpuinfo, aasmbase,aasmtai,aasmcpu,symsym, defutil, nflw,pass_2, cgbase,procinfo,cgobj,tgobj ; {***************************************************************************** TNOTHING *****************************************************************************} procedure tcgnothingnode.pass_2; begin location_reset(location,LOC_VOID,OS_NO); { avoid an abstract rte } end; {***************************************************************************** TSTATEMENTNODE *****************************************************************************} procedure tcgstatementnode.pass_2; var hp : tstatementnode; begin location_reset(location,LOC_VOID,OS_NO); hp:=self; while assigned(hp) do begin if assigned(hp.left) then begin secondpass(hp.left); { Compiler inserted blocks can return values } location_copy(hp.location,hp.left.location); end; hp:=tstatementnode(hp.right); end; end; {***************************************************************************** TASMNODE *****************************************************************************} procedure tcgasmnode.pass_2; procedure ReLabel(var p:tasmsymbol); begin { Only relabel local tasmlabels } if (p.defbind = AB_LOCAL) and (p is tasmlabel) then begin if not assigned(p.altsymbol) then objectlibrary.GenerateAltSymbol(p); p:=p.altsymbol; p.increfs; end; end; procedure ResolveRef(var op:toper); var sym : tvarsym; {$ifdef x86} scale : byte; {$endif x86} getoffset : boolean; indexreg : tregister; sofs : longint; begin if (op.typ=top_local) then begin sofs:=op.localsymofs; indexreg:=op.localindexreg; {$ifdef x86} scale:=op.localscale; {$endif x86} getoffset:=op.localgetoffset; sym:=tvarsym(pointer(op.localsym)); case sym.localloc.loc of LOC_REFERENCE : begin if getoffset then begin if indexreg=NR_NO then begin op.typ:=top_const; op.val:=aword(sym.localloc.reference.offset+sofs); end else begin op.typ:=top_ref; new(op.ref); reference_reset_base(op.ref^,indexreg, sym.localloc.reference.offset+sofs); end; end else begin op.typ:=top_ref; new(op.ref); reference_reset_base(op.ref^,sym.localloc.reference.index, sym.localloc.reference.offset+sofs); op.ref^.index:=indexreg; {$ifdef x86} op.ref^.scalefactor:=scale; {$endif x86} end; end; LOC_REGISTER : begin if getoffset then Message(asmr_e_invalid_reference_syntax); { Subscribed access } if sofs<>0 then begin op.typ:=top_ref; new(op.ref); reference_reset_base(op.ref^,sym.localloc.register,sofs); end else begin op.typ:=top_reg; op.reg:=sym.localloc.register; end; end; end; end; end; var hp,hp2 : tai; i : longint; skipnode : boolean; begin location_reset(location,LOC_VOID,OS_NO); if getposition then begin { Add a marker, to be sure the list is not empty } exprasmlist.concat(tai_marker.create(marker_position)); currenttai:=tai(exprasmlist.last); exit; end; { Allocate registers used in the assembler block } cg.allocexplicitregisters(exprasmlist,R_INTREGISTER,used_regs_int); if (current_procinfo.procdef.proccalloption=pocall_inline) then begin objectlibrary.CreateUsedAsmSymbolList; hp:=tai(p_asm.first); while assigned(hp) do begin hp2:=tai(hp.getcopy); skipnode:=false; case hp2.typ of ait_label : ReLabel(tasmsymbol(tai_label(hp2).l)); ait_const_rva, ait_const_symbol : ReLabel(tai_const_symbol(hp2).sym); ait_instruction : begin { remove cached insentry, because the new code can require an other less optimized instruction } {$ifdef i386} {$ifndef NOAG386BIN} taicpu(hp2).ResetPass1; {$endif} {$endif} { fixup the references } for i:=1 to taicpu(hp2).ops do begin ResolveRef(taicpu(hp2).oper[i-1]^); with taicpu(hp2).oper[i-1]^ do begin case typ of top_ref : if assigned(ref^.symbol) then ReLabel(ref^.symbol); top_symbol : ReLabel(sym); end; end; end; end; ait_marker : begin { it's not an assembler block anymore } if (tai_marker(hp2).kind in [AsmBlockStart, AsmBlockEnd]) then skipnode:=true; end; end; if not skipnode then exprasmList.concat(hp2) else hp2.free; hp:=tai(hp.next); end; { restore used symbols } objectlibrary.UsedAsmSymbolListResetAltSym; objectlibrary.DestroyUsedAsmSymbolList; end else begin hp:=tai(p_asm.first); while assigned(hp) do begin case hp.typ of ait_instruction : begin { remove cached insentry, because the new code can require an other less optimized instruction } {$ifdef i386} {$ifndef NOAG386BIN} taicpu(hp).ResetPass1; {$endif} {$endif} { fixup the references } for i:=1 to taicpu(hp).ops do ResolveRef(taicpu(hp).oper[i-1]^); end; end; hp:=tai(hp.next); end; { insert the list } exprasmList.concatlist(p_asm); end; { Release register used in the assembler block } cg.deallocexplicitregisters(exprasmlist,R_INTREGISTER,used_regs_int); end; {***************************************************************************** TBLOCKNODE *****************************************************************************} procedure tcgblocknode.pass_2; var hp : tstatementnode; begin location_reset(location,LOC_VOID,OS_NO); { do second pass on left node } if assigned(left) then begin hp:=tstatementnode(left); while assigned(hp) do begin if assigned(hp.left) then begin secondpass(hp.left); location_copy(hp.location,hp.left.location); end; location_copy(location,hp.location); hp:=tstatementnode(hp.right); end; end; end; {***************************************************************************** TTEMPCREATENODE *****************************************************************************} procedure tcgtempcreatenode.pass_2; begin location_reset(location,LOC_VOID,OS_NO); { if we're secondpassing the same tcgtempcreatenode twice, we have a bug } if tempinfo^.valid then internalerror(200108222); { get a (persistent) temp } if tempinfo^.restype.def.needs_inittable then tg.GetTempTyped(exprasmlist,tempinfo^.restype.def,tempinfo^.temptype,tempinfo^.ref) else tg.GetTemp(exprasmlist,size,tempinfo^.temptype,tempinfo^.ref); tempinfo^.valid := true; end; {***************************************************************************** TTEMPREFNODE *****************************************************************************} procedure tcgtemprefnode.pass_2; begin { check if the temp is valid } if not tempinfo^.valid then internalerror(200108231); { set the temp's location } location_reset(location,LOC_REFERENCE,def_cgsize(tempinfo^.restype.def)); location.reference := tempinfo^.ref; inc(location.reference.offset,offset); end; procedure tcgtemprefnode.changelocation(const ref: treference); begin { check if the temp is valid } if not tempinfo^.valid then internalerror(200306081); if (tempinfo^.temptype = tt_persistent) then tg.ChangeTempType(exprasmlist,tempinfo^.ref,tt_normal); tg.ungettemp(exprasmlist,tempinfo^.ref); tempinfo^.ref := ref; tg.ChangeTempType(exprasmlist,tempinfo^.ref,tempinfo^.temptype); { adapt location } location.reference := ref; inc(location.reference.offset,offset); end; {***************************************************************************** TTEMPDELETENODE *****************************************************************************} procedure tcgtempdeletenode.pass_2; begin location_reset(location,LOC_VOID,OS_NO); if release_to_normal then tg.ChangeTempType(exprasmlist,tempinfo^.ref,tt_normal) else tg.UnGetTemp(exprasmlist,tempinfo^.ref); end; begin cnothingnode:=tcgnothingnode; casmnode:=tcgasmnode; cstatementnode:=tcgstatementnode; cblocknode:=tcgblocknode; ctempcreatenode:=tcgtempcreatenode; ctemprefnode:=tcgtemprefnode; ctempdeletenode:=tcgtempdeletenode; end. { $Log$ Revision 1.51 2003-11-07 15:58:32 florian * Florian's culmutative nr. 1; contains: - invalid calling conventions for a certain cpu are rejected - arm softfloat calling conventions - -Sp for cpu dependend code generation - several arm fixes - remaining code for value open array paras on heap Revision 1.50 2003/11/04 15:35:13 peter * fix for referencecounted temps Revision 1.49 2003/11/02 13:30:05 jonas * fixed ppc compilation Revision 1.48 2003/10/30 19:59:00 peter * support scalefactor for opr_local * support reference with opr_local set, fixes tw2631 Revision 1.47 2003/10/29 15:40:20 peter * support indexing and offset retrieval for locals Revision 1.46 2003/10/24 17:39:41 peter * asmnode.get_position now inserts a marker Revision 1.45 2003/10/21 15:15:36 peter * taicpu_abstract.oper[] changed to pointers Revision 1.44 2003/10/10 17:48:13 peter * old trgobj moved to x86/rgcpu and renamed to trgx86fpu * tregisteralloctor renamed to trgobj * removed rgobj from a lot of units * moved location_* and reference_* to cgobj * first things for mmx register allocation Revision 1.43 2003/10/09 21:31:37 daniel * Register allocator splitted, ans abstract now Revision 1.42 2003/10/07 18:18:16 peter * fix register calling for assembler procedures * fix result loading for assembler procedures Revision 1.41 2003/10/01 20:34:48 peter * procinfo unit contains tprocinfo * cginfo renamed to cgbase * moved cgmessage to verbose * fixed ppc and sparc compiles Revision 1.40 2003/09/23 17:56:05 peter * locals and paras are allocated in the code generation * tvarsym.localloc contains the location of para/local when generating code for the current procedure Revision 1.39 2003/09/07 22:09:35 peter * preparations for different default calling conventions * various RA fixes Revision 1.38 2003/09/03 15:55:00 peter * NEWRA branch merged Revision 1.37.2.1 2003/08/27 20:23:55 peter * remove old ra code Revision 1.37 2003/06/13 21:19:30 peter * current_procdef removed, use current_procinfo.procdef instead Revision 1.36 2003/06/09 18:26:46 peter * remove temptype, use tempinfo.temptype instead Revision 1.35 2003/06/09 12:20:47 peter * getposition added to retrieve the the current tai item Revision 1.34 2003/05/17 13:30:08 jonas * changed tt_persistant to tt_persistent :) * tempcreatenode now doesn't accept a boolean anymore for persistent temps, but a ttemptype, so you can also create ansistring temps etc Revision 1.33 2003/04/27 11:21:33 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.32 2002/04/25 20:15:39 florian * block nodes within expressions shouldn't release the used registers, fixed using a flag till the new rg is ready Revision 1.31 2003/04/22 23:50:22 peter * firstpass uses expectloc * checks if there are differences between the expectloc and location.loc from secondpass in EXTDEBUG Revision 1.30 2003/04/17 07:50:24 daniel * Some work on interference graph construction Revision 1.29 2003/03/28 19:16:56 peter * generic constructor working for i386 * remove fixed self register * esi added as address register for i386 Revision 1.28 2002/11/27 15:33:19 peter * fixed relabeling to relabel only tasmlabel (formerly proclocal) Revision 1.27 2002/11/27 02:37:13 peter * case statement inlining added * fixed inlining of write() * switched statementnode left and right parts so the statements are processed in the correct order when getcopy is used. This is required for tempnodes Revision 1.26 2002/11/17 16:31:56 carl * memory optimization (3-4%) : cleanup of tai fields, cleanup of tdef and tsym fields. * make it work for m68k Revision 1.25 2002/11/15 16:29:30 peter * made tasmsymbol.refs private (merged) Revision 1.24 2002/11/15 01:58:51 peter * merged changes from 1.0.7 up to 04-11 - -V option for generating bug report tracing - more tracing for option parsing - errors for cdecl and high() - win32 import stabs - win32 records<=8 are returned in eax:edx (turned off by default) - heaptrc update - more info for temp management in .s file with EXTDEBUG Revision 1.23 2002/08/23 16:14:48 peter * tempgen cleanup * tt_noreuse temp type added that will be used in genentrycode Revision 1.22 2002/08/11 14:32:26 peter * renamed current_library to objectlibrary Revision 1.21 2002/08/11 13:24:11 peter * saving of asmsymbols in ppu supported * asmsymbollist global is removed and moved into a new class tasmlibrarydata that will hold the info of a .a file which corresponds with a single module. Added librarydata to tmodule to keep the library info stored for the module. In the future the objectfiles will also be stored to the tasmlibrarydata class * all getlabel/newasmsymbol and friends are moved to the new class Revision 1.20 2002/07/01 18:46:22 peter * internal linker * reorganized aasm layer Revision 1.19 2002/05/18 13:34:09 peter * readded missing revisions Revision 1.18 2002/05/16 19:46:37 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.16 2002/05/13 19:54:37 peter * removed n386ld and n386util units * maybe_save/maybe_restore added instead of the old maybe_push Revision 1.15 2002/05/12 16:53:07 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.14 2002/04/23 19:16:34 peter * add pinline unit that inserts compiler supported functions using one or more statements * moved finalize and setlength from ninl to pinline Revision 1.13 2002/04/21 19:02:03 peter * removed newn and disposen nodes, the code is now directly inlined from pexpr * -an option that will write the secondpass nodes to the .s file, this requires EXTDEBUG define to actually write the info * fixed various internal errors and crashes due recent code changes Revision 1.12 2002/04/04 19:05:57 peter * removed unused units * use tlocation.size in cg.a_*loc*() routines Revision 1.11 2002/03/31 20:26:34 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 }