{ $Id$ Copyright (c) 1998-2002 by Florian Klaempfl Helper routines for all code generators 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 ncgutil; {$i fpcdefs.inc} interface uses node,cpuinfo, globtype, cpubase,cgbase, aasmbase,aasmtai,aasmcpu, symconst,symbase,symdef,symsym,symtype,symtable {$ifndef cpu64bit} ,cg64f32 {$endif cpu64bit} ; type tloadregvars = (lr_dont_load_regvars, lr_load_regvars); procedure firstcomplex(p : tbinarynode); procedure maketojumpbool(list:TAAsmoutput; p : tnode; loadregvars: tloadregvars); // procedure remove_non_regvars_from_loc(const t: tlocation; var regs:Tsuperregisterset); procedure location_force_reg(list:TAAsmoutput;var l:tlocation;dst_size:TCGSize;maybeconst:boolean); procedure location_force_fpureg(list:TAAsmoutput;var l: tlocation;maybeconst:boolean); procedure location_force_mem(list:TAAsmoutput;var l:tlocation); procedure location_force_mmregscalar(list:TAAsmoutput;var l: tlocation;maybeconst:boolean); function maybe_pushfpu(list:taasmoutput;needed : byte;var l:tlocation) : boolean; procedure gen_proc_symbol(list:Taasmoutput); procedure gen_proc_symbol_end(list:Taasmoutput); procedure gen_stackalloc_code(list:Taasmoutput); procedure gen_stackfree_code(list:Taasmoutput;usesacc,usesacchi:boolean); procedure gen_save_used_regs(list:TAAsmoutput); procedure gen_restore_used_regs(list:TAAsmoutput;const funcretparaloc:tparalocation); procedure gen_initialize_code(list:TAAsmoutput;inlined:boolean); procedure gen_finalize_code(list:TAAsmoutput;inlined:boolean); procedure gen_entry_code(list:TAAsmoutput); procedure gen_exit_code(list:TAAsmoutput); procedure gen_load_para_value(list:TAAsmoutput); procedure gen_load_return_value(list:TAAsmoutput; var uses_acc,uses_acchi,uses_fpu : boolean); (* procedure geninlineentrycode(list:TAAsmoutput;stackframe:longint); procedure geninlineexitcode(list:TAAsmoutput;inlined:boolean); *) {# Allocate the buffers for exception management and setjmp environment. Return a pointer to these buffers, send them to the utility routine so they are registered, and then call setjmp. Then compare the result of setjmp with 0, and if not equal to zero, then jump to exceptlabel. Also store the result of setjmp to a temporary space by calling g_save_exception_reason It is to note that this routine may be called *after* the stackframe of a routine has been called, therefore on machines where the stack cannot be modified, all temps should be allocated on the heap instead of the stack. } const EXCEPT_BUF_SIZE = 12; type texceptiontemps=record jmpbuf, envbuf, reasonbuf : treference; end; procedure get_exception_temps(list:taasmoutput;var t:texceptiontemps); procedure unget_exception_temps(list:taasmoutput;const t:texceptiontemps); procedure new_exception(list:TAAsmoutput;const t:texceptiontemps;a:aword;exceptlabel:tasmlabel); procedure free_exception(list:TAAsmoutput;const t:texceptiontemps;a:aword;endexceptlabel:tasmlabel;onlyfree:boolean); procedure insertconstdata(sym : ttypedconstsym); procedure insertbssdata(sym : tvarsym); procedure gen_alloc_localst(list:TAAsmoutput;st:tlocalsymtable); procedure gen_free_localst(list:TAAsmoutput;st:tlocalsymtable); procedure gen_alloc_parast(list:TAAsmoutput;st:tparasymtable); procedure gen_alloc_inline_parast(list:TAAsmoutput;st:tparasymtable); procedure gen_free_parast(list:TAAsmoutput;st:tparasymtable); { rtti and init/final } procedure generate_rtti(p:Ttypesym); procedure generate_inittable(p:tsym); implementation uses {$ifdef Delphi} Sysutils, {$else} strings, {$endif} cutils,cclasses, globals,systems,verbose, defutil, procinfo,paramgr,fmodule, regvars, {$ifdef GDB} gdb, {$endif GDB} pass_1,pass_2, ncon,nld,nutils, tgobj,cgutils,cgobj; {***************************************************************************** Misc Helpers *****************************************************************************} { DO NOT RELY on the fact that the tnode is not yet swaped because of inlining code PM } procedure firstcomplex(p : tbinarynode); var hp : tnode; begin { always calculate boolean AND and OR from left to right } if (p.nodetype in [orn,andn]) and is_boolean(p.left.resulttype.def) then begin if nf_swaped in p.flags then internalerror(234234); end else if ( (p.location.loc=LOC_FPUREGISTER) and (p.right.registersfpu > p.left.registersfpu) ) or ( ( ( ((p.left.registersfpu = 0) and (p.right.registersfpu = 0)) or (p.location.loc<>LOC_FPUREGISTER) ) and (p.left.registersint0 then cg.a_jmp_always(list,truelabel) else cg.a_jmp_always(list,falselabel) end else begin opsize:=def_cgsize(p.resulttype.def); case p.location.loc of LOC_CREGISTER,LOC_REGISTER,LOC_CREFERENCE,LOC_REFERENCE : begin {$ifdef OLDREGVARS} if (p.location.loc = LOC_CREGISTER) then load_regvar_reg(list,p.location.register); {$endif OLDREGVARS} cg.a_cmp_const_loc_label(list,opsize,OC_NE, 0,p.location,truelabel); { !!! should happen right after cmp (JM) } location_release(list,p.location); cg.a_jmp_always(list,falselabel); end; LOC_JUMP: ; {$ifdef cpuflags} LOC_FLAGS : begin cg.a_jmp_flags(list,p.location.resflags, truelabel); cg.a_jmp_always(list,falselabel); end; {$endif cpuflags} else begin printnode(output,p); internalerror(200308241); end; end; end; end else internalerror(200112305); aktfilepos:=storepos; end; (* This code needs fixing. It is not safe to use rgint; on the m68000 it would be rgaddr. procedure remove_non_regvars_from_loc(const t: tlocation; var regs:Tsuperregisterset); begin case t.loc of LOC_REGISTER: begin { can't be a regvar, since it would be LOC_CREGISTER then } exclude(regs,getsupreg(t.register)); if t.registerhigh<>NR_NO then exclude(regs,getsupreg(t.registerhigh)); end; LOC_CREFERENCE,LOC_REFERENCE: begin if not(cs_regvars in aktglobalswitches) or (getsupreg(t.reference.base) in cg.rgint.usableregs) then exclude(regs,getsupreg(t.reference.base)); if not(cs_regvars in aktglobalswitches) or (getsupreg(t.reference.index) in cg.rgint.usableregs) then exclude(regs,getsupreg(t.reference.index)); end; end; end; *) {***************************************************************************** EXCEPTION MANAGEMENT *****************************************************************************} procedure get_exception_temps(list:taasmoutput;var t:texceptiontemps); begin tg.GetTemp(list,EXCEPT_BUF_SIZE,tt_persistent,t.envbuf); tg.GetTemp(list,JMP_BUF_SIZE,tt_persistent,t.jmpbuf); tg.GetTemp(list,sizeof(aword),tt_persistent,t.reasonbuf); end; procedure unget_exception_temps(list:taasmoutput;const t:texceptiontemps); begin tg.Ungettemp(list,t.jmpbuf); tg.ungettemp(list,t.envbuf); tg.ungettemp(list,t.reasonbuf); end; procedure new_exception(list:TAAsmoutput;const t:texceptiontemps;a:aword;exceptlabel:tasmlabel); var paraloc1,paraloc2,paraloc3 : tparalocation; begin paraloc1:=paramanager.getintparaloc(pocall_default,1); paraloc2:=paramanager.getintparaloc(pocall_default,2); paraloc3:=paramanager.getintparaloc(pocall_default,3); paramanager.allocparaloc(list,paraloc3); cg.a_paramaddr_ref(list,t.envbuf,paraloc3); paramanager.allocparaloc(list,paraloc2); cg.a_paramaddr_ref(list,t.jmpbuf,paraloc2); { push type of exceptionframe } paramanager.allocparaloc(list,paraloc1); cg.a_param_const(list,OS_S32,1,paraloc1); paramanager.freeparaloc(list,paraloc3); paramanager.freeparaloc(list,paraloc2); paramanager.freeparaloc(list,paraloc1); cg.allocexplicitregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default)); cg.a_call_name(list,'FPC_PUSHEXCEPTADDR'); cg.deallocexplicitregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default)); paraloc1:=paramanager.getintparaloc(pocall_default,1); paramanager.allocparaloc(list,paraloc1); cg.a_param_reg(list,OS_ADDR,NR_FUNCTION_RESULT_REG,paraloc1); paramanager.freeparaloc(list,paraloc1); cg.allocexplicitregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default)); cg.a_call_name(list,'FPC_SETJMP'); cg.deallocexplicitregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default)); cg.g_exception_reason_save(list, t.reasonbuf); cg.a_cmp_const_reg_label(list,OS_S32,OC_NE,0,cg.makeregsize(NR_FUNCTION_RESULT_REG,OS_S32),exceptlabel); end; procedure free_exception(list:TAAsmoutput;const t:texceptiontemps;a:aword;endexceptlabel:tasmlabel;onlyfree:boolean); begin cg.allocexplicitregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default)); cg.a_call_name(list,'FPC_POPADDRSTACK'); cg.deallocexplicitregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default)); if not onlyfree then begin cg.g_exception_reason_load(list, t.reasonbuf); cg.a_cmp_const_reg_label(list,OS_INT,OC_EQ,a,NR_FUNCTION_RESULT_REG,endexceptlabel); end; end; {***************************************************************************** TLocation *****************************************************************************} {$ifndef cpu64bit} { 32-bit version } procedure location_force_reg(list:TAAsmoutput;var l:tlocation;dst_size:TCGSize;maybeconst:boolean); var hregister, hregisterhi : tregister; hreg64 : tregister64; hl : tasmlabel; oldloc : tlocation; begin oldloc:=l; if dst_size=OS_NO then internalerror(200309144); { handle transformations to 64bit separate } if dst_size in [OS_64,OS_S64] then begin if not (l.size in [OS_64,OS_S64]) then begin { load a smaller size to OS_64 } if l.loc=LOC_REGISTER then begin hregister:=cg.makeregsize(l.registerlow,OS_32); cg.a_load_reg_reg(list,l.size,OS_32,l.registerlow,hregister); end else begin location_release(list,l); hregister:=cg.getintregister(list,OS_INT); end; { load value in low register } case l.loc of LOC_FLAGS : cg.g_flags2reg(list,OS_INT,l.resflags,hregister); LOC_JUMP : begin cg.a_label(list,truelabel); cg.a_load_const_reg(list,OS_INT,1,hregister); objectlibrary.getlabel(hl); cg.a_jmp_always(list,hl); cg.a_label(list,falselabel); cg.a_load_const_reg(list,OS_INT,0,hregister); cg.a_label(list,hl); end; else cg.a_load_loc_reg(list,OS_INT,l,hregister); end; { reset hi part, take care of the signed bit of the current value } hregisterhi:=cg.getintregister(list,OS_INT); if (dst_size=OS_S64) and (l.size in [OS_S8,OS_S16,OS_S32]) then begin if l.loc=LOC_CONSTANT then begin if (longint(l.value)<0) then cg.a_load_const_reg(list,OS_32,$ffffffff,hregisterhi) else cg.a_load_const_reg(list,OS_32,0,hregisterhi); end else begin cg.a_op_const_reg_reg(list,OP_SAR,OS_32,31,hregister, hregisterhi); end; end else cg.a_load_const_reg(list,OS_32,0,hregisterhi); location_reset(l,LOC_REGISTER,dst_size); l.registerlow:=hregister; l.registerhigh:=hregisterhi; end else begin { 64bit to 64bit } if (l.loc=LOC_REGISTER) or ((l.loc=LOC_CREGISTER) and maybeconst) then begin hregister:=l.registerlow; hregisterhi:=l.registerhigh; end else begin hregister:=cg.getintregister(list,OS_INT); hregisterhi:=cg.getintregister(list,OS_INT); location_release(list,l); end; hreg64.reglo:=hregister; hreg64.reghi:=hregisterhi; { load value in new register } cg64.a_load64_loc_reg(list,l,hreg64); location_reset(l,LOC_REGISTER,dst_size); l.registerlow:=hregister; l.registerhigh:=hregisterhi; end; end else begin {Do not bother to recycle the existing register. The register allocator eliminates unnecessary moves, so it's not needed and trying to recycle registers can cause problems because the registers changes size and may need aditional constraints.} location_release(list,l); hregister:=cg.getintregister(list,dst_size); { load value in new register } case l.loc of LOC_FLAGS : cg.g_flags2reg(list,dst_size,l.resflags,hregister); LOC_JUMP : begin cg.a_label(list,truelabel); cg.a_load_const_reg(list,dst_size,1,hregister); objectlibrary.getlabel(hl); cg.a_jmp_always(list,hl); cg.a_label(list,falselabel); cg.a_load_const_reg(list,dst_size,0,hregister); cg.a_label(list,hl); end; else begin { load_loc_reg can only handle size >= l.size, when the new size is smaller then we need to adjust the size of the orignal and maybe recalculate l.register for i386 } if (TCGSize2Size[dst_size] LOC_CREGISTER) or not maybeconst then location_reset(l,LOC_REGISTER,dst_size) else location_reset(l,LOC_CREGISTER,dst_size); l.register:=hregister; end; { Release temp when it was a reference } if oldloc.loc=LOC_REFERENCE then location_freetemp(list,oldloc); end; {$else cpu64bit} { 64-bit version } procedure location_force_reg(list:TAAsmoutput;var l:tlocation;dst_size:TCGSize;maybeconst:boolean); var hregister : tregister; hl : tasmlabel; oldloc : tlocation; begin {Do not bother to recycle the existing register. The register allocator eliminates unnecessary moves, so it's not needed and trying to recycle registers can cause problems because the registers changes size and may need aditional constraints.} location_release(list,l); hregister:=cg.getintregister(list,dst_size); { load value in new register } case l.loc of LOC_FLAGS : cg.g_flags2reg(list,dst_size,l.resflags,hregister); LOC_JUMP : begin cg.a_label(list,truelabel); cg.a_load_const_reg(list,dst_size,1,hregister); objectlibrary.getlabel(hl); cg.a_jmp_always(list,hl); cg.a_label(list,falselabel); cg.a_load_const_reg(list,dst_size,0,hregister); cg.a_label(list,hl); end; else begin { load_loc_reg can only handle size >= l.size, when the new size is smaller then we need to adjust the size of the orignal and maybe recalculate l.register for i386 } if (TCGSize2Size[dst_size] LOC_CREGISTER) or not maybeconst then location_reset(l,LOC_REGISTER,dst_size) else location_reset(l,LOC_CREGISTER,dst_size); l.register:=hregister; { Release temp when it was a reference } if oldloc.loc=LOC_REFERENCE then location_freetemp(list,oldloc); end; {$endif cpu64bit} procedure location_force_fpureg(list:TAAsmoutput;var l: tlocation;maybeconst:boolean); var reg : tregister; href : treference; begin if (l.loc<>LOC_FPUREGISTER) and ((l.loc<>LOC_CFPUREGISTER) or (not maybeconst)) then begin { if it's in an mm register, store to memory first } if (l.loc in [LOC_MMREGISTER,LOC_CMMREGISTER]) then begin tg.GetTemp(list,tcgsize2size[l.size],tt_normal,href); cg.a_loadmm_reg_ref(list,l.size,l.size,l.register,href,mms_movescalar); location_release(list,l); location_reset(l,LOC_REFERENCE,l.size); l.reference:=href; end; reg:=cg.getfpuregister(list,l.size); cg.a_loadfpu_loc_reg(list,l,reg); location_freetemp(list,l); location_release(list,l); location_reset(l,LOC_FPUREGISTER,l.size); l.register:=reg; end; end; procedure location_force_mmregscalar(list:TAAsmoutput;var l: tlocation;maybeconst:boolean); var reg : tregister; href : treference; begin if (l.loc<>LOC_MMREGISTER) and ((l.loc<>LOC_CMMREGISTER) or (not maybeconst)) then begin { if it's in an fpu register, store to memory first } if (l.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER]) then begin tg.GetTemp(list,tcgsize2size[l.size],tt_normal,href); cg.a_loadfpu_reg_ref(list,l.size,l.register,href); location_release(list,l); location_reset(l,LOC_REFERENCE,l.size); l.reference:=href; end; reg:=cg.getmmregister(list,l.size); cg.a_loadmm_loc_reg(list,l.size,l,reg,mms_movescalar); location_freetemp(list,l); location_release(list,l); location_reset(l,LOC_MMREGISTER,l.size); l.register:=reg; end; end; procedure location_force_mem(list:TAAsmoutput;var l:tlocation); var r : treference; begin case l.loc of LOC_FPUREGISTER, LOC_CFPUREGISTER : begin tg.GetTemp(list,TCGSize2Size[l.size],tt_normal,r); cg.a_loadfpu_reg_ref(list,l.size,l.register,r); location_release(list,l); location_reset(l,LOC_REFERENCE,l.size); l.reference:=r; end; LOC_MMREGISTER, LOC_CMMREGISTER: begin tg.GetTemp(list,TCGSize2Size[l.size],tt_normal,r); cg.a_loadmm_reg_ref(list,l.size,l.size,l.register,r,mms_movescalar); location_release(list,l); location_reset(l,LOC_REFERENCE,l.size); l.reference:=r; end; LOC_CONSTANT, LOC_REGISTER, LOC_CREGISTER : begin tg.GetTemp(list,TCGSize2Size[l.size],tt_normal,r); if l.size in [OS_64,OS_S64] then begin cg64.a_load64_loc_ref(list,l,r); location_release(list,l); end else begin location_release(list,l); cg.a_load_loc_ref(list,l.size,l,r); end; location_reset(l,LOC_REFERENCE,l.size); l.reference:=r; end; LOC_CREFERENCE, LOC_REFERENCE : ; else internalerror(200203219); end; end; {***************************************************************************** Maybe_Save *****************************************************************************} function maybe_pushfpu(list:taasmoutput;needed : byte;var l:tlocation) : boolean; begin {$ifdef i386} if (needed>=maxfpuregs) and (l.loc = LOC_FPUREGISTER) then begin location_force_mem(list,l); maybe_pushfpu:=true; end else maybe_pushfpu:=false; {$endif i386} end; {**************************************************************************** Init/Finalize Code ****************************************************************************} procedure copyvalueparas(p : tnamedindexitem;arg:pointer); var href1,href2 : treference; list:TAAsmoutput; hsym : tvarsym; l : longint; loadref : boolean; localcopyloc : tparalocation; begin list:=taasmoutput(arg); if (tsym(p).typ=varsym) and (tvarsym(p).varspez=vs_value) and (paramanager.push_addr_param(tvarsym(p).varspez,tvarsym(p).vartype.def,current_procinfo.procdef.proccalloption)) then begin loadref:=true; case tvarsym(p).localloc.loc of LOC_REGISTER : begin reference_reset_base(href1,tvarsym(p).localloc.register,0); loadref:=false; end; LOC_REFERENCE : reference_reset_base(href1,tvarsym(p).localloc.reference.index, tvarsym(p).localloc.reference.offset); else internalerror(200309181); end; if is_open_array(tvarsym(p).vartype.def) or is_array_of_const(tvarsym(p).vartype.def) then begin { cdecl functions don't have a high pointer so it is not possible to generate a local copy } if not(current_procinfo.procdef.proccalloption in [pocall_cdecl,pocall_cppdecl]) then begin hsym:=tvarsym(tsym(p).owner.search('high'+p.name)); if not assigned(hsym) then internalerror(200306061); case hsym.localloc.loc of LOC_REFERENCE : begin { this code is only executed before the code for the body and the entry/exit code is generated so we're allowed to include pi_do_call here; after pass1 is run, this isn't allowed anymore } include(current_procinfo.flags,pi_do_call); reference_reset_base(href2,hsym.localloc.reference.index,hsym.localloc.reference.offset); cg.g_copyvaluepara_openarray(list,href1,href2,tarraydef(tvarsym(p).vartype.def).elesize) end else internalerror(200309182); end; end; end else begin if tvarsym(p).localloc.loc<>LOC_REFERENCE then internalerror(200309183); { Allocate space for the local copy } l:=tvarsym(p).getvaluesize; localcopyloc.loc:=LOC_REFERENCE; localcopyloc.size:=int_cgsize(l); tg.GetLocal(list,l,tvarsym(p).vartype.def,localcopyloc.reference); { Copy data } reference_reset_base(href2,localcopyloc.reference.index,localcopyloc.reference.offset); if is_shortstring(tvarsym(p).vartype.def) then begin { this code is only executed before the code for the body and the entry/exit code is generated so we're allowed to include pi_do_call here; after pass1 is run, this isn't allowed anymore } include(current_procinfo.flags,pi_do_call); cg.g_copyshortstring(list,href1,href2,tstringdef(tvarsym(p).vartype.def).len,false,loadref) end else cg.g_concatcopy(list,href1,href2,tvarsym(p).vartype.def.size,true,loadref); { update localloc of varsym } tg.Ungetlocal(list,tvarsym(p).localloc.reference); tvarsym(p).localloc:=localcopyloc; end; end; end; { generates the code for initialisation of local data } procedure initialize_data(p : tnamedindexitem;arg:pointer); var oldexprasmlist : TAAsmoutput; hp : tnode; begin if (tsym(p).typ=varsym) and (tvarsym(p).refs>0) and assigned(tvarsym(p).vartype.def) and not(is_class(tvarsym(p).vartype.def)) and tvarsym(p).vartype.def.needs_inittable then begin if (cs_implicit_exceptions in aktmoduleswitches) then include(current_procinfo.flags,pi_needs_implicit_finally); oldexprasmlist:=exprasmlist; exprasmlist:=taasmoutput(arg); hp:=initialize_data_node(cloadnode.create(tsym(p),tsym(p).owner)); firstpass(hp); secondpass(hp); hp.free; exprasmlist:=oldexprasmlist; end; end; { generates the code for finalisation of local data } procedure finalize_data(p : tnamedindexitem;arg:pointer); var oldexprasmlist : TAAsmoutput; hp : tnode; dofinalize : boolean; begin dofinalize:=false; case tsym(p).typ of varsym : begin if (tvarsym(p).refs>0) and not(vo_is_funcret in tvarsym(p).varoptions) and assigned(tvarsym(p).vartype.def) and not(is_class(tvarsym(p).vartype.def)) and tvarsym(p).vartype.def.needs_inittable then dofinalize:=true; end; typedconstsym : begin if ttypedconstsym(p).is_writable and ttypedconstsym(p).typedconsttype.def.needs_inittable then dofinalize:=true; end; end; if dofinalize then begin oldexprasmlist:=exprasmlist; exprasmlist:=taasmoutput(arg); hp:=finalize_data_node(cloadnode.create(tsym(p),tsym(p).owner)); firstpass(hp); secondpass(hp); hp.free; exprasmlist:=oldexprasmlist; end; end; { generates the code for incrementing the reference count of parameters and initialize out parameters } procedure init_paras(p : tnamedindexitem;arg:pointer); var href : treference; tmpreg : tregister; list:TAAsmoutput; begin list:=taasmoutput(arg); if (tsym(p).typ=varsym) and not is_class(tvarsym(p).vartype.def) and tvarsym(p).vartype.def.needs_inittable then begin case tvarsym(p).varspez of vs_value : begin if (cs_implicit_exceptions in aktmoduleswitches) then include(current_procinfo.flags,pi_needs_implicit_finally); if tvarsym(p).localloc.loc<>LOC_REFERENCE then internalerror(200309187); reference_reset_base(href,tvarsym(p).localloc.reference.index,tvarsym(p).localloc.reference.offset); cg.g_incrrefcount(list,tvarsym(p).vartype.def,href,is_open_array(tvarsym(p).vartype.def)); end; vs_out : begin case tvarsym(p).localloc.loc of LOC_REFERENCE : reference_reset_base(href,tvarsym(p).localloc.reference.index,tvarsym(p).localloc.reference.offset); else internalerror(2003091810); end; tmpreg:=cg.getaddressregister(list); cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,tmpreg); reference_reset_base(href,tmpreg,0); cg.g_initialize(list,tvarsym(p).vartype.def,href,false); cg.ungetregister(list,tmpreg); end; end; end; end; { generates the code for decrementing the reference count of parameters } procedure final_paras(p : tnamedindexitem;arg:pointer); var href : treference; list:TAAsmoutput; begin list:=taasmoutput(arg); if (tsym(p).typ=varsym) and not is_class(tvarsym(p).vartype.def) and tvarsym(p).vartype.def.needs_inittable then begin if (tvarsym(p).varspez=vs_value) then begin if tvarsym(p).localloc.loc<>LOC_REFERENCE then internalerror(200309188); reference_reset_base(href,tvarsym(p).localloc.reference.index,tvarsym(p).localloc.reference.offset); cg.g_decrrefcount(list,tvarsym(p).vartype.def,href,is_open_array(tvarsym(p).vartype.def)); end; end else if (tsym(p).typ=varsym) and (tvarsym(p).varspez=vs_value) and (is_open_array(tvarsym(p).vartype.def) or is_array_of_const(tvarsym(p).vartype.def)) then begin { cdecl functions don't have a high pointer so it is not possible to generate a local copy } if not(current_procinfo.procdef.proccalloption in [pocall_cdecl,pocall_cppdecl]) then begin reference_reset_base(href,tvarsym(p).localloc.reference.index,tvarsym(p).localloc.reference.offset); cg.g_releasevaluepara_openarray(list,href); end; end; end; { Initialize temp ansi/widestrings,interfaces } procedure inittempvariables(list:taasmoutput); var hp : ptemprecord; href : treference; begin hp:=tg.templist; while assigned(hp) do begin if assigned(hp^.def) and hp^.def.needs_inittable then begin if (cs_implicit_exceptions in aktmoduleswitches) then include(current_procinfo.flags,pi_needs_implicit_finally); reference_reset_base(href,current_procinfo.framepointer,hp^.pos); cg.g_initialize(list,hp^.def,href,false); end; hp:=hp^.next; end; end; procedure finalizetempvariables(list:taasmoutput); var hp : ptemprecord; href : treference; paraloc1 : tparalocation; begin paraloc1:=paramanager.getintparaloc(pocall_default,1); hp:=tg.templist; while assigned(hp) do begin if assigned(hp^.def) and hp^.def.needs_inittable then begin reference_reset_base(href,current_procinfo.framepointer,hp^.pos); cg.g_finalize(list,hp^.def,href,false); end; hp:=hp^.next; end; end; procedure gen_load_return_value(list:TAAsmoutput; var uses_acc,uses_acchi,uses_fpu : boolean); var ressym : tvarsym; resloc : tlocation; href : treference; hreg : tregister; begin { Is the loading needed? } if is_void(current_procinfo.procdef.rettype.def) or ( (po_assembler in current_procinfo.procdef.procoptions) and (not(assigned(current_procinfo.procdef.funcretsym)) or (tvarsym(current_procinfo.procdef.funcretsym).refs=0)) ) then exit; { Constructors need to return self } if (current_procinfo.procdef.proctypeoption=potype_constructor) then begin cg.getexplicitregister(list,NR_FUNCTION_RETURN_REG); { return the self pointer } ressym:=tvarsym(current_procinfo.procdef.parast.search('self')); if not assigned(ressym) then internalerror(200305058); cg.ungetregister(list,NR_FUNCTION_RETURN_REG); // for the optimizer cg.a_reg_alloc(list,NR_FUNCTION_RETURN_REG); case ressym.localloc.loc of LOC_REFERENCE : begin reference_reset_base(href,ressym.localloc.reference.index,ressym.localloc.reference.offset); cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_FUNCTION_RETURN_REG); end; LOC_REGISTER: cg.a_load_reg_reg(list,OS_ADDR,OS_ADDR,ressym.localloc.register,NR_FUNCTION_RETURN_REG); else internalerror(2004020409); end; uses_acc:=true; exit; end; ressym := tvarsym(current_procinfo.procdef.funcretsym); if (ressym.refs>0) then begin case ressym.localloc.loc of LOC_FPUREGISTER, LOC_REGISTER : begin if paramanager.ret_in_param(current_procinfo.procdef.rettype.def,current_procinfo.procdef.proccalloption) then location_reset(resloc,LOC_CREGISTER,OS_ADDR) else if ressym.vartype.def.deftype = floatdef then location_reset(resloc,LOC_CFPUREGISTER,def_cgsize(current_procinfo.procdef.rettype.def)) else location_reset(resloc,LOC_CREGISTER,def_cgsize(current_procinfo.procdef.rettype.def)); resloc.register:=ressym.localloc.register; end; LOC_REFERENCE : begin location_reset(resloc,LOC_REFERENCE,def_cgsize(current_procinfo.procdef.rettype.def)); reference_reset_base(resloc.reference,ressym.localloc.reference.index,ressym.localloc.reference.offset); end; else internalerror(200309184); end; { Here, we return the function result. In most architectures, the value is passed into the FUNCTION_RETURN_REG, but in a windowed architecure like sparc a function returns in a register and the caller receives it in an other one } case current_procinfo.procdef.rettype.def.deftype of orddef, enumdef : begin uses_acc:=true; {$ifndef cpu64bit} if resloc.size in [OS_64,OS_S64] then begin uses_acchi:=true; cg.getexplicitregister(list,NR_FUNCTION_RETURN64_LOW_REG); cg.getexplicitregister(list,NR_FUNCTION_RETURN64_HIGH_REG); cg.ungetregister(list,NR_FUNCTION_RETURN64_LOW_REG); cg.ungetregister(list,NR_FUNCTION_RETURN64_HIGH_REG); // for the optimizer cg.a_reg_alloc(list,NR_FUNCTION_RETURN64_LOW_REG); cg.a_reg_alloc(list,NR_FUNCTION_RETURN64_HIGH_REG); cg64.a_load64_loc_reg(list,resloc,joinreg64(NR_FUNCTION_RETURN64_LOW_REG, NR_FUNCTION_RETURN64_HIGH_REG)); end else {$endif cpu64bit} begin cg.getexplicitregister(list,NR_FUNCTION_RETURN_REG); hreg:=cg.makeregsize(NR_FUNCTION_RETURN_REG,resloc.size); cg.ungetregister(list,hreg); // for the optimizer cg.a_reg_alloc(list,NR_FUNCTION_RETURN_REG); cg.a_load_loc_reg(list,resloc.size,resloc,hreg); end; end; floatdef : begin uses_fpu := true; {$ifdef cpufpemu} if cs_fp_emulation in aktmoduleswitches then cg.a_loadfpu_loc_reg(list,resloc,NR_FUNCTION_RETURN_REG) else {$endif cpufpemu} cg.a_loadfpu_loc_reg(list,resloc,NR_FPU_RESULT_REG); end; else begin if not paramanager.ret_in_param(current_procinfo.procdef.rettype.def,current_procinfo.procdef.proccalloption) then begin uses_acc:=true; {$ifndef cpu64bit} { Win32 can return records in EAX:EDX } if resloc.size in [OS_64,OS_S64] then begin uses_acchi:=true; cg.getexplicitregister(list,NR_FUNCTION_RETURN64_LOW_REG); cg.getexplicitregister(list,NR_FUNCTION_RETURN64_HIGH_REG); cg.ungetregister(list,NR_FUNCTION_RETURN64_LOW_REG); cg.ungetregister(list,NR_FUNCTION_RETURN64_HIGH_REG); // for the optimizer cg.a_reg_alloc(list,NR_FUNCTION_RETURN64_LOW_REG); cg.a_reg_alloc(list,NR_FUNCTION_RETURN64_HIGH_REG); cg64.a_load64_loc_reg(list,resloc,joinreg64(NR_FUNCTION_RETURN64_LOW_REG, NR_FUNCTION_RETURN64_HIGH_REG)); end else {$endif cpu64bit} begin cg.getexplicitregister(list,NR_FUNCTION_RETURN_REG); hreg:=cg.makeregsize(NR_FUNCTION_RETURN_REG,resloc.size); cg.ungetregister(list,hreg); // for the optimizer cg.a_reg_alloc(list,NR_FUNCTION_RETURN_REG); cg.a_load_loc_reg(list,resloc.size,resloc,hreg); end; end end; end; end; end; procedure gen_load_para_value(list:TAAsmoutput); var hp : tparaitem; href : treference; gotregvarparas : boolean; begin { Store register parameters in reference or in register variable } if assigned(current_procinfo.procdef.parast) and not (po_assembler in current_procinfo.procdef.procoptions) then begin { move register parameters which aren't regable into memory } { we do this before init_paras because that one calls routines which may overwrite these } { registers and it also expects the values to be in memory } hp:=tparaitem(current_procinfo.procdef.para.first); gotregvarparas := false; while assigned(hp) do begin case tvarsym(hp.parasym).localloc.loc of LOC_REGISTER, LOC_MMREGISTER, LOC_FPUREGISTER: begin gotregvarparas := true; { cg.a_load_param_reg will first allocate and then deallocate paraloc } { register (if the parameter resides in a register) and then allocate } { the regvar (which is currently not allocated) } cg.a_loadany_param_reg(list,hp.paraloc[calleeside],tvarsym(hp.parasym).localloc.register,nil); end; LOC_REFERENCE : begin if hp.paraloc[calleeside].loc<>LOC_REFERENCE then begin if getsupreg(hp.paraloc[calleeside].register)normal_function_level) then list.concat(Tai_stabs.Create(strpnew( '"parent_ebp:'+tstoreddef(voidpointertype.def).numberstring+'",'+ tostr(N_LSYM)+',0,0,'+tostr(current_procinfo.parent_framepointer_offset)))); } if (not is_void(current_procinfo.procdef.rettype.def)) and (tvarsym(current_procinfo.procdef.funcretsym).refs>0) then begin if tvarsym(current_procinfo.procdef.funcretsym).localloc.loc=LOC_REFERENCE then begin {$warning Need to add gdb support for ret in param register calling} if paramanager.ret_in_param(current_procinfo.procdef.rettype.def,current_procinfo.procdef.proccalloption) then begin list.concat(Tai_stabs.Create(strpnew( '"'+current_procinfo.procdef.procsym.name+':X*'+tstoreddef(current_procinfo.procdef.rettype.def).numberstring+'",'+ tostr(N_tsym)+',0,0,'+tostr(tvarsym(current_procinfo.procdef.funcretsym).localloc.reference.offset)))); if (m_result in aktmodeswitches) then list.concat(Tai_stabs.Create(strpnew( '"RESULT:X*'+tstoreddef(current_procinfo.procdef.rettype.def).numberstring+'",'+ tostr(N_tsym)+',0,0,'+tostr(tvarsym(current_procinfo.procdef.funcretsym).localloc.reference.offset)))) end else begin list.concat(Tai_stabs.Create(strpnew( '"'+current_procinfo.procdef.procsym.name+':X'+tstoreddef(current_procinfo.procdef.rettype.def).numberstring+'",'+ tostr(N_tsym)+',0,0,'+tostr(tvarsym(current_procinfo.procdef.funcretsym).localloc.reference.offset)))); if (m_result in aktmodeswitches) then list.concat(Tai_stabs.Create(strpnew( '"RESULT:X'+tstoreddef(current_procinfo.procdef.rettype.def).numberstring+'",'+ tostr(N_tsym)+',0,0,'+tostr(tvarsym(current_procinfo.procdef.funcretsym).localloc.reference.offset)))); end; end; end; mangled_length:=length(current_procinfo.procdef.mangledname); getmem(p,2*mangled_length+50); strpcopy(p,'192,0,0,'); strpcopy(strend(p),current_procinfo.procdef.mangledname); if (target_info.use_function_relative_addresses) then begin strpcopy(strend(p),'-'); strpcopy(strend(p),current_procinfo.procdef.mangledname); end; list.concat(Tai_stabn.Create(strnew(p))); {List.concat(Tai_stabn.Create(strpnew('192,0,0,' +current_procinfo.procdef.mangledname)))); p[0]:='2';p[1]:='2';p[2]:='4'; strpcopy(strend(p),'_end');} strpcopy(p,'224,0,0,'+stabsendlabel.name); if (target_info.use_function_relative_addresses) then begin strpcopy(strend(p),'-'); strpcopy(strend(p),current_procinfo.procdef.mangledname); end; list.concatlist(withdebuglist); list.concat(Tai_stabn.Create(strnew(p))); { strpnew('224,0,0,' +current_procinfo.procdef.mangledname+'_end'))));} freemem(p,2*mangled_length+50); end; {$endif GDB} end; procedure gen_stackalloc_code(list:Taasmoutput); var hitemp, lotemp, stackframe : longint; check : boolean; paraloc1 : tparalocation; href : treference; begin check:=(cs_check_stack in aktlocalswitches) and (current_procinfo.procdef.proctypeoption<>potype_proginit); if check then begin { Allocate tempspace to store register parameter than is destroyed when calling stackchecking code } paraloc1:=paramanager.getintparaloc(pocall_default,1); if paraloc1.loc=LOC_REGISTER then tg.GetTemp(list,POINTER_SIZE,tt_normal,href); end; { Calculate size of stackframe } stackframe:=current_procinfo.calc_stackframe_size; { All temps are know, write offsets used for information } if (cs_asm_source in aktglobalswitches) then begin if tg.direction>0 then begin lotemp:=current_procinfo.tempstart; hitemp:=tg.lasttemp; end else begin lotemp:=tg.lasttemp; hitemp:=current_procinfo.tempstart; end; list.concat(Tai_comment.Create(strpnew('Temps allocated between '+std_regname(current_procinfo.framepointer)+ tostr_with_plus(lotemp)+' and '+std_regname(current_procinfo.framepointer)+tostr_with_plus(hitemp)))); end; {$ifndef powerpc} { at least for the ppc this applies always, so this code isn't usable (FK) } { omit stack frame ? } if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then begin CGmessage(cg_d_stackframe_omited); if stackframe<>0 then cg.g_stackpointer_alloc(list,stackframe); end else {$endif powerpc} begin if (po_interrupt in current_procinfo.procdef.procoptions) then cg.g_interrupt_stackframe_entry(list); cg.g_stackframe_entry(list,stackframe); { Add stack checking code? } if check then begin { The tempspace to store original register is already allocated above before the stackframe size is calculated. } if paraloc1.loc=LOC_REGISTER then cg.a_load_reg_ref(list,OS_INT,OS_INT,paraloc1.register,href); paramanager.allocparaloc(list,paraloc1); cg.a_param_const(list,OS_INT,stackframe,paraloc1); paramanager.freeparaloc(list,paraloc1); { No register saving needed, saveregisters is used } {$ifndef x86} cg.allocexplicitregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default)); {$endif x86} cg.a_call_name(list,'FPC_STACKCHECK'); {$ifndef x86} cg.deallocexplicitregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default)); {$endif x86} if paraloc1.loc=LOC_REGISTER then begin cg.a_load_ref_reg(list,OS_INT,OS_INT,href,paraloc1.register); tg.UnGetTemp(list,href); end; end; end; end; procedure gen_stackfree_code(list:Taasmoutput;usesacc,usesacchi:boolean); var stacksize, retsize : longint; begin {$ifndef powerpc} { remove stackframe } if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then begin stacksize:=current_procinfo.calc_stackframe_size; if (stacksize<>0) then cg.a_op_const_reg(list,OP_ADD,OS_ADDR,stacksize,current_procinfo.framepointer); end else cg.g_restore_frame_pointer(list); {$endif} {$ifdef x86} { at last, the return is generated } if (po_interrupt in current_procinfo.procdef.procoptions) then cg.g_interrupt_stackframe_exit(list,usesacc,usesacchi) else {$endif x86} begin if current_procinfo.procdef.proccalloption in clearstack_pocalls then begin retsize:=0; if paramanager.ret_in_param(current_procinfo.procdef.rettype.def,current_procinfo.procdef.proccalloption) then inc(retsize,POINTER_SIZE); end else retsize:=current_procinfo.para_stack_size; cg.g_return_from_proc(list,retsize); end; {$ifndef cpu64bit} if usesacchi then begin cg.a_reg_dealloc(list,NR_FUNCTION_RETURN64_LOW_REG); cg.a_reg_dealloc(list,NR_FUNCTION_RETURN64_HIGH_REG); end else {$endif cpu64bit} if usesacc then cg.a_reg_dealloc(list,NR_FUNCTION_RETURN_REG); end; procedure gen_save_used_regs(list:TAAsmoutput); begin { Pure assembler routines need to save the registers themselves } if (po_assembler in current_procinfo.procdef.procoptions) then exit; { for the save all registers we can simply use a pusha,popa which push edi,esi,ebp,esp(ignored),ebx,edx,ecx,eax } if (po_saveregisters in current_procinfo.procdef.procoptions) then cg.g_save_all_registers(list) else if current_procinfo.procdef.proccalloption in savestdregs_pocalls then cg.g_save_standard_registers(list); end; procedure gen_restore_used_regs(list:TAAsmoutput;const funcretparaloc:tparalocation); begin { Pure assembler routines need to save the registers themselves } if (po_assembler in current_procinfo.procdef.procoptions) then exit; { for the save all registers we can simply use a pusha,popa which push edi,esi,ebp,esp(ignored),ebx,edx,ecx,eax } if (po_saveregisters in current_procinfo.procdef.procoptions) then cg.g_restore_all_registers(list,funcretparaloc) else if current_procinfo.procdef.proccalloption in savestdregs_pocalls then cg.g_restore_standard_registers(list); end; {**************************************************************************** Inlining ****************************************************************************} (* procedure load_inlined_return_value(list:TAAsmoutput); var ressym: tvarsym; resloc: tlocation; r,r2 : tregister; begin if not is_void(current_procinfo.procdef.rettype.def) then begin ressym := tvarsym(current_procinfo.procdef.funcretsym); if ressym.reg.enum <> R_NO then begin if paramanager.ret_in_param(current_procinfo.procdef.rettype.def,current_procinfo.procdef.proccalloption) then location_reset(resloc,LOC_CREGISTER,OS_ADDR) else if ressym.vartype.def.deftype = floatdef then location_reset(resloc,LOC_CFPUREGISTER,def_cgsize(current_procinfo.procdef.rettype.def)) else location_reset(resloc,LOC_CREGISTER,def_cgsize(current_procinfo.procdef.rettype.def)); resloc.register := ressym.reg; end else begin location_reset(resloc,LOC_CREGISTER,def_cgsize(current_procinfo.procdef.rettype.def)); reference_reset_base(resloc.reference,current_procinfo.framepointer,tvarsym(current_procinfo.procdef.funcretsym).adjusted_address); end; { Here, we return the function result. In most architectures, the value is passed into the FUNCTION_RETURN_REG, but in a windowed architecure like sparc a function returns in a register and the caller receives it in an other one } case current_procinfo.procdef.rettype.def.deftype of orddef, enumdef : begin {$ifndef cpu64bit} if resloc.size in [OS_64,OS_S64] then begin r:=cg.getregisterint(list,OS_INT); r2:=cg.getregisterint(list,OS_INT); cg64.a_load64_loc_reg(list,resloc,joinreg64(r,r2)); end else {$endif cpu64bit} begin r:=cg.getregisterint(list,resloc.size); cg.a_load_loc_reg(list,resloc.size,resloc,r); end; end; floatdef : begin {$ifdef cpufpemu} if cs_fp_emulation in aktmoduleswitches then r.enum := FUNCTION_RETURN_REG else {$endif cpufpemu} r.enum:=FPU_RESULT_REG; cg.a_loadfpu_loc_reg(list,resloc,r); end; else begin if not paramanager.ret_in_param(current_procinfo.procdef.rettype.def,current_procinfo.procdef.proccalloption) then begin {$ifndef cpu64bit} { Win32 can return records in EAX:EDX } if resloc.size in [OS_64,OS_S64] then begin r:=cg.getregisterint(list,OS_INT); r2:=cg.getregisterint(list,OS_INT); cg64.a_load64_loc_reg(list,resloc,joinreg64(r,r2)); end else {$endif cpu64bit} begin r:=cg.getregisterint(list,resloc.size); cg.a_load_loc_reg(list,resloc.size,resloc,r); end; end end; end; end; end; procedure geninlineentrycode(list:TAAsmoutput;stackframe:longint); begin { initialize return value } initretvalue(list); current_procinfo.procdef.localst.foreach_static({$ifndef TP}@{$endif}initialize_data,list); { initialisizes temp. ansi/wide string data } inittempvariables(list); { initialize ansi/widesstring para's } if assigned(current_procinfo.procdef.parast) then current_procinfo.procdef.parast.foreach_static({$ifndef TP}@{$endif}init_paras,list); { generate copies of call by value parameters } if not(po_assembler in current_procinfo.procdef.procoptions) then current_procinfo.procdef.parast.foreach_static({$ifndef TP}@{$endif}copyvalueparas,list); load_regvars(list,nil); end; procedure geninlineexitcode(list:TAAsmoutput;inlined:boolean); var usesacc, usesacchi, usesfpu : boolean; begin if aktexitlabel.is_used then cg.a_label(list,aktexitlabel); cleanup_regvars(list); { finalize temporary data } finalizetempvariables(list); current_procinfo.procdef.localst.foreach_static({$ifndef TP}@{$endif}finalize_data,list); { finalize paras data } if assigned(current_procinfo.procdef.parast) then current_procinfo.procdef.parast.foreach_static({$ifndef TP}@{$endif}final_paras,list); { handle return value, this is not done for assembler routines when they didn't reference the result variable } if not(po_assembler in current_procinfo.procdef.procoptions) or (assigned(current_procinfo.procdef.funcretsym) and (tvarsym(current_procinfo.procdef.funcretsym).refcount>1)) then begin if (current_procinfo.procdef.proctypeoption=potype_constructor) then internalerror(200305263); // load_inlined_return_value(list); load_return_value(list,usesacc,usesacchi,usesfpu) end; cleanup_regvars(list); end; *) {**************************************************************************** Const Data ****************************************************************************} procedure insertconstdata(sym : ttypedconstsym); { this does not affect the local stack space, since all typed constansts and initialized variables are always put in the .data / .rodata section } var storefilepos : tfileposinfo; curconstsegment : taasmoutput; l : longint; stabstr:Pchar; begin storefilepos:=aktfilepos; aktfilepos:=sym.fileinfo; if sym.is_writable then curconstsegment:=datasegment else curconstsegment:=consts; l:=sym.getsize; { insert cut for smartlinking or alignment } if (cs_create_smart in aktmoduleswitches) then curconstSegment.concat(Tai_cut.Create); curconstSegment.concat(Tai_align.create(const_align(l))); if (sym.owner.symtabletype=globalsymtable) or (cs_create_smart in aktmoduleswitches) or (assigned(current_procinfo) and (current_procinfo.procdef.proccalloption=pocall_inline)) or DLLSource then curconstSegment.concat(Tai_symbol.Createname_global(sym.mangledname,AT_DATA,l)) else curconstSegment.concat(Tai_symbol.Createname(sym.mangledname,AT_DATA,l)); aktfilepos:=storefilepos; end; procedure insertbssdata(sym : tvarsym); var l,varalign : longint; storefilepos : tfileposinfo; stabstr:Pchar; begin storefilepos:=aktfilepos; aktfilepos:=sym.fileinfo; l:=sym.getvaluesize; if (vo_is_thread_var in sym.varoptions) then inc(l,pointer_size); varalign:=var_align(l); { sym.address:=align(datasize,varalign); datasize:=tvarsym(sym).address+l; } { insert cut for smartlinking or alignment } if (cs_create_smart in aktmoduleswitches) then bssSegment.concat(Tai_cut.Create); bssSegment.concat(Tai_align.create(varalign)); if (sym.owner.symtabletype=globalsymtable) or (cs_create_smart in aktmoduleswitches) or DLLSource or (assigned(current_procinfo) and (current_procinfo.procdef.proccalloption=pocall_inline)) or (vo_is_exported in sym.varoptions) or (vo_is_C_var in sym.varoptions) then bssSegment.concat(Tai_datablock.Create_global(sym.mangledname,l)) else bssSegment.concat(Tai_datablock.Create(sym.mangledname,l)); aktfilepos:=storefilepos; end; procedure gen_alloc_localst(list:TAAsmoutput;st:tlocalsymtable); var sym : tsym; begin sym:=tsym(st.symindex.first); while assigned(sym) do begin { Only allocate space for referenced locals } if (sym.typ=varsym) and (tvarsym(sym).refs>0) then begin with tvarsym(sym) do begin {$warning TODO Add support for register variables} localloc.loc:=LOC_REFERENCE; tg.GetLocal(list,getvaluesize,vartype.def,localloc.reference); if cs_asm_source in aktglobalswitches then list.concat(Tai_comment.Create(strpnew('Local '+realname+' located at '+ std_regname(localloc.reference.index)+tostr_with_plus(localloc.reference.offset)))); end; end; sym:=tsym(sym.indexnext); end; end; procedure gen_free_localst(list:TAAsmoutput;st:tlocalsymtable); var sym : tsym; begin sym:=tsym(st.symindex.first); while assigned(sym) do begin if (sym.typ=varsym) and (tvarsym(sym).refs>0) then begin with tvarsym(sym) do begin { Note: We need to keep the data available in memory for the sub procedures that can access local data in the parent procedures } case localloc.loc of LOC_REFERENCE : tg.Ungetlocal(list,localloc.reference); LOC_REGISTER : begin {$ifndef cpu64bit} if localloc.size in [OS_64,OS_S64] then begin cg.ungetregister(list,localloc.registerlow); cg.ungetregister(list,localloc.registerhigh); end else {$endif cpu64bit} cg.ungetregister(list,localloc.register); end; end; end; end; sym:=tsym(sym.indexnext); end; end; procedure gen_alloc_parast(list:TAAsmoutput;st:tparasymtable); var sym : tsym; begin sym:=tsym(st.symindex.first); while assigned(sym) do begin if sym.typ=varsym then begin with tvarsym(sym) do begin if not(po_assembler in current_procinfo.procdef.procoptions) then begin case paraitem.paraloc[calleeside].loc of LOC_MMREGISTER, LOC_FPUREGISTER, LOC_REGISTER: begin (* if paraitem.paraloc[calleeside].register=NR_NO then begin paraitem.paraloc[calleeside].loc:=LOC_REGISTER; paraitem.paraloc[calleeside].size:=paraitem.paraloc[calleeside].size; {$ifndef cpu64bit} if paraitem.paraloc[calleeside].size in [OS_64,OS_S64] then begin paraitem.paraloc[calleeside].registerlow:=cg.getregisterint(list,OS_32); paraitem.paraloc[calleeside].registerhigh:=cg.getregisterint(list,OS_32); end else {$endif cpu64bit} paraitem.paraloc[calleeside].register:=cg.getregisterint(list,localloc.size); end; *) (* {$warning TODO Allocate register paras} localloc.loc:=LOC_REGISTER; localloc.size:=paraitem.paraloc[calleeside].size; {$ifndef cpu64bit} if localloc.size in [OS_64,OS_S64] then begin localloc.registerlow:=cg.getregisterint(list,OS_32); localloc.registerhigh:=cg.getregisterint(list,OS_32); end else {$endif cpu64bit} localloc.register:=cg.getregisterint(list,localloc.size); *) localloc.loc:=LOC_REFERENCE; localloc.size:=paraitem.paraloc[calleeside].size; tg.GetLocal(list,tcgsize2size[localloc.size],vartype.def,localloc.reference); end else localloc:=paraitem.paraloc[calleeside]; end; end else localloc:=paraitem.paraloc[calleeside]; if cs_asm_source in aktglobalswitches then begin case localloc.loc of LOC_REFERENCE : begin list.concat(Tai_comment.Create(strpnew('Para '+realname+' located at '+ std_regname(localloc.reference.index)+tostr_with_plus(localloc.reference.offset)))); {$ifdef powerpc} localloc.size:=paraitem.paraloc[calleeside].size; tg.GetLocal(list,tcgsize2size[localloc.size],vartype.def,localloc.reference); {$endif powerpc} end; end; end; end; end; sym:=tsym(sym.indexnext); end; end; procedure gen_alloc_inline_parast(list:TAAsmoutput;st:tparasymtable); var sym : tsym; begin sym:=tsym(st.symindex.first); while assigned(sym) do begin if sym.typ=varsym then begin with tvarsym(sym) do begin {$warning TODO Allocate register paras} localloc.loc:=LOC_REFERENCE; localloc.size:=int_cgsize(paramanager.push_size(vs_value,vartype.def,pocall_inline)); tg.GetLocal(list,tcgsize2size[localloc.size],vartype.def,localloc.reference); if cs_asm_source in aktglobalswitches then begin case localloc.loc of LOC_REFERENCE : list.concat(Tai_comment.Create(strpnew('Para '+realname+' allocated at '+ std_regname(localloc.reference.index)+tostr_with_plus(localloc.reference.offset)))); end; end; paraitem.paraloc[callerside]:=localloc; paraitem.paraloc[calleeside]:=localloc; end; end; sym:=tsym(sym.indexnext); end; end; procedure gen_free_parast(list:TAAsmoutput;st:tparasymtable); var sym : tsym; begin sym:=tsym(st.symindex.first); while assigned(sym) do begin if sym.typ=varsym then begin with tvarsym(sym) do begin { Note: We need to keep the data available in memory for the sub procedures that can access local data in the parent procedures } case localloc.loc of LOC_REFERENCE : tg.UngetLocal(list,localloc.reference); LOC_REGISTER : begin if localloc.register<>paraitem.paraloc[calleeside].register then begin {$ifndef cpu64bit} if localloc.size in [OS_64,OS_S64] then begin cg.ungetregister(list,localloc.registerlow); cg.ungetregister(list,localloc.registerhigh); end else {$endif cpu64bit} cg.ungetregister(list,localloc.register); end; end; end; end; end; sym:=tsym(sym.indexnext); end; end; { persistent rtti generation } procedure generate_rtti(p:Ttypesym); var rsym : trttisym; def : tstoreddef; begin { rtti can only be generated for classes that are always typesyms } def:=tstoreddef(ttypesym(p).restype.def); { there is an error, skip rtti info } if def.deftype=errordef then exit; { only create rtti once for each definition } if not(df_has_rttitable in def.defoptions) then begin { definition should be in the same symtable as the symbol } if p.owner<>def.owner then internalerror(200108262); { create rttisym } rsym:=trttisym.create(p.name,fullrtti); p.owner.insert(rsym); { register rttisym in definition } include(def.defoptions,df_has_rttitable); def.rttitablesym:=rsym; { write rtti data } def.write_child_rtti_data(fullrtti); if (cs_create_smart in aktmoduleswitches) then rttiList.concat(Tai_cut.Create); rttilist.concat(tai_align.create(const_align(pointer_size))); rttiList.concat(Tai_symbol.Create_global(rsym.get_label,0)); def.write_rtti_data(fullrtti); rttiList.concat(Tai_symbol_end.Create(rsym.get_label)); end; end; { persistent init table generation } procedure generate_inittable(p:tsym); var rsym : trttisym; def : tstoreddef; begin { anonymous types are also allowed for records that can be varsym } case p.typ of typesym : def:=tstoreddef(ttypesym(p).restype.def); varsym : def:=tstoreddef(tvarsym(p).vartype.def); else internalerror(200108263); end; { only create inittable once for each definition } if not(df_has_inittable in def.defoptions) then begin { definition should be in the same symtable as the symbol } if p.owner<>def.owner then internalerror(200108264); { create rttisym } rsym:=trttisym.create(p.name,initrtti); p.owner.insert(rsym); { register rttisym in definition } include(def.defoptions,df_has_inittable); def.inittablesym:=rsym; { write inittable data } def.write_child_rtti_data(initrtti); if (cs_create_smart in aktmoduleswitches) then rttiList.concat(Tai_cut.Create); rttilist.concat(tai_align.create(const_align(pointer_size))); rttiList.concat(Tai_symbol.Create_global(rsym.get_label,0)); def.write_rtti_data(initrtti); rttiList.concat(Tai_symbol_end.Create(rsym.get_label)); end; end; end. { $Log$ Revision 1.198 2004-05-02 17:26:19 peter * fix stabs for globals Revision 1.197 2004/03/29 14:43:47 peter * cleaner temp get/unget for exceptions Revision 1.196 2004/03/03 22:02:52 peter * use loadnode and finalize_data_node for init/final code to support threadvars correctly Revision 1.195 2004/03/02 00:36:33 olle * big transformation of Tai_[const_]Symbol.Create[data]name* Revision 1.194 2004/02/27 10:21:05 florian * top_symbol killed + refaddr to treference added + refsymbol to treference added * top_local stuff moved to an extra record to save memory + aint introduced * tppufile.get/putint64/aint implemented Revision 1.193 2004/02/22 18:27:21 florian * fixed exception reason size for 64 bit systems Revision 1.192 2004/02/08 17:48:59 jonas * fixed regvars Revision 1.191 2004/02/05 19:35:27 florian * more x86-64 fixes Revision 1.190 2004/02/05 01:24:08 florian * several fixes to compile x86-64 system Revision 1.189 2004/02/04 22:15:15 daniel * Rtti generation moved to ncgutil * Assmtai usage of symsym removed * operator overloading cleanup up Revision 1.188 2004/02/04 22:01:13 peter * first try to get cpupara working for x86_64 Revision 1.187 2004/02/03 22:32:54 peter * renamed xNNbittype to xNNinttype * renamed registers32 to registersint * replace some s32bit,u32bit with torddef([su]inttype).def.typ Revision 1.186 2004/01/31 18:40:15 daniel * Last steps before removal of aasmtai dependency in symsym can be accomplished. Revision 1.185 2004/01/31 17:45:17 peter * Change several $ifdef i386 to x86 * Change several OS_32 to OS_INT/OS_ADDR Revision 1.184 2004/01/21 21:01:34 peter * fixed stackchecking for register calling Revision 1.183 2004/01/17 15:55:10 jonas * fixed allocation of parameters passed by reference for powerpc in callee Revision 1.182 2004/01/13 18:08:58 florian * x86-64 compilation fixed Revision 1.181 2004/01/12 22:11:38 peter * use localalign info for alignment for locals and temps * sparc fpu flags branching added * moved powerpc copy_valye_openarray to generic Revision 1.180 2003/12/28 21:57:43 jonas * fixed procedures declared as "interrupt" for non-x86 Revision 1.179 2003/12/26 13:19:16 florian * rtl and compiler compile with -Cfsse2 Revision 1.178 2003/12/26 00:32:21 florian + fpu<->mm register conversion Revision 1.177 2003/12/24 00:10:02 florian - delete parameter in cg64 methods removed Revision 1.176 2003/12/23 14:38:07 florian + second_floataddsse implemented Revision 1.175 2003/12/22 19:00:17 florian * fixed some x86-64 issues Revision 1.174 2003/12/07 16:28:30 jonas * fixed typo found by Charlie Revision 1.173 2003/12/06 01:15:22 florian * reverted Peter's alloctemp patch; hopefully properly Revision 1.172 2003/12/03 23:13:20 peter * delayed paraloc allocation, a_param_*() gets extra parameter if it needs to allocate temp or real paralocation * optimized/simplified int-real loading Revision 1.171 2003/11/30 19:35:29 florian * fixed several arm related problems Revision 1.170 2003/11/29 20:13:25 florian * fixed several pi_do_call problems Revision 1.169 2003/11/23 17:05:15 peter * register calling is left-right * parameter ordering * left-right calling inserts result parameter last Revision 1.168 2003/11/22 00:31:25 jonas + extra allocations of function result regs for the optimiser Revision 1.167 2003/11/11 21:10:12 peter * remove temporary stdcall hack Revision 1.166 2003/11/10 22:02:52 peter * cross unit inlining fixed Revision 1.165 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.164 2003/11/04 19:03:50 peter * fixes for temp type patch Revision 1.163 2003/11/04 15:35:13 peter * fix for referencecounted temps Revision 1.162 2003/10/25 11:34:02 florian * fixed compilation of ppc system unit Revision 1.161 2003/10/19 01:34:30 florian * some ppc stuff fixed * memory leak fixed Revision 1.160 2003/10/17 15:08:34 peter * commented out more obsolete constants Revision 1.159 2003/10/17 14:38:32 peter * 64k registers supported * fixed some memory leaks Revision 1.158 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.157 2003/10/09 21:31:37 daniel * Register allocator splitted, ans abstract now Revision 1.156 2003/10/07 18:18:16 peter * fix register calling for assembler procedures * fix result loading for assembler procedures Revision 1.155 2003/10/07 15:17:07 peter * inline supported again, LOC_REFERENCEs are used to pass the parameters * inlineparasymtable,inlinelocalsymtable removed * exitlabel inserting fixed Revision 1.154 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.153 2003/09/30 21:02:37 peter * updates for inlining Revision 1.152 2003/09/29 20:58:56 peter * optimized releasing of registers Revision 1.151 2003/09/28 21:47:18 peter * register paras and local copies updates Revision 1.150 2003/09/28 17:55:03 peter * parent framepointer changed to hidden parameter * tloadparentfpnode added Revision 1.149 2003/09/28 13:39:38 peter * optimized releasing of registers Revision 1.148 2003/09/25 21:28:00 peter * parameter fixes Revision 1.147 2003/09/23 21:03:59 peter * check for refs>0 in init/final local data Revision 1.146 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.145 2003/09/16 16:17:01 peter * varspez in calls to push_addr_param Revision 1.144 2003/09/14 21:33:37 peter * location_force_reg gives IE when size=OS_NO Revision 1.143 2003/09/14 19:18:10 peter * remove obsolete code already in comments Revision 1.142 2003/09/11 11:54:59 florian * improved arm code generation * move some protected and private field around * the temp. register for register parameters/arguments are now released before the move to the parameter register is done. This improves the code in a lot of cases. Revision 1.141 2003/09/10 08:31:47 marco * Patch from Peter for paraloc Revision 1.140 2003/09/07 22:09:35 peter * preparations for different default calling conventions * various RA fixes Revision 1.139 2003/09/03 15:55:01 peter * NEWRA branch merged Revision 1.138 2003/09/03 11:18:37 florian * fixed arm concatcopy + arm support in the common compiler sources added * moved some generic cg code around + tfputype added * ... Revision 1.137.2.4 2003/08/31 15:46:26 peter * more updates for tregister Revision 1.137.2.3 2003/08/29 17:28:59 peter * next batch of updates Revision 1.137.2.2 2003/08/28 18:35:08 peter * tregister changed to cardinal Revision 1.137.2.1 2003/08/27 19:55:54 peter * first tregister patch Revision 1.137 2003/08/20 20:29:06 daniel * Some more R_NO changes * Preventive code to loadref added Revision 1.136 2003/08/20 17:48:49 peter * fixed stackalloc to not allocate localst.datasize twice * order of stackalloc code fixed for implicit init/final Revision 1.135 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.134 2003/08/11 21:18:20 peter * start of sparc support for newra Revision 1.133 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.132 2003/08/03 14:09:50 daniel * Fixed a register allocator bug * Figured out why -dnewra generates superfluous "mov reg1,reg2" statements: changes in location_force. These moves are now no longer constrained so they are optimized away. Revision 1.131 2003/07/23 11:04:15 jonas * split en_exit_code into a part that may allocate a register and a part that doesn't, so the former can be done before the register colouring has been performed Revision 1.130 2003/07/06 17:58:22 peter * framepointer fixes for sparc * parent framepointer code more generic Revision 1.129 2003/07/06 15:31:20 daniel * Fixed register allocator. *Lots* of fixes. Revision 1.128 2003/07/02 22:18:04 peter * paraloc splitted in callerparaloc,calleeparaloc * sparc calling convention updates Revision 1.127 2003/06/17 18:13:51 jonas * fixed -dnewra compilation problems Revision 1.126 2003/06/17 16:32:44 peter * alloc register for function result Revision 1.125 2003/06/13 21:19:30 peter * current_procdef removed, use current_procinfo.procdef instead Revision 1.124 2003/06/09 12:23:30 peter * init/final of procedure data splitted from genentrycode * use asmnode getposition to insert final at the correct position als for the implicit try...finally Revision 1.123 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.122 2003/06/06 14:43:02 peter * g_copyopenarrayvalue gets length reference * don't copy open arrays for cdecl Revision 1.121 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.120 2003/06/03 15:49:49 jonas * fixed ref/loc problems Revision 1.119 2003/06/03 15:06:37 daniel * fixed conflict marks Revision 1.118 2003/06/03 13:01:59 daniel * Register allocator finished Revision 1.117 2003/06/02 21:42:05 jonas * function results can now also be regvars - removed tprocinfo.return_offset, never use it again since it's invalid if the result is a regvar Revision 1.116 2003/06/01 21:38:06 peter * getregisterfpu size parameter added * op_const_reg size parameter added * sparc updates Revision 1.115 2003/05/31 20:28:17 jonas * changed copyvalueparas so it also supports register parameters (except for copy_value_openarray, but that one is seriously broken anyway, since it expects that the high parameter will always be in memory right after the pointer to the array, while it could just as will be in a register) Revision 1.114 2003/05/31 15:05:28 peter * FUNCTION_RESULT64_LOW/HIGH_REG added for int64 results Revision 1.113 2003/05/31 00:48:15 jonas * fixed my previous commit Revision 1.112 2003/05/30 23:57:08 peter * more sparc cleanup * accumulator removed, splitted in function_return_reg (called) and function_result_reg (caller) Revision 1.111 2003/05/30 23:49:18 jonas * a_load_loc_reg now has an extra size parameter for the destination register (properly fixes what I worked around in revision 1.106 of ncgutil.pas) Revision 1.110 2003/05/30 18:52:10 jonas * fixed bug with intregvars * locapara.loc can also be LOC_CFPUREGISTER -> also fixed rcgppc.a_param_ref, which previously got bogus size values Revision 1.109 2003/05/27 21:19:08 jonas * fixed ppc cycle Revision 1.108 2003/05/27 14:28:14 jonas * patch from Peter for nested procedures Revision 1.107 2003/05/26 21:17:17 peter * procinlinenode removed * aktexit2label removed, fast exit removed + tcallnode.inlined_pass_2 added Revision 1.106 2003/05/24 11:59:42 jonas * fixed integer typeconversion problems Revision 1.105 2003/05/23 14:27:35 peter * remove some unit dependencies * current_procinfo changes to store more info Revision 1.104 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.103 2003/05/14 19:37:25 jonas * patch from Peter for int64 function results Revision 1.102 2003/05/13 19:14:41 peter * failn removed * inherited result code check moven to pexpr Revision 1.101 2003/05/13 15:16:13 peter * removed ret_in_acc, it's the reverse of ret_in_param * fixed ret_in_param for win32 cdecl array Revision 1.100 2003/05/12 08:08:27 jonas * fixed several initialization and finalization related bugs (missing tg.direction's, wrong paralocation for decreasing refcount of everything but ansistrings) Revision 1.99 2003/05/11 21:37:03 peter * moved implicit exception frame from ncgutil to psub * constructor/destructor helpers moved from cobj/ncgutil to psub Revision 1.98 2003/05/11 14:45:12 peter * tloadnode does not support objectsymtable,withsymtable anymore * withnode cleanup * direct with rewritten to use temprefnode Revision 1.97 2003/05/10 13:20:23 jonas * moved storing of register parameters to memory even earlier in the entry code to fix problems with constructors Revision 1.96 2003/05/09 17:47:02 peter * self moved to hidden parameter * removed hdisposen,hnewn,selfn Revision 1.95 2003/04/29 07:28:52 michael + Patch from peter to fix wrong pushing of ansistring function results in open array Revision 1.94 2003/04/28 21:17:38 peter * do not finalize function results Revision 1.93 2003/04/27 16:30:34 jonas * store register para's to memory before copying the valuepara's, because that one requires them to be there already (and it calls subroutines -> could overwrite those registers) Revision 1.92 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.91 2003/04/27 07:29:50 peter * current_procinfo.procdef cleanup, current_procinfo.procdef is now always nil when parsing a new procdef declaration * aktprocsym removed * lexlevel removed, use symtable.symtablelevel instead * implicit init/final code uses the normal genentry/genexit * funcret state checking updated for new funcret handling Revision 1.90 2003/04/26 17:21:08 florian * fixed passing of fpu values by fpu register Revision 1.89 2003/04/25 20:59:33 peter * removed funcretn,funcretsym, function result is now in varsym and aliases for result and function name are added using absolutesym * vs_hidden parameter for funcret passed in parameter * vs_hidden fixes * writenode changed to printnode and released from extdebug * -vp option added to generate a tree.log with the nodetree * nicer printnode for statements, callnode Revision 1.88 2003/04/23 12:35:34 florian * fixed several issues with powerpc + applied a patch from Jonas for nested function calls (PowerPC only) * ... Revision 1.87 2003/04/22 14:33:38 peter * removed some notes/hints Revision 1.86 2003/04/22 13:47:08 peter * fixed C style array of const * fixed C array passing * fixed left to right with high parameters Revision 1.85 2003/04/22 10:09:35 daniel + Implemented the actual register allocator + Scratch registers unavailable when new register allocator used + maybe_save/maybe_restore unavailable when new register allocator used Revision 1.84 2003/04/16 09:26:55 jonas * assembler procedures now again get a stackframe if they have local variables. No space is reserved for a function result however. Also, the register parameters aren't automatically saved on the stack anymore in assembler procedures. Revision 1.83 2003/04/06 21:11:23 olle * changed newasmsymbol to newasmsymboldata for data symbols Revision 1.82 2003/03/30 20:59:07 peter * fix classmethod from classmethod call * move BeforeDestruction/AfterConstruction calls to genentrycode/genexitcode instead of generating them on the fly after a call to a constructor Revision 1.81 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.80 2003/03/17 15:52:20 peter * fix range error Revision 1.79 2003/03/11 21:46:24 jonas * lots of new regallocator fixes, both in generic and ppc-specific code (ppc compiler still can't compile the linux system unit though) Revision 1.78 2003/02/26 21:15:43 daniel * Fixed the optimizer Revision 1.77 2003/02/19 22:00:14 daniel * Code generator converted to new register notation - Horribily outdated todo.txt removed Revision 1.76 2003/02/15 22:17:38 carl * bugfix of FPU emulation code Revision 1.75 2003/01/09 22:00:53 florian * fixed some PowerPC issues Revision 1.74 2003/01/09 20:41:10 florian * fixed broken PowerPC compiler Revision 1.73 2003/01/08 18:43:56 daniel * Tregister changed into a record Revision 1.72 2002/12/29 23:51:43 florian * web bug 2214 fixed: ie 10 in const array constructors Revision 1.71 2002/12/24 15:56:50 peter * stackpointer_alloc added for adjusting ESP. Win32 needs this for the pageprotection Revision 1.70 2002/12/05 14:39:21 florian * added missing then, Carl did you really a make fullcycle :) ? Revision 1.69 2002/12/03 22:13:39 carl * bugfix of problems with profile code which clobbers some registers Revision 1.68 2002/12/01 22:06:59 carl * warning of portabilitiy problems with parasize / localsize Revision 1.67 2002/11/30 18:44:57 carl + profiling support for Win32 Revision 1.66 2002/11/30 14:39:15 carl * try to fix profiling for win32 Revision 1.65 2002/11/28 23:28:14 florian * push_value_para didn't release floatdef locations, fixes tw2045 Revision 1.64 2002/11/27 02:33:19 peter * copy_value_on_stack method added for cdecl record passing Revision 1.63 2002/11/25 17:43:18 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.62 2002/11/18 17:31:55 peter * pass proccalloption to ret_in_xxx and push_xxx functions Revision 1.61 2002/11/17 17:49:08 mazen + return_result_reg and FUNCTION_RESULT_REG are now used, in all plateforms, to pass functions result between called function and its caller. See the explanation of each one Revision 1.60 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.59 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.58 2002/11/10 19:07:45 mazen * SPARC calling mechanism almost OK (as in GCC./mppcsparc ) Revision 1.57 2002/11/03 20:22:40 mazen * parameter handling updated Revision 1.56 2002/10/16 19:01:43 peter + $IMPLICITEXCEPTIONS switch to turn on/off generation of the implicit exception frames for procedures with initialized variables and for constructors. The default is on for compatibility Revision 1.55 2002/10/14 19:42:33 peter * only use init tables for threadvars Revision 1.54 2002/10/06 19:41:30 peter * Add finalization of typed consts * Finalization of globals in the main program Revision 1.53 2002/10/05 15:18:42 carl * fix heap leaks Revision 1.52 2002/09/30 07:00:46 florian * fixes to common code to get the alpha compiler compiled applied Revision 1.51 2002/09/22 14:02:35 carl * stack checking cannot be called before system unit is initialized * MC68020 define Revision 1.50 2002/09/17 18:54:03 jonas * a_load_reg_reg() now has two size parameters: source and dest. This allows some optimizations on architectures that don't encode the register size in the register name. Revision 1.49 2002/09/10 21:48:30 florian * improved handling of procedures with register calling conventions Revision 1.48 2002/09/07 15:25:03 peter * old logs removed and tabs fixed Revision 1.47 2002/09/02 18:44:48 peter * fixed (not) pushing of empty parameters * fixed implicit initialization/finalization generation * fixed/optimized local copy of value arguments init/final Revision 1.46 2002/09/01 19:27:34 peter * use index register when available for generating a reference with only a signle register. Using the base register could possibly destroy the framepointer Revision 1.45 2002/09/01 18:50:20 peter * fixed maybe_save that did not support a reference with only a index register. It now also updates the location with the new base register only Revision 1.44 2002/09/01 14:42:41 peter * removevaluepara added to fix the stackpointer so restoring of saved registers works Revision 1.43 2002/08/25 19:25:18 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.42 2002/08/24 18:38:26 peter * really use tt_noreuse for exception frame buffers Revision 1.41 2002/08/23 16:14:49 peter * tempgen cleanup * tt_noreuse temp type added that will be used in genentrycode Revision 1.40 2002/08/18 10:42:37 florian * remaining assembler writer bugs fixed, the errors in the system unit are inline assembler problems Revision 1.39 2002/08/17 09:23:36 florian * first part of procinfo rewrite Revision 1.38 2002/08/16 14:24:57 carl * issameref() to test if two references are the same (then emit no opcodes) + ret_in_reg to replace ret_in_acc (fix some register allocation bugs at the same time) + save_std_register now has an extra parameter which is the usedinproc registers Revision 1.37 2002/08/15 15:15:55 carl * jmpbuf size allocation for exceptions is now cpu specific (as it should) * more generic nodes for maths * several fixes for better m68k support Revision 1.36 2002/08/14 19:25:09 carl * fix Florian's last commit for m68k compilation Revision 1.35 2002/08/13 21:40:56 florian * more fixes for ppc calling conventions Revision 1.34 2002/08/12 15:08:39 carl + stab register indexes for powerpc (moved from gdb to cpubase) + tprocessor enumeration moved to cpuinfo + linker in target_info is now a class * many many updates for m68k (will soon start to compile) - removed some ifdef or correct them for correct cpu Revision 1.33 2002/08/11 14:32:27 peter * renamed current_library to objectlibrary Revision 1.32 2002/08/11 13:24:12 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.31 2002/08/09 19:16:57 carl * stack allocation is now done separately (at the end) of genentrycode so temps. can be allocated before. * fix generic exception handling Revision 1.30 2002/08/06 20:55:21 florian * first part of ppc calling conventions fix Revision 1.29 2002/08/04 19:09:22 carl + added generic exception support (still does not work!) + more documentation Revision 1.28 2002/07/29 21:23:42 florian * more fixes for the ppc + wrappers for the tcnvnode.first_* stuff introduced }