fpc/compiler/ncgmem.pas
Jonas Maebe 409dac05a4 - disabled with-symtable debugging code since it was broken and
at the same time confused the register allocator and therefore also
    the optimizer. May be fixed in the future using dwarf support
2004-04-21 17:39:40 +00:00

1262 lines
49 KiB
ObjectPascal

{
$Id$
Copyright (c) 1998-2002 by Florian Klaempfl
Generate assembler for memory related nodes which are
the same for all (most?) processors
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.
****************************************************************************
}
{ This unit generate assembler for memory related nodes.
}
unit ncgmem;
{$i fpcdefs.inc}
interface
uses
cgbase,cpuinfo,cpubase,
node,nmem;
type
tcgloadvmtaddrnode = class(tloadvmtaddrnode)
procedure pass_2;override;
end;
tcgloadparentfpnode = class(tloadparentfpnode)
procedure pass_2;override;
end;
tcgaddrnode = class(taddrnode)
procedure pass_2;override;
end;
tcgderefnode = class(tderefnode)
procedure pass_2;override;
end;
tcgsubscriptnode = class(tsubscriptnode)
procedure pass_2;override;
end;
tcgwithnode = class(twithnode)
procedure pass_2;override;
end;
tcgvecnode = class(tvecnode)
private
procedure rangecheck_array;
protected
function get_mul_size : longint;
{# This routine is used to calculate the address of the reference.
On entry reg contains the index in the array,
and l contains the size of each element in the array.
This routine should update location.reference correctly,
so it points to the correct address.
}
procedure update_reference_reg_mul(reg:tregister;l:aword);virtual;
procedure second_wideansistring;virtual;
procedure second_dynamicarray;virtual;
public
procedure pass_2;override;
end;
implementation
uses
{$ifdef delphi}
sysutils,
{$else}
strings,
{$endif}
{$ifdef GDB}
gdb,
{$endif GDB}
globtype,systems,
cutils,verbose,globals,
symconst,symdef,symsym,defutil,paramgr,
aasmbase,aasmtai,
procinfo,pass_2,
pass_1,nld,ncon,nadd,nutils,
cgutils,cgobj,
tgobj,ncgutil,symbase
;
{*****************************************************************************
TCGLOADVMTADDRNODE
*****************************************************************************}
procedure tcgloadvmtaddrnode.pass_2;
var
href : treference;
begin
location_reset(location,LOC_REGISTER,OS_ADDR);
if (left.nodetype<>typen) then
begin
{ left contains self, load vmt from self }
secondpass(left);
if is_object(left.resulttype.def) then
begin
case left.location.loc of
LOC_CREFERENCE,
LOC_REFERENCE:
begin
location_release(exprasmlist,left.location);
reference_reset_base(href,cg.getaddressregister(exprasmlist),tobjectdef(left.resulttype.def).vmt_offset);
cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,href.base);
end;
else
internalerror(200305056);
end;
end
else
begin
case left.location.loc of
LOC_REGISTER:
begin
{$ifdef cpu_uses_separate_address_registers}
if getregtype(left.location.register)<>R_ADDRESSREGISTER then
begin
location_release(exprasmlist,left.location);
reference_reset_base(href,cg.getaddressregister(exprasmlist),tobjectdef(left.resulttype.def).vmt_offset);
cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,left.location.register,href.base);
end
else
{$endif}
reference_reset_base(href,left.location.register,tobjectdef(left.resulttype.def).vmt_offset);
end;
LOC_CREGISTER,
LOC_CREFERENCE,
LOC_REFERENCE:
begin
location_release(exprasmlist,left.location);
reference_reset_base(href,cg.getaddressregister(exprasmlist),tobjectdef(left.resulttype.def).vmt_offset);
cg.a_load_loc_reg(exprasmlist,OS_ADDR,left.location,href.base);
end;
else
internalerror(200305057);
end;
end;
reference_release(exprasmlist,href);
location.register:=cg.getaddressregister(exprasmlist);
cg.g_maybe_testself(exprasmlist,href.base);
cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,href,location.register);
end
else
begin
reference_reset_symbol(href,
objectlibrary.newasmsymbol(tobjectdef(tclassrefdef(resulttype.def).pointertype.def).vmt_mangledname,AB_EXTERNAL,AT_DATA),0);
location.register:=cg.getaddressregister(exprasmlist);
cg.a_loadaddr_ref_reg(exprasmlist,href,location.register);
end;
end;
{*****************************************************************************
TCGLOADPARENTFPNODE
*****************************************************************************}
procedure tcgloadparentfpnode.pass_2;
var
currpi : tprocinfo;
hsym : tvarsym;
href : treference;
begin
if (current_procinfo.procdef.parast.symtablelevel=parentpd.parast.symtablelevel) then
begin
location_reset(location,LOC_REGISTER,OS_ADDR);
location.register:=current_procinfo.framepointer;
end
else
begin
currpi:=current_procinfo;
location_reset(location,LOC_REGISTER,OS_ADDR);
location.register:=cg.getaddressregister(exprasmlist);
{ load framepointer of current proc }
hsym:=tvarsym(currpi.procdef.parast.search('parentfp'));
if not assigned(hsym) then
internalerror(200309281);
case hsym.localloc.loc of
LOC_REFERENCE :
begin
reference_reset_base(href,hsym.localloc.reference.index,hsym.localloc.reference.offset);
cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,href,location.register);
end;
LOC_REGISTER :
cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,hsym.localloc.register,location.register);
end;
{ walk parents }
while (currpi.procdef.owner.symtablelevel>parentpd.parast.symtablelevel) do
begin
currpi:=currpi.parent;
if not assigned(currpi) then
internalerror(200311201);
hsym:=tvarsym(currpi.procdef.parast.search('parentfp'));
if not assigned(hsym) then
internalerror(200309282);
if hsym.localloc.loc<>LOC_REFERENCE then
internalerror(200309283);
reference_reset_base(href,location.register,hsym.localloc.reference.offset);
cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,href,location.register);
end;
end;
end;
{*****************************************************************************
TCGADDRNODE
*****************************************************************************}
procedure tcgaddrnode.pass_2;
begin
secondpass(left);
{ when loading procvar we do nothing with this node, so load the
location of left }
if nf_procvarload in flags then
begin
location_copy(location,left.location);
exit;
end;
location_release(exprasmlist,left.location);
location_reset(location,LOC_REGISTER,OS_ADDR);
location.register:=cg.getaddressregister(exprasmlist);
{ @ on a procvar means returning an address to the procedure that
is stored in it }
if (m_tp_procvar in aktmodeswitches) and
(left.nodetype=loadn) and
(tloadnode(left).resulttype.def.deftype=procvardef) and
assigned(tloadnode(left).symtableentry) and
(tloadnode(left).symtableentry.typ=varsym) then
cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,left.location.reference,location.register)
else
cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,location.register);
end;
{*****************************************************************************
TCGDEREFNODE
*****************************************************************************}
procedure tcgderefnode.pass_2;
var
paraloc1 : tparalocation;
begin
secondpass(left);
location_reset(location,LOC_REFERENCE,def_cgsize(resulttype.def));
case left.location.loc of
LOC_REGISTER:
begin
{$ifdef cpu_uses_separate_address_registers}
if getregtype(left.location.register)<>R_ADDRESSREGISTER then
begin
location_release(exprasmlist,left.location);
location.reference.base := cg.getaddressregister(exprasmlist);
cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,left.location.register,
location.reference.base);
end
else
{$endif}
location.reference.base := left.location.register;
end;
LOC_CREGISTER,
LOC_CREFERENCE,
LOC_REFERENCE:
begin
location_release(exprasmlist,left.location);
location.reference.base:=cg.getaddressregister(exprasmlist);
cg.a_load_loc_reg(exprasmlist,OS_ADDR,left.location,location.reference.base);
end;
end;
if (cs_gdb_heaptrc in aktglobalswitches) and
(cs_checkpointer in aktglobalswitches) and
not(cs_compilesystem in aktmoduleswitches) and
(not tpointerdef(left.resulttype.def).is_far) then
begin
paraloc1:=paramanager.getintparaloc(pocall_default,1);
paramanager.allocparaloc(exprasmlist,paraloc1);
cg.a_param_reg(exprasmlist, OS_ADDR,location.reference.base,paraloc1);
paramanager.freeparaloc(exprasmlist,paraloc1);
{ FPC_CHECKPOINTER uses saveregisters }
cg.a_call_name(exprasmlist,'FPC_CHECKPOINTER');
end;
end;
{*****************************************************************************
TCGSUBSCRIPTNODE
*****************************************************************************}
procedure tcgsubscriptnode.pass_2;
var
paraloc1 : tparalocation;
begin
secondpass(left);
if codegenerror then
exit;
{ classes and interfaces must be dereferenced implicit }
if is_class_or_interface(left.resulttype.def) then
begin
location_reset(location,LOC_REFERENCE,def_cgsize(resulttype.def));
case left.location.loc of
LOC_CREGISTER,
LOC_REGISTER:
begin
{$ifdef cpu_uses_separate_address_registers}
if getregtype(left.location.register)<>R_ADDRESSREGISTER then
begin
location_release(exprasmlist,left.location);
location.reference.base:=rg.getaddressregister(exprasmlist);
cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,
left.location.register,location.reference.base);
end
else
{$endif}
location.reference.base := left.location.register;
end;
LOC_CREFERENCE,
LOC_REFERENCE:
begin
location_release(exprasmlist,left.location);
location.reference.base:=cg.getaddressregister(exprasmlist);
cg.a_load_loc_reg(exprasmlist,OS_ADDR,left.location,location.reference.base);
end;
end;
{ implicit deferencing }
if (cs_gdb_heaptrc in aktglobalswitches) and
(cs_checkpointer in aktglobalswitches) and
not(cs_compilesystem in aktmoduleswitches) then
begin
paraloc1:=paramanager.getintparaloc(pocall_default,1);
paramanager.allocparaloc(exprasmlist,paraloc1);
cg.a_param_reg(exprasmlist, OS_ADDR,location.reference.base,paraloc1);
paramanager.freeparaloc(exprasmlist,paraloc1);
{ FPC_CHECKPOINTER uses saveregisters }
cg.a_call_name(exprasmlist,'FPC_CHECKPOINTER');
end;
end
else if is_interfacecom(left.resulttype.def) then
begin
tg.GetTempTyped(exprasmlist,left.resulttype.def,tt_normal,location.reference);
cg.a_load_loc_ref(exprasmlist,OS_ADDR,left.location,location.reference);
{ implicit deferencing also for interfaces }
if (cs_gdb_heaptrc in aktglobalswitches) and
(cs_checkpointer in aktglobalswitches) and
not(cs_compilesystem in aktmoduleswitches) then
begin
paraloc1:=paramanager.getintparaloc(pocall_default,1);
paramanager.allocparaloc(exprasmlist,paraloc1);
cg.a_param_reg(exprasmlist, OS_ADDR,location.reference.base,paraloc1);
paramanager.freeparaloc(exprasmlist,paraloc1);
{ FPC_CHECKPOINTER uses saveregisters }
cg.a_call_name(exprasmlist,'FPC_CHECKPOINTER');
end;
end
else
location_copy(location,left.location);
inc(location.reference.offset,vs.fieldoffset);
{ also update the size of the location }
location.size:=def_cgsize(resulttype.def);
end;
{*****************************************************************************
TCGWITHNODE
*****************************************************************************}
procedure tcgwithnode.pass_2;
{$ifdef WITHNODEDEBUG}
const
withlevel : longint = 0;
var
withstartlabel,withendlabel : tasmlabel;
pp : pchar;
mangled_length : longint;
refnode : tnode;
{$endif WITHNODEDEBUG}
begin
location_reset(location,LOC_VOID,OS_NO);
{$ifdef WITHNODEDEBUG}
if (cs_debuginfo in aktmoduleswitches) then
begin
{ load reference }
if (withrefnode.nodetype=derefn) and
(tderefnode(withrefnode).left.nodetype=temprefn) then
refnode:=tderefnode(withrefnode).left
else
refnode:=withrefnode;
secondpass(refnode);
location_release(exprasmlist,refnode.location);
location_freetemp(exprasmlist,refnode.location);
if not(refnode.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
internalerror(2003092810);
inc(withlevel);
objectlibrary.getaddrlabel(withstartlabel);
objectlibrary.getaddrlabel(withendlabel);
cg.a_label(exprasmlist,withstartlabel);
withdebugList.concat(Tai_stabs.Create(strpnew(
'"with'+tostr(withlevel)+':'+tostr(symtablestack.getnewtypecount)+
'=*'+tstoreddef(left.resulttype.def).numberstring+'",'+
tostr(N_LSYM)+',0,0,'+tostr(refnode.location.reference.offset))));
mangled_length:=length(current_procinfo.procdef.mangledname);
getmem(pp,mangled_length+50);
strpcopy(pp,'192,0,0,'+withstartlabel.name);
if (target_info.use_function_relative_addresses) then
begin
strpcopy(strend(pp),'-');
strpcopy(strend(pp),current_procinfo.procdef.mangledname);
end;
withdebugList.concat(Tai_stabn.Create(strnew(pp)));
end;
{$endif WITHNODEDEBUG}
if assigned(left) then
secondpass(left);
{$ifdef WITHNODEDEBUG}
if (cs_debuginfo in aktmoduleswitches) then
begin
cg.a_label(exprasmlist,withendlabel);
strpcopy(pp,'224,0,0,'+withendlabel.name);
if (target_info.use_function_relative_addresses) then
begin
strpcopy(strend(pp),'-');
strpcopy(strend(pp),current_procinfo.procdef.mangledname);
end;
withdebugList.concat(Tai_stabn.Create(strnew(pp)));
freemem(pp,mangled_length+50);
dec(withlevel);
end;
{$endif WITHNODEDEBUG}
end;
{*****************************************************************************
TCGVECNODE
*****************************************************************************}
function tcgvecnode.get_mul_size : longint;
begin
if nf_memindex in flags then
get_mul_size:=1
else
begin
if (left.resulttype.def.deftype=arraydef) then
get_mul_size:=tarraydef(left.resulttype.def).elesize
else
get_mul_size:=resulttype.def.size;
end
end;
procedure tcgvecnode.update_reference_reg_mul(reg:tregister;l:aword);
var
hreg: tregister;
begin
if location.reference.base=NR_NO then
begin
if l<>1 then
cg.a_op_const_reg(exprasmlist,OP_IMUL,OS_ADDR,l,reg);
location.reference.base:=reg;
end
else if location.reference.index=NR_NO then
begin
if l<>1 then
cg.a_op_const_reg(exprasmlist,OP_IMUL,OS_ADDR,l,reg);
location.reference.index:=reg;
end
else
begin
cg.ungetreference(exprasmlist,location.reference);
hreg := cg.getaddressregister(exprasmlist);
cg.a_loadaddr_ref_reg(exprasmlist,location.reference,hreg);
reference_reset_base(location.reference,hreg,0);
{ insert new index register }
if l<>1 then
cg.a_op_const_reg(exprasmlist,OP_IMUL,OS_ADDR,l,reg);
location.reference.index:=reg;
end;
end;
procedure tcgvecnode.second_wideansistring;
begin
end;
procedure tcgvecnode.second_dynamicarray;
begin
end;
procedure tcgvecnode.rangecheck_array;
var
freereg : boolean;
hightree : tnode;
poslabel,
neglabel : tasmlabel;
hreg : tregister;
paraloc1,paraloc2 : tparalocation;
begin
if is_open_array(left.resulttype.def) or
is_array_of_const(left.resulttype.def) then
begin
{ cdecl functions don't have high() so we can not check the range }
if not(current_procinfo.procdef.proccalloption in [pocall_cdecl,pocall_cppdecl]) then
begin
{ Get high value }
hightree:=load_high_value_node(tvarsym(tloadnode(left).symtableentry));
{ it must be available }
if not assigned(hightree) then
internalerror(200212201);
firstpass(hightree);
secondpass(hightree);
{ generate compares }
freereg:=false;
if (right.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
hreg:=right.location.register
else
begin
hreg:=cg.getintregister(exprasmlist,OS_INT);
freereg:=true;
cg.a_load_loc_reg(exprasmlist,OS_INT,right.location,hreg);
end;
objectlibrary.getlabel(neglabel);
objectlibrary.getlabel(poslabel);
cg.a_cmp_const_reg_label(exprasmlist,OS_INT,OC_LT,0,hreg,poslabel);
location_release(exprasmlist,hightree.location);
cg.a_cmp_loc_reg_label(exprasmlist,OS_INT,OC_BE,hightree.location,hreg,neglabel);
if freereg then
cg.ungetregister(exprasmlist,hreg);
cg.a_label(exprasmlist,poslabel);
cg.a_call_name(exprasmlist,'FPC_RANGEERROR');
cg.a_label(exprasmlist,neglabel);
{ release hightree }
hightree.free;
end;
end
else
if is_dynamic_array(left.resulttype.def) then
begin
paraloc1:=paramanager.getintparaloc(pocall_default,1);
paraloc2:=paramanager.getintparaloc(pocall_default,2);
paramanager.allocparaloc(exprasmlist,paraloc2);
cg.a_param_loc(exprasmlist,right.location,paraloc2);
paramanager.allocparaloc(exprasmlist,paraloc1);
cg.a_param_loc(exprasmlist,left.location,paraloc1);
paramanager.freeparaloc(exprasmlist,paraloc1);
paramanager.freeparaloc(exprasmlist,paraloc2);
cg.allocexplicitregisters(exprasmlist,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
cg.a_call_name(exprasmlist,'FPC_DYNARRAY_RANGECHECK');
cg.deallocexplicitregisters(exprasmlist,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
end
else
cg.g_rangecheck(exprasmlist,right.location,right.resulttype.def,left.resulttype.def);
end;
procedure tcgvecnode.pass_2;
var
extraoffset : longint;
t : tnode;
href : treference;
otl,ofl : tasmlabel;
newsize : tcgsize;
mulsize: longint;
isjump : boolean;
paraloc1,paraloc2 : tparalocation;
begin
mulsize := get_mul_size;
newsize:=def_cgsize(resulttype.def);
secondpass(left);
if left.location.loc=LOC_CREFERENCE then
location_reset(location,LOC_CREFERENCE,newsize)
else
location_reset(location,LOC_REFERENCE,newsize);
{ an ansistring needs to be dereferenced }
if is_ansistring(left.resulttype.def) or
is_widestring(left.resulttype.def) then
begin
if nf_callunique in flags then
internalerror(200304236);
case left.location.loc of
LOC_REGISTER,
LOC_CREGISTER :
location.reference.base:=left.location.register;
LOC_CREFERENCE,
LOC_REFERENCE :
begin
location_release(exprasmlist,left.location);
location.reference.base:=cg.getaddressregister(exprasmlist);
cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,left.location.reference,location.reference.base);
end;
else
internalerror(2002032218);
end;
{ check for a zero length string,
we can use the ansistring routine here }
if (cs_check_range in aktlocalswitches) then
begin
paraloc1:=paramanager.getintparaloc(pocall_default,1);
paramanager.allocparaloc(exprasmlist,paraloc1);
cg.a_param_reg(exprasmlist,OS_ADDR,location.reference.base,paraloc1);
paramanager.freeparaloc(exprasmlist,paraloc1);
cg.allocexplicitregisters(exprasmlist,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
cg.a_call_name(exprasmlist,'FPC_'+upper(tstringdef(left.resulttype.def).stringtypname)+'_CHECKZERO');
cg.deallocexplicitregisters(exprasmlist,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
end;
{ in ansistrings/widestrings S[1] is p<w>char(S)[0] !! }
if is_ansistring(left.resulttype.def) then
dec(location.reference.offset)
else
dec(location.reference.offset,2);
end
else if is_dynamic_array(left.resulttype.def) then
begin
case left.location.loc of
LOC_REGISTER,
LOC_CREGISTER :
location.reference.base:=left.location.register;
LOC_REFERENCE,
LOC_CREFERENCE :
begin
location_release(exprasmlist,left.location);
location.reference.base:=cg.getaddressregister(exprasmlist);
cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,
left.location.reference,location.reference.base);
end;
else
internalerror(2002032219);
end;
end
else
location_copy(location,left.location);
{ offset can only differ from 0 if arraydef }
if (left.resulttype.def.deftype=arraydef) and
not(is_dynamic_array(left.resulttype.def)) then
dec(location.reference.offset,mulsize*tarraydef(left.resulttype.def).lowrange);
if right.nodetype=ordconstn then
begin
{ offset can only differ from 0 if arraydef }
case left.resulttype.def.deftype of
arraydef :
begin
if not(is_open_array(left.resulttype.def)) and
not(is_array_of_const(left.resulttype.def)) and
not(is_dynamic_array(left.resulttype.def)) then
begin
if (tordconstnode(right).value>tarraydef(left.resulttype.def).highrange) or
(tordconstnode(right).value<tarraydef(left.resulttype.def).lowrange) then
begin
{ this should be caught in the resulttypepass! (JM) }
if (cs_check_range in aktlocalswitches) then
CGMessage(parser_e_range_check_error)
else
CGMessage(parser_w_range_check_error);
end;
end
else
begin
{ range checking for open and dynamic arrays needs
runtime code }
secondpass(right);
if (cs_check_range in aktlocalswitches) then
rangecheck_array;
end;
end;
stringdef :
begin
if (cs_check_range in aktlocalswitches) then
begin
case tstringdef(left.resulttype.def).string_typ of
{ it's the same for ansi- and wide strings }
st_widestring,
st_ansistring:
begin
paraloc1:=paramanager.getintparaloc(pocall_default,1);
paraloc2:=paramanager.getintparaloc(pocall_default,2);
paramanager.allocparaloc(exprasmlist,paraloc2);
cg.a_param_const(exprasmlist,OS_INT,tordconstnode(right).value,paraloc2);
href:=location.reference;
dec(href.offset,7);
paramanager.allocparaloc(exprasmlist,paraloc1);
cg.a_param_ref(exprasmlist,OS_INT,href,paraloc1);
paramanager.freeparaloc(exprasmlist,paraloc1);
paramanager.freeparaloc(exprasmlist,paraloc2);
cg.allocexplicitregisters(exprasmlist,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
cg.a_call_name(exprasmlist,'FPC_'+upper(tstringdef(left.resulttype.def).stringtypname)+'_RANGECHECK');
cg.deallocexplicitregisters(exprasmlist,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
end;
st_shortstring:
begin
{!!!!!!!!!!!!!!!!!}
end;
st_longstring:
begin
{!!!!!!!!!!!!!!!!!}
end;
end;
end;
end;
end;
inc(location.reference.offset,
mulsize*tordconstnode(right).value);
end
else
{ not nodetype=ordconstn }
begin
if (cs_regvars in aktglobalswitches) and
{ if we do range checking, we don't }
{ need that fancy code (it would be }
{ buggy) }
not(cs_check_range in aktlocalswitches) and
(left.resulttype.def.deftype=arraydef) then
begin
extraoffset:=0;
if (right.nodetype=addn) then
begin
if taddnode(right).right.nodetype=ordconstn then
begin
extraoffset:=tordconstnode(taddnode(right).right).value;
t:=taddnode(right).left;
{ First pass processed this with the assumption }
{ that there was an add node which may require an }
{ extra register. Fake it or die with IE10 (JM) }
t.registersint := taddnode(right).registersint;
taddnode(right).left:=nil;
right.free;
right:=t;
end
else if taddnode(right).left.nodetype=ordconstn then
begin
extraoffset:=tordconstnode(taddnode(right).left).value;
t:=taddnode(right).right;
t.registersint := right.registersint;
taddnode(right).right:=nil;
right.free;
right:=t;
end;
end
else if (right.nodetype=subn) then
begin
if taddnode(right).right.nodetype=ordconstn then
begin
extraoffset:=-tordconstnode(taddnode(right).right).value;
t:=taddnode(right).left;
t.registersint := right.registersint;
taddnode(right).left:=nil;
right.free;
right:=t;
end
{ You also have to negate right.right in this case! I can't add an
unaryminusn without causing a crash, so I've disabled it (JM)
else if right.left.nodetype=ordconstn then
begin
extraoffset:=right.left.value;
t:=right.right;
t^.registersint := right.registersint;
putnode(right);
putnode(right.left);
right:=t;
end;}
end;
inc(location.reference.offset,
mulsize*extraoffset);
end;
{ calculate from left to right }
if not(location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
internalerror(200304237);
isjump:=(right.location.loc=LOC_JUMP);
if isjump then
begin
otl:=truelabel;
objectlibrary.getlabel(truelabel);
ofl:=falselabel;
objectlibrary.getlabel(falselabel);
end;
secondpass(right);
if cs_check_range in aktlocalswitches then
begin
if left.resulttype.def.deftype=arraydef then
rangecheck_array;
end;
{ if mulsize = 1, we won't have to modify the index }
location_force_reg(exprasmlist,right.location,OS_ADDR,(mulsize = 1));
if isjump then
begin
truelabel:=otl;
falselabel:=ofl;
end;
{ produce possible range check code: }
if cs_check_range in aktlocalswitches then
begin
if left.resulttype.def.deftype=arraydef then
begin
{ done defore (PM) }
end
else if (left.resulttype.def.deftype=stringdef) then
begin
case tstringdef(left.resulttype.def).string_typ of
{ it's the same for ansi- and wide strings }
st_widestring,
st_ansistring:
begin
paraloc1:=paramanager.getintparaloc(pocall_default,1);
paraloc2:=paramanager.getintparaloc(pocall_default,2);
paramanager.allocparaloc(exprasmlist,paraloc2);
cg.a_param_reg(exprasmlist,OS_INT,right.location.register,paraloc2);
href:=location.reference;
dec(href.offset,7);
paramanager.allocparaloc(exprasmlist,paraloc1);
cg.a_param_ref(exprasmlist,OS_INT,href,paraloc1);
paramanager.freeparaloc(exprasmlist,paraloc1);
paramanager.freeparaloc(exprasmlist,paraloc2);
cg.allocexplicitregisters(exprasmlist,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
cg.a_call_name(exprasmlist,'FPC_'+upper(tstringdef(left.resulttype.def).stringtypname)+'_RANGECHECK');
cg.deallocexplicitregisters(exprasmlist,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
end;
st_shortstring:
begin
{!!!!!!!!!!!!!!!!!}
end;
st_longstring:
begin
{!!!!!!!!!!!!!!!!!}
end;
end;
end;
end;
{ insert the register and the multiplication factor in the
reference }
update_reference_reg_mul(right.location.register,mulsize);
end;
location.size:=newsize;
end;
begin
cloadvmtaddrnode:=tcgloadvmtaddrnode;
cloadparentfpnode:=tcgloadparentfpnode;
caddrnode:=tcgaddrnode;
cderefnode:=tcgderefnode;
csubscriptnode:=tcgsubscriptnode;
cwithnode:=tcgwithnode;
cvecnode:=tcgvecnode;
end.
{
$Log$
Revision 1.90 2004-04-21 17:39:40 jonas
- disabled with-symtable debugging code since it was broken and
at the same time confused the register allocator and therefore also
the optimizer. May be fixed in the future using dwarf support
Revision 1.89 2004/03/02 00:36:33 olle
* big transformation of Tai_[const_]Symbol.Create[data]name*
Revision 1.88 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.87 2004/02/20 21:55:59 peter
* procvar cleanup
Revision 1.86 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.85 2004/01/31 17:45:17 peter
* Change several $ifdef i386 to x86
* Change several OS_32 to OS_INT/OS_ADDR
Revision 1.84 2004/01/12 16:38:50 peter
* don't generate IMUL reg,1
Revision 1.83 2003/12/06 01:15:22 florian
* reverted Peter's alloctemp patch; hopefully properly
Revision 1.82 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.81 2003/11/23 17:03:35 peter
* fixed parentfp loading, it was using the offset of the current
nested proc instead of the parent
Revision 1.80 2003/11/04 15:35:13 peter
* fix for referencecounted temps
Revision 1.79 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.78 2003/10/09 21:31:37 daniel
* Register allocator splitted, ans abstract now
Revision 1.77 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.76 2003/09/29 20:58:56 peter
* optimized releasing of registers
Revision 1.75 2003/09/28 21:45:52 peter
* fix register leak in with debug
Revision 1.74 2003/09/28 17:55:03 peter
* parent framepointer changed to hidden parameter
* tloadparentfpnode added
Revision 1.73 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.72 2003/09/10 08:31:47 marco
* Patch from Peter for paraloc
Revision 1.71 2003/09/07 22:09:35 peter
* preparations for different default calling conventions
* various RA fixes
Revision 1.70 2003/09/03 15:55:00 peter
* NEWRA branch merged
Revision 1.69.2.1 2003/08/29 17:28:59 peter
* next batch of updates
Revision 1.69 2003/08/10 17:25:23 peter
* fixed some reported bugs
Revision 1.68 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.67 2003/07/23 11:01:14 jonas
* several rg.allocexplicitregistersint/rg.deallocexplicitregistersint
pairs round calls to helpers
Revision 1.66 2003/07/06 21:50:33 jonas
* fixed ppc compilation problems and changed VOLATILE_REGISTERS for x86
so that it doesn't include ebp and esp anymore
Revision 1.65 2003/07/06 15:31:20 daniel
* Fixed register allocator. *Lots* of fixes.
Revision 1.64 2003/06/17 19:24:08 jonas
* fixed conversion of fpc_*str_unique to compilerproc
Revision 1.63 2003/06/17 16:34:44 jonas
* lots of newra fixes (need getfuncretparaloc implementation for i386)!
* renamed all_intregisters to paramanager.get_volatile_registers_int(pocall_default) and made it
processor dependent
Revision 1.62 2003/06/13 21:19:30 peter
* current_procdef removed, use current_procinfo.procdef instead
Revision 1.61 2003/06/09 16:45:41 jonas
* fixed update_reference_reg_mul() so that it won't modify CREGISTERs
in a reference
* cache value of get_mul_size()
* if get_mul_size = 1, the index can be a CREGISTER since it won't be
modified
Revision 1.60 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.59 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.58 2003/06/03 13:01:59 daniel
* Register allocator finished
Revision 1.57 2003/06/02 22:35:45 florian
* better handling of CREGISTER in subscript nodes
Revision 1.56 2003/06/01 21:38:06 peter
* getregisterfpu size parameter added
* op_const_reg size parameter added
* sparc updates
Revision 1.55 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.54 2003/05/15 16:10:37 florian
* fixed getintparaloc call for ansi- and widestring range checking
Revision 1.53 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.52 2003/05/11 14:45:12 peter
* tloadnode does not support objectsymtable,withsymtable anymore
* withnode cleanup
* direct with rewritten to use temprefnode
Revision 1.51 2003/05/09 17:47:02 peter
* self moved to hidden parameter
* removed hdisposen,hnewn,selfn
Revision 1.50 2003/05/07 09:16:23 mazen
- non used units removed from uses clause
Revision 1.49 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.48 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.47 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.46 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.45 2003/04/06 21:11:23 olle
* changed newasmsymbol to newasmsymboldata for data symbols
Revision 1.44 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.43 2003/03/12 22:43:38 jonas
* more powerpc and generic fixes related to the new register allocator
Revision 1.42 2003/02/19 22:00:14 daniel
* Code generator converted to new register notation
- Horribily outdated todo.txt removed
Revision 1.41 2003/01/30 21:46:57 peter
* self fixes for static methods (merged)
Revision 1.40 2003/01/08 18:43:56 daniel
* Tregister changed into a record
Revision 1.39 2002/12/20 18:13:19 peter
* no rangecheck for openarrays with cdecl
Revision 1.38 2002/12/17 22:19:33 peter
* fixed pushing of records>8 bytes with stdcall
* simplified hightree loading
Revision 1.37 2002/12/08 13:39:03 carl
+ some documentation added
Revision 1.36 2002/12/07 14:14:19 carl
* bugfix on invalid typecast
Revision 1.35 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.34 2002/11/24 18:19:20 carl
+ checkpointer for interfaces also
Revision 1.33 2002/11/23 22:50:06 carl
* some small speed optimizations
+ added several new warnings/hints
Revision 1.32 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.31 2002/10/09 20:24:47 florian
+ range checking for dyn. arrays
Revision 1.30 2002/10/07 21:30:45 peter
* rangecheck for open arrays added
Revision 1.29 2002/10/05 12:43:25 carl
* fixes for Delphi 6 compilation
(warning : Some features do not work under Delphi)
Revision 1.28 2002/09/17 18:54:02 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.27 2002/09/07 15:25:03 peter
* old logs removed and tabs fixed
Revision 1.26 2002/09/01 18:46:01 peter
* fixed generic tcgvecnode
* move code that updates a reference with index register and multiplier
to separate method so it can be overriden for scaled indexing
* i386 uses generic tcgvecnode
Revision 1.25 2002/08/23 16:14:48 peter
* tempgen cleanup
* tt_noreuse temp type added that will be used in genentrycode
Revision 1.24 2002/08/15 08:13:54 carl
- a_load_sym_ofs_reg removed
* loadvmt now calls loadaddr_ref_reg instead
Revision 1.23 2002/08/11 14:32:26 peter
* renamed current_library to objectlibrary
Revision 1.22 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.21 2002/08/11 11:36:57 jonas
* always first try to use base and only then index
Revision 1.20 2002/08/11 06:14:40 florian
* fixed powerpc compilation problems
Revision 1.19 2002/08/10 14:46:29 carl
+ moved target_cpu_string to cpuinfo
* renamed asmmode enum.
* assembler reader has now less ifdef's
* move from nppcmem.pas -> ncgmem.pas vec. node.
Revision 1.18 2002/07/28 21:34:31 florian
* more powerpc fixes
+ dummy tcgvecnode
Revision 1.17 2002/07/11 14:41:28 florian
* start of the new generic parameter handling
Revision 1.16 2002/07/07 09:52:32 florian
* powerpc target fixed, very simple units can be compiled
* some basic stuff for better callparanode handling, far from being finished
Revision 1.15 2002/07/01 18:46:23 peter
* internal linker
* reorganized aasm layer
Revision 1.14 2002/07/01 16:23:53 peter
* cg64 patch
* basics for currency
* asnode updates for class and interface (not finished)
Revision 1.13 2002/05/20 13:30:40 carl
* bugfix of hdisponen (base must be set, not index)
* more portability fixes
Revision 1.12 2002/05/18 13:34:09 peter
* readded missing revisions
Revision 1.11 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.9 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.8 2002/04/20 21:32:23 carl
+ generic FPC_CHECKPOINTER
+ first parameter offset in stack now portable
* rename some constants
+ move some cpu stuff to other units
- remove unused constents
* fix stacksize for some targets
* fix generic size problems which depend now on EXTEND_SIZE constant
Revision 1.7 2002/04/15 18:58:47 carl
+ target_info.size_of_pointer -> pointer_Size
Revision 1.6 2002/04/04 19:05:57 peter
* removed unused units
* use tlocation.size in cg.a_*loc*() routines
}