mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-15 13:19:27 +02:00

http://svn.freepascal.org/svn/fpc/branches/unicodestring ........ r11665 | florian | 2008-08-30 13:30:17 +0200 (Sat, 30 Aug 2008) | 1 line * continued to work on unicodestring type support ........ r11666 | florian | 2008-08-30 19:02:26 +0200 (Sat, 30 Aug 2008) | 2 lines * expectloc for wide/ansi/unicode strings is LOC_CONSTANT or LOC_REGISTER now ........ r11667 | florian | 2008-08-30 20:42:37 +0200 (Sat, 30 Aug 2008) | 1 line * more unicodestring stuff fixed, test results on win32 are already good ........ r11670 | florian | 2008-08-30 23:21:48 +0200 (Sat, 30 Aug 2008) | 2 lines * first fixes for unix bootstrapping ........ r11683 | ivost | 2008-09-01 12:46:39 +0200 (Mon, 01 Sep 2008) | 2 lines * fixed 64bit bug in iconvenc.pas ........ r11689 | florian | 2008-09-01 23:12:34 +0200 (Mon, 01 Sep 2008) | 1 line * fixed several errors when building on unix ........ r11694 | florian | 2008-09-03 20:32:43 +0200 (Wed, 03 Sep 2008) | 1 line * fixed unix compilation ........ r11695 | florian | 2008-09-03 21:01:04 +0200 (Wed, 03 Sep 2008) | 1 line * bootstrapping fix ........ r11696 | florian | 2008-09-03 21:07:18 +0200 (Wed, 03 Sep 2008) | 1 line * more bootstrapping fixed ........ r11698 | florian | 2008-09-03 22:47:54 +0200 (Wed, 03 Sep 2008) | 1 line + two missing compiler procs exported ........ r11701 | florian | 2008-09-04 16:42:34 +0200 (Thu, 04 Sep 2008) | 2 lines + lazarus project for the linux rtl ........ r11702 | florian | 2008-09-04 16:43:27 +0200 (Thu, 04 Sep 2008) | 2 lines + set unicode string procedures ........ r11707 | florian | 2008-09-04 23:23:02 +0200 (Thu, 04 Sep 2008) | 2 lines * fixed several type casting stuff ........ r11712 | florian | 2008-09-05 22:46:03 +0200 (Fri, 05 Sep 2008) | 1 line * fixed unicodestring compilation on windows after recent unix changes ........ r11713 | florian | 2008-09-05 23:35:12 +0200 (Fri, 05 Sep 2008) | 1 line + UnicodeString support for Variants ........ r11715 | florian | 2008-09-06 20:59:54 +0200 (Sat, 06 Sep 2008) | 1 line * patch by Martin Schreiber for UnicodeString streaming ........ r11716 | florian | 2008-09-06 22:22:55 +0200 (Sat, 06 Sep 2008) | 2 lines * fixed test ........ r11717 | florian | 2008-09-07 10:25:51 +0200 (Sun, 07 Sep 2008) | 1 line * fixed typo when converting tunicodestring to punicodechar ........ r11718 | florian | 2008-09-07 11:29:52 +0200 (Sun, 07 Sep 2008) | 3 lines * fixed writing of UnicodeString properties * moved some helper routines to unicode headers ........ r11734 | florian | 2008-09-09 22:38:55 +0200 (Tue, 09 Sep 2008) | 1 line * fixed bootstrapping ........ r11735 | florian | 2008-09-10 11:25:28 +0200 (Wed, 10 Sep 2008) | 2 lines * first fixes for persisten unicodestrings ........ r11736 | florian | 2008-09-10 14:31:00 +0200 (Wed, 10 Sep 2008) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-11663" from http://svn.freepascal.org/svn/fpc/trunk ........ r11737 | florian | 2008-09-10 21:06:57 +0200 (Wed, 10 Sep 2008) | 3 lines * fixed unicodestring <-> variant handling * fixed unicodestring property reading ........ git-svn-id: trunk@11739 -
1170 lines
53 KiB
ObjectPascal
1170 lines
53 KiB
ObjectPascal
{
|
|
Copyright (c) 1998-2002 by Florian Klaempfl
|
|
|
|
Generate assembler for nodes that handle loads and assignments 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.
|
|
|
|
****************************************************************************
|
|
}
|
|
unit ncgld;
|
|
|
|
{$i fpcdefs.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
node,nld,cgutils;
|
|
|
|
type
|
|
tcgloadnode = class(tloadnode)
|
|
procedure pass_generate_code;override;
|
|
procedure generate_picvaraccess;virtual;
|
|
procedure changereflocation(const ref: treference);
|
|
end;
|
|
|
|
tcgassignmentnode = class(tassignmentnode)
|
|
procedure pass_generate_code;override;
|
|
end;
|
|
|
|
tcgarrayconstructornode = class(tarrayconstructornode)
|
|
procedure pass_generate_code;override;
|
|
end;
|
|
|
|
tcgrttinode = class(trttinode)
|
|
procedure pass_generate_code;override;
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
cutils,
|
|
systems,
|
|
verbose,globtype,globals,constexp,
|
|
nutils,
|
|
symconst,symtype,symdef,symsym,defutil,paramgr,
|
|
ncnv,ncon,nmem,nbas,ncgrtti,
|
|
aasmbase,aasmtai,aasmdata,aasmcpu,
|
|
cgbase,pass_2,
|
|
procinfo,
|
|
cpubase,parabase,
|
|
tgobj,ncgutil,
|
|
cgobj,
|
|
ncgbas,ncgflw;
|
|
|
|
{*****************************************************************************
|
|
SSA (for memory temps) support
|
|
*****************************************************************************}
|
|
|
|
type
|
|
preplacerefrec = ^treplacerefrec;
|
|
treplacerefrec = record
|
|
old, new: preference;
|
|
ressym: tsym;
|
|
end;
|
|
|
|
function doreplaceref(var n: tnode; para: pointer): foreachnoderesult;
|
|
var
|
|
rr: preplacerefrec absolute para;
|
|
begin
|
|
result := fen_false;
|
|
case n.nodetype of
|
|
loadn:
|
|
begin
|
|
{ regular variable }
|
|
if (tabstractvarsym(tloadnode(n).symtableentry).varoptions * [vo_is_dll_var, vo_is_thread_var] = []) and
|
|
not assigned(tloadnode(n).left) and
|
|
{ not function result, or no exit in function }
|
|
(((tloadnode(n).symtableentry <> rr^.ressym) and
|
|
not(vo_is_funcret in tabstractvarsym(tloadnode(n).symtableentry).varoptions)) or
|
|
not(fc_exit in flowcontrol)) and
|
|
{ stored in memory... }
|
|
(tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.loc in [LOC_REFERENCE]) and
|
|
{ ... at the place we are looking for }
|
|
references_equal(tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.reference,rr^.old^) then
|
|
begin
|
|
{ relocate variable }
|
|
tcgloadnode(n).changereflocation(rr^.new^);
|
|
result := fen_norecurse_true;
|
|
end;
|
|
end;
|
|
temprefn:
|
|
begin
|
|
if (ti_valid in ttemprefnode(n).tempinfo^.flags) and
|
|
{ memory temp... }
|
|
(ttemprefnode(n).tempinfo^.location.loc in [LOC_REFERENCE]) and
|
|
{ ... at the place we are looking for }
|
|
references_equal(ttemprefnode(n).tempinfo^.location.reference,rr^.old^) then
|
|
begin
|
|
{ relocate the temp }
|
|
tcgtemprefnode(n).changelocation(rr^.new^);
|
|
result := fen_norecurse_true;
|
|
end;
|
|
end;
|
|
{ optimize the searching a bit }
|
|
derefn,addrn,
|
|
calln,inlinen,casen,
|
|
addn,subn,muln,
|
|
andn,orn,xorn,
|
|
ltn,lten,gtn,gten,equaln,unequaln,
|
|
slashn,divn,shrn,shln,notn,
|
|
inn,
|
|
asn,isn:
|
|
result := fen_norecurse_false;
|
|
end;
|
|
end;
|
|
|
|
|
|
function maybechangetemp(list: TAsmList; var n: tnode; const newref: treference): boolean;
|
|
var
|
|
rr: treplacerefrec;
|
|
begin
|
|
result := false;
|
|
|
|
{ only do for -O2 or higher (breaks debugging since }
|
|
{ variables move to different memory locations) }
|
|
if not(cs_opt_level2 in current_settings.optimizerswitches) or
|
|
{ must be a copy to a memory location ... }
|
|
(n.location.loc <> LOC_REFERENCE) or
|
|
{ not inside a control flow statement and no goto's in sight }
|
|
([fc_inflowcontrol,fc_gotolabel] * flowcontrol <> []) or
|
|
{ not for refcounted types, because those locations are }
|
|
{ still used later on in initialisation/finalisation code }
|
|
(not(is_class(n.resultdef)) and
|
|
n.resultdef.needs_inittable) or
|
|
{ source and destination are temps (= not global variables) }
|
|
not tg.istemp(n.location.reference) or
|
|
not tg.istemp(newref) or
|
|
{ and both point to the start of a temp, and the source is a }
|
|
{ non-persistent temp (otherwise we need some kind of copy- }
|
|
{ on-write support in case later on both are still used) }
|
|
(tg.gettypeoftemp(newref) <> tt_normal) or
|
|
not (tg.gettypeoftemp(n.location.reference) in [tt_normal,tt_persistent]) or
|
|
{ and both have the same size }
|
|
(tg.sizeoftemp(current_asmdata.CurrAsmList,newref) <> tg.sizeoftemp(current_asmdata.CurrAsmList,n.location.reference)) then
|
|
exit;
|
|
|
|
{ find the source of the old reference (loadnode or tempnode) }
|
|
{ and replace it with the new reference }
|
|
rr.old := @n.location.reference;
|
|
rr.new := @newref;
|
|
rr.ressym := nil;
|
|
|
|
if (current_procinfo.procdef.funcretloc[calleeside].loc<>LOC_VOID) and
|
|
assigned(current_procinfo.procdef.funcretsym) and
|
|
(tabstractvarsym(current_procinfo.procdef.funcretsym).refs <> 0) then
|
|
if (current_procinfo.procdef.proctypeoption=potype_constructor) then
|
|
rr.ressym:=tsym(current_procinfo.procdef.parast.Find('self'))
|
|
else
|
|
rr.ressym:=current_procinfo.procdef.funcretsym;
|
|
|
|
{ if source not found, don't do anything }
|
|
if not foreachnodestatic(n,@doreplaceref,@rr) then
|
|
exit;
|
|
|
|
n.location.reference := newref;
|
|
result:=true;
|
|
end;
|
|
|
|
{*****************************************************************************
|
|
SecondLoad
|
|
*****************************************************************************}
|
|
|
|
procedure tcgloadnode.generate_picvaraccess;
|
|
begin
|
|
{$ifndef sparc}
|
|
location.reference.base:=current_procinfo.got;
|
|
location.reference.symbol:=current_asmdata.RefAsmSymbol(tstaticvarsym(symtableentry).mangledname+'@GOT');
|
|
{$endif sparc}
|
|
end;
|
|
|
|
|
|
procedure tcgloadnode.changereflocation(const ref: treference);
|
|
var
|
|
oldtemptype: ttemptype;
|
|
begin
|
|
if (location.loc<>LOC_REFERENCE) then
|
|
internalerror(2007020812);
|
|
if not tg.istemp(location.reference) then
|
|
internalerror(2007020813);
|
|
oldtemptype:=tg.gettypeoftemp(location.reference);
|
|
if (oldtemptype = tt_persistent) then
|
|
tg.ChangeTempType(current_asmdata.CurrAsmList,location.reference,tt_normal);
|
|
tg.ungettemp(current_asmdata.CurrAsmList,location.reference);
|
|
location.reference:=ref;
|
|
tg.ChangeTempType(current_asmdata.CurrAsmList,location.reference,oldtemptype);
|
|
tabstractnormalvarsym(symtableentry).localloc:=location;
|
|
end;
|
|
|
|
|
|
procedure tcgloadnode.pass_generate_code;
|
|
var
|
|
hregister : tregister;
|
|
vs : tabstractnormalvarsym;
|
|
gvs : tstaticvarsym;
|
|
pd : tprocdef;
|
|
href : treference;
|
|
newsize : tcgsize;
|
|
endrelocatelab,
|
|
norelocatelab : tasmlabel;
|
|
paraloc1 : tcgpara;
|
|
begin
|
|
|
|
{ we don't know the size of all arrays }
|
|
newsize:=def_cgsize(resultdef);
|
|
location_reset(location,LOC_REFERENCE,newsize);
|
|
case symtableentry.typ of
|
|
absolutevarsym :
|
|
begin
|
|
{ this is only for toasm and toaddr }
|
|
case tabsolutevarsym(symtableentry).abstyp of
|
|
toaddr :
|
|
begin
|
|
{$ifdef i386}
|
|
if tabsolutevarsym(symtableentry).absseg then
|
|
location.reference.segment:=NR_FS;
|
|
{$endif i386}
|
|
location.reference.offset:=tabsolutevarsym(symtableentry).addroffset;
|
|
end;
|
|
toasm :
|
|
location.reference.symbol:=current_asmdata.RefAsmSymbol(tabsolutevarsym(symtableentry).mangledname);
|
|
else
|
|
internalerror(200310283);
|
|
end;
|
|
end;
|
|
constsym:
|
|
begin
|
|
if tconstsym(symtableentry).consttyp=constresourcestring then
|
|
begin
|
|
location_reset(location,LOC_CREFERENCE,OS_ADDR);
|
|
location.reference.symbol:=current_asmdata.RefAsmSymbol(make_mangledname('RESSTR',symtableentry.owner,symtableentry.name));
|
|
{ Resourcestring layout:
|
|
TResourceStringRecord = Packed Record
|
|
Name,
|
|
CurrentValue,
|
|
DefaultValue : AnsiString;
|
|
HashValue : LongWord;
|
|
end;
|
|
}
|
|
location.reference.offset:=sizeof(pint);
|
|
end
|
|
else
|
|
internalerror(22798);
|
|
end;
|
|
staticvarsym :
|
|
begin
|
|
gvs:=tstaticvarsym(symtableentry);
|
|
if ([vo_is_dll_var,vo_is_external] * gvs.varoptions <> []) then
|
|
begin
|
|
location.reference.base := cg.g_indirect_sym_load(current_asmdata.CurrAsmList,tstaticvarsym(symtableentry).mangledname);
|
|
if (location.reference.base <> NR_NO) then
|
|
exit;
|
|
end;
|
|
|
|
if (vo_is_dll_var in gvs.varoptions) then
|
|
{ DLL variable }
|
|
begin
|
|
hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
|
|
location.reference.symbol:=current_asmdata.RefAsmSymbol(tstaticvarsym(symtableentry).mangledname);
|
|
cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,location.reference,hregister);
|
|
reference_reset_base(location.reference,hregister,0);
|
|
end
|
|
{ Thread variable }
|
|
else if (vo_is_thread_var in gvs.varoptions) and
|
|
not(tf_section_threadvars in target_info.flags) then
|
|
begin
|
|
if (tf_section_threadvars in target_info.flags) then
|
|
begin
|
|
if gvs.localloc.loc=LOC_INVALID then
|
|
reference_reset_symbol(location.reference,current_asmdata.RefAsmSymbol(gvs.mangledname),0)
|
|
else
|
|
location:=gvs.localloc;
|
|
{$ifdef i386}
|
|
case target_info.system of
|
|
system_i386_linux:
|
|
location.reference.segment:=NR_GS;
|
|
system_i386_win32:
|
|
location.reference.segment:=NR_FS;
|
|
end;
|
|
{$endif i386}
|
|
end
|
|
else
|
|
begin
|
|
{
|
|
Thread var loading is optimized to first check if
|
|
a relocate function is available. When the function
|
|
is available it is called to retrieve the address.
|
|
Otherwise the address is loaded with the symbol
|
|
|
|
The code needs to be in the order to first handle the
|
|
call and then the address load to be sure that the
|
|
register that is used for returning is the same (PFV)
|
|
}
|
|
current_asmdata.getjumplabel(norelocatelab);
|
|
current_asmdata.getjumplabel(endrelocatelab);
|
|
{ make sure hregister can't allocate the register necessary for the parameter }
|
|
paraloc1.init;
|
|
paramanager.getintparaloc(pocall_default,1,paraloc1);
|
|
hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
|
|
reference_reset_symbol(href,current_asmdata.RefAsmSymbol('FPC_THREADVAR_RELOCATE'),0);
|
|
cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,href,hregister);
|
|
cg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,OS_ADDR,OC_EQ,0,hregister,norelocatelab);
|
|
{ don't save the allocated register else the result will be destroyed later }
|
|
reference_reset_symbol(href,current_asmdata.RefAsmSymbol(tstaticvarsym(symtableentry).mangledname),0);
|
|
paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc1);
|
|
cg.a_param_ref(current_asmdata.CurrAsmList,OS_32,href,paraloc1);
|
|
paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc1);
|
|
paraloc1.done;
|
|
cg.allocallcpuregisters(current_asmdata.CurrAsmList);
|
|
cg.a_call_reg(current_asmdata.CurrAsmList,hregister);
|
|
cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
|
|
cg.getcpuregister(current_asmdata.CurrAsmList,NR_FUNCTION_RESULT_REG);
|
|
cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_FUNCTION_RESULT_REG);
|
|
hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
|
|
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_ADDR,NR_FUNCTION_RESULT_REG,hregister);
|
|
cg.a_jmp_always(current_asmdata.CurrAsmList,endrelocatelab);
|
|
cg.a_label(current_asmdata.CurrAsmList,norelocatelab);
|
|
{ no relocation needed, load the address of the variable only, the
|
|
layout of a threadvar is (4 bytes pointer):
|
|
0 - Threadvar index
|
|
4 - Threadvar value in single threading }
|
|
reference_reset_symbol(href,current_asmdata.RefAsmSymbol(tstaticvarsym(symtableentry).mangledname),sizeof(pint));
|
|
cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,hregister);
|
|
cg.a_label(current_asmdata.CurrAsmList,endrelocatelab);
|
|
location.reference.base:=hregister;
|
|
end;
|
|
end
|
|
{ Normal (or external) variable }
|
|
else
|
|
begin
|
|
if gvs.localloc.loc=LOC_INVALID then
|
|
reference_reset_symbol(location.reference,current_asmdata.RefAsmSymbol(gvs.mangledname),0)
|
|
else
|
|
location:=gvs.localloc;
|
|
end;
|
|
|
|
{ make const a LOC_CREFERENCE }
|
|
if (gvs.varspez=vs_const) and
|
|
(location.loc=LOC_REFERENCE) then
|
|
location.loc:=LOC_CREFERENCE;
|
|
location.reference.alignment:=gvs.vardef.alignment;
|
|
end;
|
|
paravarsym,
|
|
localvarsym :
|
|
begin
|
|
vs:=tabstractnormalvarsym(symtableentry);
|
|
{ Nested variable }
|
|
if assigned(left) then
|
|
begin
|
|
secondpass(left);
|
|
if left.location.loc<>LOC_REGISTER then
|
|
internalerror(200309286);
|
|
if vs.localloc.loc<>LOC_REFERENCE then
|
|
internalerror(200409241);
|
|
reference_reset_base(location.reference,left.location.register,vs.localloc.reference.offset);
|
|
end
|
|
else
|
|
location:=vs.localloc;
|
|
|
|
{ handle call by reference variables when they are not
|
|
alreayd copied to local copies. Also ignore the reference
|
|
when we need to load the self pointer for objects }
|
|
if is_addr_param_load then
|
|
begin
|
|
if (location.loc in [LOC_CREGISTER,LOC_REGISTER]) then
|
|
hregister:=location.register
|
|
else
|
|
begin
|
|
hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
|
|
{ we need to load only an address }
|
|
location.size:=OS_ADDR;
|
|
cg.a_load_loc_reg(current_asmdata.CurrAsmList,location.size,location,hregister);
|
|
end;
|
|
location_reset(location,LOC_REFERENCE,newsize);
|
|
location.reference.base:=hregister;
|
|
end;
|
|
|
|
{ make const a LOC_CREFERENCE }
|
|
if (vs.varspez=vs_const) and
|
|
(location.loc=LOC_REFERENCE) then
|
|
location.loc:=LOC_CREFERENCE;
|
|
end;
|
|
procsym:
|
|
begin
|
|
if not assigned(procdef) then
|
|
internalerror(200312011);
|
|
if assigned(left) then
|
|
begin
|
|
{$if sizeof(pint) = 4}
|
|
location_reset(location,LOC_CREFERENCE,OS_64);
|
|
{$else} {$if sizeof(pint) = 8}
|
|
location_reset(location,LOC_CREFERENCE,OS_128);
|
|
{$else}
|
|
internalerror(20020520);
|
|
{$endif} {$endif}
|
|
tg.GetTemp(current_asmdata.CurrAsmList,2*sizeof(pint),tt_normal,location.reference);
|
|
secondpass(left);
|
|
|
|
{ load class instance/classrefdef address }
|
|
if left.location.loc=LOC_CONSTANT then
|
|
location_force_reg(current_asmdata.CurrAsmList,left.location,OS_ADDR,false);
|
|
case left.location.loc of
|
|
LOC_CREGISTER,
|
|
LOC_REGISTER:
|
|
begin
|
|
{ this is not possible for objects }
|
|
if is_object(left.resultdef) then
|
|
internalerror(200304234);
|
|
hregister:=left.location.register;
|
|
end;
|
|
LOC_CREFERENCE,
|
|
LOC_REFERENCE:
|
|
begin
|
|
hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
|
|
if not is_object(left.resultdef) then
|
|
cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,left.location.reference,hregister)
|
|
else
|
|
cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.location.reference,hregister);
|
|
location_freetemp(current_asmdata.CurrAsmList,left.location);
|
|
end;
|
|
else
|
|
internalerror(200610311);
|
|
end;
|
|
|
|
{ store the class instance or classredef address }
|
|
href:=location.reference;
|
|
inc(href.offset,sizeof(pint));
|
|
cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,hregister,href);
|
|
|
|
{ virtual method ? }
|
|
if (po_virtualmethod in procdef.procoptions) and
|
|
not(nf_inherited in flags) then
|
|
begin
|
|
{ a classrefdef already points to the VMT }
|
|
if (left.resultdef.typ<>classrefdef) then
|
|
begin
|
|
{ load vmt pointer }
|
|
reference_reset_base(href,hregister,0);
|
|
hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
|
|
cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,href,hregister);
|
|
end;
|
|
{ load method address }
|
|
reference_reset_base(href,hregister,procdef._class.vmtmethodoffset(procdef.extnumber));
|
|
hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
|
|
cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,href,hregister);
|
|
{ ... and store it }
|
|
cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,hregister,location.reference);
|
|
end
|
|
else
|
|
begin
|
|
{ load address of the function }
|
|
reference_reset_symbol(href,current_asmdata.RefAsmSymbol(procdef.mangledname),0);
|
|
hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
|
|
cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,hregister);
|
|
cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,hregister,location.reference);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
pd:=tprocdef(tprocsym(symtableentry).ProcdefList[0]);
|
|
if (po_external in pd.procoptions) then
|
|
location.reference.base := cg.g_indirect_sym_load(current_asmdata.CurrAsmList,pd.mangledname);
|
|
{!!!!! Be aware, work on virtual methods too }
|
|
if (location.reference.base = NR_NO) then
|
|
location.reference.symbol:=current_asmdata.RefAsmSymbol(procdef.mangledname);
|
|
end;
|
|
end;
|
|
labelsym :
|
|
location.reference.symbol:=tcglabelnode((tlabelsym(symtableentry).code)).getasmlabel;
|
|
else internalerror(200510032);
|
|
end;
|
|
end;
|
|
|
|
|
|
{*****************************************************************************
|
|
SecondAssignment
|
|
*****************************************************************************}
|
|
|
|
procedure tcgassignmentnode.pass_generate_code;
|
|
var
|
|
otlabel,hlabel,oflabel : tasmlabel;
|
|
href : treference;
|
|
releaseright : boolean;
|
|
len : aint;
|
|
r : tregister;
|
|
oldflowcontrol : tflowcontrol;
|
|
begin
|
|
location_reset(location,LOC_VOID,OS_NO);
|
|
|
|
otlabel:=current_procinfo.CurrTrueLabel;
|
|
oflabel:=current_procinfo.CurrFalseLabel;
|
|
current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel);
|
|
current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel);
|
|
|
|
{
|
|
in most cases we can process first the right node which contains
|
|
the most complex code. Exceptions for this are:
|
|
- result is in flags, loading left will then destroy the flags
|
|
- result is a jump, loading left must be already done before the jump is made
|
|
- result need reference count, when left points to a value used in
|
|
right then decreasing the refcnt on left can possibly release
|
|
the memory before right increased the refcnt, result is that an
|
|
empty value is assigned
|
|
|
|
But not when the result is in the flags, then
|
|
loading the left node afterwards can destroy the flags.
|
|
}
|
|
if not(right.expectloc in [LOC_FLAGS,LOC_JUMP]) and
|
|
((right.resultdef.needs_inittable) or
|
|
(node_complexity(right)>node_complexity(left))) then
|
|
begin
|
|
secondpass(right);
|
|
{ increment source reference counter, this is
|
|
useless for constants }
|
|
if (right.resultdef.needs_inittable) and
|
|
not is_constnode(right) then
|
|
begin
|
|
location_force_mem(current_asmdata.CurrAsmList,right.location);
|
|
location_get_data_ref(current_asmdata.CurrAsmList,right.location,href,false);
|
|
cg.g_incrrefcount(current_asmdata.CurrAsmList,right.resultdef,href);
|
|
end;
|
|
if codegenerror then
|
|
exit;
|
|
|
|
{ left can't be never a 64 bit LOC_REGISTER, so the 3. arg }
|
|
{ can be false }
|
|
secondpass(left);
|
|
{ decrement destination reference counter }
|
|
if (left.resultdef.needs_inittable) then
|
|
begin
|
|
location_get_data_ref(current_asmdata.CurrAsmList,left.location,href,false);
|
|
cg.g_decrrefcount(current_asmdata.CurrAsmList,left.resultdef,href);
|
|
end;
|
|
if codegenerror then
|
|
exit;
|
|
end
|
|
else
|
|
begin
|
|
{ calculate left sides }
|
|
secondpass(left);
|
|
{ decrement destination reference counter }
|
|
if (left.resultdef.needs_inittable) then
|
|
begin
|
|
location_get_data_ref(current_asmdata.CurrAsmList,left.location,href,false);
|
|
cg.g_decrrefcount(current_asmdata.CurrAsmList,left.resultdef,href);
|
|
end;
|
|
if codegenerror then
|
|
exit;
|
|
|
|
{ tell the SSA/SSL code that the left side was handled first so
|
|
ni SSL is done
|
|
}
|
|
oldflowcontrol:=flowcontrol;
|
|
include(flowcontrol,fc_lefthandled);
|
|
|
|
{ left can't be never a 64 bit LOC_REGISTER, so the 3. arg }
|
|
{ can be false }
|
|
secondpass(right);
|
|
flowcontrol:=oldflowcontrol;
|
|
{ increment source reference counter, this is
|
|
useless for string constants}
|
|
if (right.resultdef.needs_inittable) and
|
|
(right.nodetype<>stringconstn) then
|
|
begin
|
|
location_force_mem(current_asmdata.CurrAsmList,right.location);
|
|
location_get_data_ref(current_asmdata.CurrAsmList,right.location,href,false);
|
|
cg.g_incrrefcount(current_asmdata.CurrAsmList,right.resultdef,href);
|
|
end;
|
|
|
|
if codegenerror then
|
|
exit;
|
|
end;
|
|
|
|
releaseright:=true;
|
|
|
|
{ shortstring assignments are handled separately }
|
|
if is_shortstring(left.resultdef) then
|
|
begin
|
|
{
|
|
we can get here only in the following situations
|
|
for the right node:
|
|
- empty constant string
|
|
- char
|
|
}
|
|
|
|
{ The addn is replaced by a blockn or calln that already returns
|
|
a shortstring }
|
|
if is_shortstring(right.resultdef) and
|
|
(right.nodetype in [blockn,calln]) then
|
|
begin
|
|
{ nothing to do }
|
|
end
|
|
{ empty constant string }
|
|
else if (right.nodetype=stringconstn) and
|
|
(tstringconstnode(right).len=0) then
|
|
begin
|
|
cg.a_load_const_ref(current_asmdata.CurrAsmList,OS_8,0,left.location.reference);
|
|
end
|
|
{ char loading }
|
|
else if is_char(right.resultdef) then
|
|
begin
|
|
if right.nodetype=ordconstn then
|
|
begin
|
|
if (target_info.endian = endian_little) then
|
|
cg.a_load_const_ref(current_asmdata.CurrAsmList,OS_16,(tordconstnode(right).value.svalue shl 8) or 1,
|
|
setalignment(left.location.reference,1))
|
|
else
|
|
cg.a_load_const_ref(current_asmdata.CurrAsmList,OS_16,tordconstnode(right).value.svalue or (1 shl 8),
|
|
setalignment(left.location.reference,1));
|
|
end
|
|
else
|
|
begin
|
|
href:=left.location.reference;
|
|
cg.a_load_const_ref(current_asmdata.CurrAsmList,OS_8,1,href);
|
|
inc(href.offset,1);
|
|
case right.location.loc of
|
|
LOC_REGISTER,
|
|
LOC_CREGISTER :
|
|
begin
|
|
r:=cg.makeregsize(current_asmdata.CurrAsmList,right.location.register,OS_8);
|
|
cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_8,OS_8,r,href);
|
|
end;
|
|
LOC_REFERENCE,
|
|
LOC_CREFERENCE :
|
|
cg.a_load_ref_ref(current_asmdata.CurrAsmList,OS_8,OS_8,right.location.reference,href);
|
|
else
|
|
internalerror(200205111);
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
internalerror(200204249);
|
|
end
|
|
{ try to reuse memory locations instead of copying }
|
|
{ copy to a memory location ... }
|
|
else if (right.location.loc = LOC_REFERENCE) and
|
|
maybechangetemp(current_asmdata.CurrAsmList,left,right.location.reference) then
|
|
begin
|
|
{ if it worked, we're done }
|
|
end
|
|
else
|
|
begin
|
|
{ SSA support }
|
|
maybechangeloadnodereg(current_asmdata.CurrAsmList,left,false);
|
|
maybechangeloadnodereg(current_asmdata.CurrAsmList,right,true);
|
|
case right.location.loc of
|
|
LOC_CONSTANT :
|
|
begin
|
|
{$ifndef cpu64bitalu}
|
|
if (left.location.size in [OS_64,OS_S64]) or (right.location.size in [OS_64,OS_S64]) then
|
|
cg64.a_load64_const_loc(current_asmdata.CurrAsmList,right.location.value64,left.location)
|
|
else
|
|
{$endif not cpu64bitalu}
|
|
cg.a_load_const_loc(current_asmdata.CurrAsmList,right.location.value,left.location);
|
|
end;
|
|
LOC_REFERENCE,
|
|
LOC_CREFERENCE :
|
|
begin
|
|
case left.location.loc of
|
|
LOC_REGISTER,
|
|
LOC_CREGISTER :
|
|
begin
|
|
{$ifndef cpu64bitalu}
|
|
if left.location.size in [OS_64,OS_S64] then
|
|
cg64.a_load64_ref_reg(current_asmdata.CurrAsmList,right.location.reference,left.location.register64)
|
|
else
|
|
{$endif not cpu64bitalu}
|
|
cg.a_load_ref_reg(current_asmdata.CurrAsmList,right.location.size,left.location.size,right.location.reference,left.location.register);
|
|
end;
|
|
LOC_FPUREGISTER,
|
|
LOC_CFPUREGISTER :
|
|
begin
|
|
cg.a_loadfpu_ref_reg(current_asmdata.CurrAsmList,
|
|
right.location.size,left.location.size,
|
|
right.location.reference,
|
|
left.location.register);
|
|
end;
|
|
LOC_REFERENCE,
|
|
LOC_CREFERENCE :
|
|
begin
|
|
if (left.resultdef.typ=floatdef) and
|
|
(right.resultdef.typ=floatdef) and
|
|
(left.location.size<>right.location.size) then
|
|
begin
|
|
cg.a_loadfpu_ref_ref(current_asmdata.CurrAsmList,
|
|
right.location.size,left.location.size,
|
|
right.location.reference,left.location.reference)
|
|
end
|
|
else
|
|
begin
|
|
{ TODO: HACK: unaligned test, maybe remove all unaligned locations (array of char) from the compiler}
|
|
{ Use unaligned copy when the offset is not aligned }
|
|
len:=left.resultdef.size;
|
|
if (right.location.reference.offset mod sizeof(aint)<>0) or
|
|
(left.location.reference.offset mod sizeof(aint)<>0) or
|
|
(right.resultdef.alignment<sizeof(aint)) or
|
|
((right.location.reference.alignment<>0) and
|
|
(right.location.reference.alignment<sizeof(aint))) or
|
|
((left.location.reference.alignment<>0) and
|
|
(left.location.reference.alignment<sizeof(aint))) then
|
|
cg.g_concatcopy_unaligned(current_asmdata.CurrAsmList,right.location.reference,left.location.reference,len)
|
|
else
|
|
cg.g_concatcopy(current_asmdata.CurrAsmList,right.location.reference,left.location.reference,len);
|
|
end;
|
|
end;
|
|
LOC_MMREGISTER,
|
|
LOC_CMMREGISTER:
|
|
begin
|
|
{$ifdef x86}
|
|
if not use_sse(right.resultdef) then
|
|
begin
|
|
{ perform size conversion if needed (the mm-code cannot }
|
|
{ convert an extended into a double/single, since sse }
|
|
{ doesn't support extended) }
|
|
r:=cg.getfpuregister(current_asmdata.CurrAsmList,right.location.size);
|
|
tg.gettemp(current_asmdata.CurrAsmList,left.resultdef.size,tt_normal,href);
|
|
cg.a_loadfpu_ref_reg(current_asmdata.CurrAsmList,right.location.size,right.location.size,right.location.reference,r);
|
|
cg.a_loadfpu_reg_ref(current_asmdata.CurrAsmList,right.location.size,left.location.size,r,href);
|
|
if releaseright then
|
|
location_freetemp(current_asmdata.CurrAsmList,right.location);
|
|
releaseright:=true;
|
|
location_reset(right.location,LOC_REFERENCE,left.location.size);
|
|
right.location.reference:=href;
|
|
end;
|
|
{$endif}
|
|
cg.a_loadmm_ref_reg(current_asmdata.CurrAsmList,
|
|
right.location.size,
|
|
left.location.size,
|
|
right.location.reference,
|
|
left.location.register,mms_movescalar);
|
|
end;
|
|
LOC_SUBSETREG,
|
|
LOC_CSUBSETREG:
|
|
cg.a_load_ref_subsetreg(current_asmdata.CurrAsmList,right.location.size,left.location.size,right.location.reference,left.location.sreg);
|
|
LOC_SUBSETREF,
|
|
LOC_CSUBSETREF:
|
|
{$ifndef cpu64bitalu}
|
|
if right.location.size in [OS_64,OS_S64] then
|
|
cg64.a_load64_ref_subsetref(current_asmdata.CurrAsmList,right.location.reference,left.location.sref)
|
|
else
|
|
{$endif not cpu64bitalu}
|
|
cg.a_load_ref_subsetref(current_asmdata.CurrAsmList,right.location.size,left.location.size,right.location.reference,left.location.sref);
|
|
else
|
|
internalerror(200203284);
|
|
end;
|
|
end;
|
|
{$ifdef SUPPORT_MMX}
|
|
LOC_CMMXREGISTER,
|
|
LOC_MMXREGISTER:
|
|
begin
|
|
if left.location.loc=LOC_CMMXREGISTER then
|
|
cg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,OS_M64,OS_M64,right.location.register,left.location.register,nil)
|
|
else
|
|
cg.a_loadmm_reg_ref(current_asmdata.CurrAsmList,OS_M64,OS_M64,right.location.register,left.location.reference,nil);
|
|
end;
|
|
{$endif SUPPORT_MMX}
|
|
LOC_MMREGISTER,
|
|
LOC_CMMREGISTER:
|
|
begin
|
|
if left.resultdef.typ=arraydef then
|
|
begin
|
|
end
|
|
else
|
|
begin
|
|
if left.location.loc=LOC_CMMREGISTER then
|
|
cg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,right.location.size,left.location.size,right.location.register,left.location.register,mms_movescalar)
|
|
else
|
|
cg.a_loadmm_reg_ref(current_asmdata.CurrAsmList,right.location.size,left.location.size,right.location.register,left.location.reference,mms_movescalar);
|
|
end;
|
|
end;
|
|
LOC_REGISTER,
|
|
LOC_CREGISTER :
|
|
begin
|
|
{$ifndef cpu64bitalu}
|
|
if left.location.size in [OS_64,OS_S64] then
|
|
cg64.a_load64_reg_loc(current_asmdata.CurrAsmList,
|
|
right.location.register64,left.location)
|
|
else
|
|
{$endif not cpu64bitalu}
|
|
cg.a_load_reg_loc(current_asmdata.CurrAsmList,right.location.size,right.location.register,left.location);
|
|
end;
|
|
LOC_FPUREGISTER,
|
|
LOC_CFPUREGISTER :
|
|
begin
|
|
{ we can't do direct moves between fpu and mm registers }
|
|
if left.location.loc in [LOC_MMREGISTER,LOC_CMMREGISTER] then
|
|
begin
|
|
{$ifdef x86}
|
|
if not use_sse(right.resultdef) then
|
|
begin
|
|
{ perform size conversion if needed (the mm-code cannot convert an }
|
|
{ extended into a double/single, since sse doesn't support extended) }
|
|
tg.gettemp(current_asmdata.CurrAsmList,left.resultdef.size,tt_normal,href);
|
|
cg.a_loadfpu_reg_ref(current_asmdata.CurrAsmList,right.location.size,left.location.size,right.location.register,href);
|
|
location_reset(right.location,LOC_REFERENCE,left.location.size);
|
|
right.location.reference:=href;
|
|
end;
|
|
{$endif}
|
|
location_force_mmregscalar(current_asmdata.CurrAsmList,right.location,false);
|
|
cg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,
|
|
right.location.size,left.location.size,
|
|
right.location.register,left.location.register,mms_movescalar);
|
|
end
|
|
else
|
|
cg.a_loadfpu_reg_loc(current_asmdata.CurrAsmList,
|
|
right.location.size,
|
|
right.location.register,left.location);
|
|
end;
|
|
LOC_SUBSETREG,
|
|
LOC_CSUBSETREG:
|
|
begin
|
|
cg.a_load_subsetreg_loc(current_asmdata.CurrAsmList,
|
|
right.location.size,right.location.sreg,left.location);
|
|
end;
|
|
LOC_SUBSETREF,
|
|
LOC_CSUBSETREF:
|
|
begin
|
|
{$ifndef cpu64bitalu}
|
|
if right.location.size in [OS_64,OS_S64] then
|
|
cg64.a_load64_subsetref_loc(current_asmdata.CurrAsmList,right.location.sref,left.location)
|
|
else
|
|
{$endif not cpu64bitalu}
|
|
cg.a_load_subsetref_loc(current_asmdata.CurrAsmList,
|
|
right.location.size,right.location.sref,left.location);
|
|
end;
|
|
LOC_JUMP :
|
|
begin
|
|
current_asmdata.getjumplabel(hlabel);
|
|
cg.a_label(current_asmdata.CurrAsmList,current_procinfo.CurrTrueLabel);
|
|
if is_pasbool(left.resultdef) then
|
|
cg.a_load_const_loc(current_asmdata.CurrAsmList,1,left.location)
|
|
else
|
|
cg.a_load_const_loc(current_asmdata.CurrAsmList,-1,left.location);
|
|
cg.a_jmp_always(current_asmdata.CurrAsmList,hlabel);
|
|
cg.a_label(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
|
|
cg.a_load_const_loc(current_asmdata.CurrAsmList,0,left.location);
|
|
cg.a_label(current_asmdata.CurrAsmList,hlabel);
|
|
end;
|
|
{$ifdef cpuflags}
|
|
LOC_FLAGS :
|
|
begin
|
|
if is_pasbool(left.resultdef) then
|
|
begin
|
|
case left.location.loc of
|
|
LOC_REGISTER,LOC_CREGISTER:
|
|
cg.g_flags2reg(current_asmdata.CurrAsmList,left.location.size,right.location.resflags,left.location.register);
|
|
LOC_REFERENCE:
|
|
cg.g_flags2ref(current_asmdata.CurrAsmList,left.location.size,right.location.resflags,left.location.reference);
|
|
LOC_SUBSETREG,LOC_SUBSETREF:
|
|
begin
|
|
r:=cg.getintregister(current_asmdata.CurrAsmList,left.location.size);
|
|
cg.g_flags2reg(current_asmdata.CurrAsmList,left.location.size,right.location.resflags,r);
|
|
cg.a_load_reg_loc(current_asmdata.CurrAsmList,left.location.size,r,left.location);
|
|
end;
|
|
else
|
|
internalerror(200203273);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
r:=cg.getintregister(current_asmdata.CurrAsmList,left.location.size);
|
|
cg.g_flags2reg(current_asmdata.CurrAsmList,left.location.size,right.location.resflags,r);
|
|
cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_NEG,left.location.size,r,r);
|
|
cg.a_load_reg_loc(current_asmdata.CurrAsmList,left.location.size,r,left.location);
|
|
end;
|
|
end;
|
|
{$endif cpuflags}
|
|
end;
|
|
end;
|
|
|
|
if releaseright then
|
|
location_freetemp(current_asmdata.CurrAsmList,right.location);
|
|
|
|
current_procinfo.CurrTrueLabel:=otlabel;
|
|
current_procinfo.CurrFalseLabel:=oflabel;
|
|
end;
|
|
|
|
|
|
{*****************************************************************************
|
|
SecondArrayConstruct
|
|
*****************************************************************************}
|
|
|
|
const
|
|
vtInteger = 0;
|
|
vtBoolean = 1;
|
|
vtChar = 2;
|
|
vtExtended = 3;
|
|
vtString = 4;
|
|
vtPointer = 5;
|
|
vtPChar = 6;
|
|
vtObject = 7;
|
|
vtClass = 8;
|
|
vtWideChar = 9;
|
|
vtPWideChar = 10;
|
|
vtAnsiString32 = 11;
|
|
vtCurrency = 12;
|
|
vtVariant = 13;
|
|
vtInterface = 14;
|
|
vtWideString = 15;
|
|
vtInt64 = 16;
|
|
vtQWord = 17;
|
|
vtAnsiString16 = 18;
|
|
vtAnsiString64 = 19;
|
|
|
|
procedure tcgarrayconstructornode.pass_generate_code;
|
|
var
|
|
hp : tarrayconstructornode;
|
|
href : treference;
|
|
lt : tdef;
|
|
vaddr : boolean;
|
|
vtype : longint;
|
|
freetemp,
|
|
dovariant : boolean;
|
|
elesize : longint;
|
|
tmpreg : tregister;
|
|
paraloc : tcgparalocation;
|
|
otlabel,
|
|
oflabel : tasmlabel;
|
|
begin
|
|
if is_packed_array(resultdef) then
|
|
internalerror(200608042);
|
|
dovariant:=(nf_forcevaria in flags) or is_variant_array(resultdef);
|
|
if dovariant then
|
|
elesize:=sizeof(pint)+sizeof(pint)
|
|
else
|
|
elesize:=tarraydef(resultdef).elesize;
|
|
location_reset(location,LOC_CREFERENCE,OS_NO);
|
|
fillchar(paraloc,sizeof(paraloc),0);
|
|
{ Allocate always a temp, also if no elements are required, to
|
|
be sure that location is valid (PFV) }
|
|
if tarraydef(resultdef).highrange=-1 then
|
|
tg.GetTemp(current_asmdata.CurrAsmList,elesize,tt_normal,location.reference)
|
|
else
|
|
tg.GetTemp(current_asmdata.CurrAsmList,(tarraydef(resultdef).highrange+1)*elesize,tt_normal,location.reference);
|
|
href:=location.reference;
|
|
{ Process nodes in array constructor }
|
|
hp:=self;
|
|
while assigned(hp) do
|
|
begin
|
|
if assigned(hp.left) then
|
|
begin
|
|
freetemp:=true;
|
|
if (hp.left.expectloc=LOC_JUMP) then
|
|
begin
|
|
otlabel:=current_procinfo.CurrTrueLabel;
|
|
oflabel:=current_procinfo.CurrFalseLabel;
|
|
current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel);
|
|
current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel);
|
|
end;
|
|
secondpass(hp.left);
|
|
{ Move flags and jump in register }
|
|
if hp.left.location.loc in [LOC_FLAGS,LOC_JUMP] then
|
|
location_force_reg(current_asmdata.CurrAsmList,hp.left.location,def_cgsize(hp.left.resultdef),false);
|
|
|
|
if (hp.left.location.loc=LOC_JUMP) then
|
|
begin
|
|
if (hp.left.expectloc<>LOC_JUMP) then
|
|
internalerror(2007103101);
|
|
current_procinfo.CurrTrueLabel:=otlabel;
|
|
current_procinfo.CurrFalseLabel:=oflabel;
|
|
end;
|
|
|
|
if dovariant then
|
|
begin
|
|
{ find the correct vtype value }
|
|
vtype:=$ff;
|
|
vaddr:=false;
|
|
lt:=hp.left.resultdef;
|
|
case lt.typ of
|
|
enumdef,
|
|
orddef :
|
|
begin
|
|
if is_64bit(lt) then
|
|
begin
|
|
case torddef(lt).ordtype of
|
|
scurrency:
|
|
vtype:=vtCurrency;
|
|
s64bit:
|
|
vtype:=vtInt64;
|
|
u64bit:
|
|
vtype:=vtQWord;
|
|
end;
|
|
freetemp:=false;
|
|
vaddr:=true;
|
|
end
|
|
else if (lt.typ=enumdef) or
|
|
is_integer(lt) then
|
|
vtype:=vtInteger
|
|
else
|
|
if is_boolean(lt) then
|
|
vtype:=vtBoolean
|
|
else
|
|
if (lt.typ=orddef) then
|
|
begin
|
|
case torddef(lt).ordtype of
|
|
uchar:
|
|
vtype:=vtChar;
|
|
uwidechar:
|
|
vtype:=vtWideChar;
|
|
end;
|
|
end;
|
|
end;
|
|
floatdef :
|
|
begin
|
|
if is_currency(lt) then
|
|
vtype:=vtCurrency
|
|
else
|
|
vtype:=vtExtended;
|
|
freetemp:=false;
|
|
vaddr:=true;
|
|
end;
|
|
procvardef,
|
|
pointerdef :
|
|
begin
|
|
if is_pchar(lt) then
|
|
vtype:=vtPChar
|
|
else if is_pwidechar(lt) then
|
|
vtype:=vtPWideChar
|
|
else
|
|
vtype:=vtPointer;
|
|
end;
|
|
variantdef :
|
|
begin
|
|
vtype:=vtVariant;
|
|
vaddr:=true;
|
|
freetemp:=false;
|
|
end;
|
|
classrefdef :
|
|
vtype:=vtClass;
|
|
objectdef :
|
|
if is_interface(lt) then
|
|
vtype:=vtInterface
|
|
{ vtObject really means a class based on TObject }
|
|
else if is_class(lt) then
|
|
vtype:=vtObject
|
|
else
|
|
internalerror(200505171);
|
|
stringdef :
|
|
begin
|
|
if is_shortstring(lt) then
|
|
begin
|
|
vtype:=vtString;
|
|
vaddr:=true;
|
|
freetemp:=false;
|
|
end
|
|
else
|
|
if is_ansistring(lt) then
|
|
begin
|
|
vtype:=vtAnsiString;
|
|
freetemp:=false;
|
|
end
|
|
else
|
|
if is_widestring(lt) or is_unicodestring(lt) then
|
|
begin
|
|
vtype:=vtWideString;
|
|
freetemp:=false;
|
|
end;
|
|
end;
|
|
end;
|
|
if vtype=$ff then
|
|
internalerror(14357);
|
|
{ write changing field update href to the next element }
|
|
inc(href.offset,sizeof(pint));
|
|
if vaddr then
|
|
begin
|
|
location_force_mem(current_asmdata.CurrAsmList,hp.left.location);
|
|
tmpreg:=cg.getaddressregister(current_asmdata.CurrAsmList);
|
|
cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,hp.left.location.reference,tmpreg);
|
|
cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,tmpreg,href);
|
|
end
|
|
else
|
|
cg.a_load_loc_ref(current_asmdata.CurrAsmList,OS_ADDR,hp.left.location,href);
|
|
{ update href to the vtype field and write it }
|
|
dec(href.offset,sizeof(pint));
|
|
cg.a_load_const_ref(current_asmdata.CurrAsmList, OS_INT,vtype,href);
|
|
{ goto next array element }
|
|
inc(href.offset,sizeof(pint)*2);
|
|
end
|
|
else
|
|
{ normal array constructor of the same type }
|
|
begin
|
|
if resultdef.needs_inittable then
|
|
freetemp:=false;
|
|
case hp.left.location.loc of
|
|
LOC_MMREGISTER,
|
|
LOC_CMMREGISTER:
|
|
cg.a_loadmm_reg_ref(current_asmdata.CurrAsmList,hp.left.location.size,hp.left.location.size,
|
|
hp.left.location.register,href,mms_movescalar);
|
|
LOC_FPUREGISTER,
|
|
LOC_CFPUREGISTER :
|
|
cg.a_loadfpu_reg_ref(current_asmdata.CurrAsmList,hp.left.location.size,hp.left.location.size,hp.left.location.register,href);
|
|
LOC_REFERENCE,
|
|
LOC_CREFERENCE :
|
|
begin
|
|
if is_shortstring(hp.left.resultdef) then
|
|
cg.g_copyshortstring(current_asmdata.CurrAsmList,hp.left.location.reference,href,
|
|
Tstringdef(hp.left.resultdef).len)
|
|
else
|
|
cg.g_concatcopy(current_asmdata.CurrAsmList,hp.left.location.reference,href,elesize);
|
|
end;
|
|
else
|
|
begin
|
|
{$ifndef cpu64bitalu}
|
|
if hp.left.location.size in [OS_64,OS_S64] then
|
|
cg64.a_load64_loc_ref(current_asmdata.CurrAsmList,hp.left.location,href)
|
|
else
|
|
{$endif not cpu64bitalu}
|
|
cg.a_load_loc_ref(current_asmdata.CurrAsmList,hp.left.location.size,hp.left.location,href);
|
|
end;
|
|
end;
|
|
inc(href.offset,elesize);
|
|
end;
|
|
if freetemp then
|
|
location_freetemp(current_asmdata.CurrAsmList,hp.left.location);
|
|
end;
|
|
{ load next entry }
|
|
hp:=tarrayconstructornode(hp.right);
|
|
end;
|
|
end;
|
|
|
|
|
|
{*****************************************************************************
|
|
SecondRTTI
|
|
*****************************************************************************}
|
|
|
|
procedure tcgrttinode.pass_generate_code;
|
|
begin
|
|
location_reset(location,LOC_CREFERENCE,OS_NO);
|
|
case rttidatatype of
|
|
rdt_normal:
|
|
location.reference.symbol:=RTTIWriter.get_rtti_label(rttidef,rttitype);
|
|
rdt_ord2str:
|
|
location.reference.symbol:=RTTIWriter.get_rtti_label_ord2str(rttidef,rttitype);
|
|
rdt_str2ord:
|
|
location.reference.symbol:=RTTIWriter.get_rtti_label_str2ord(rttidef,rttitype);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
begin
|
|
cloadnode:=tcgloadnode;
|
|
cassignmentnode:=tcgassignmentnode;
|
|
carrayconstructornode:=tcgarrayconstructornode;
|
|
crttinode:=tcgrttinode;
|
|
end.
|