mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-26 15:33:40 +02:00
1595 lines
57 KiB
ObjectPascal
1595 lines
57 KiB
ObjectPascal
{
|
|
$Id$
|
|
Copyright (c) 1998-2002 by Florian Klaempfl, Daniel Mantione
|
|
|
|
Does the parsing and codegeneration at subroutine level
|
|
|
|
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 psub;
|
|
|
|
{$i fpcdefs.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
cclasses,
|
|
node,
|
|
symdef,cgbase;
|
|
|
|
type
|
|
tcgprocinfo=class(tprocinfo)
|
|
{ code for the subroutine as tree }
|
|
code : tnode;
|
|
{ list to store the procinfo's of the nested procedures }
|
|
nestedprocs : tlinkedlist;
|
|
constructor create(aparent:tprocinfo);override;
|
|
destructor destroy;override;
|
|
procedure generate_code;
|
|
procedure resetprocdef;
|
|
procedure add_to_symtablestack;
|
|
procedure remove_from_symtablestack;
|
|
procedure parse_body;
|
|
end;
|
|
|
|
|
|
procedure printnode_reset;
|
|
|
|
{ reads the declaration blocks }
|
|
procedure read_declarations(islibrary : boolean);
|
|
|
|
{ reads declarations in the interface part of a unit }
|
|
procedure read_interface_declarations;
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
{ common }
|
|
cutils,
|
|
{ global }
|
|
globtype,globals,tokens,verbose,comphook,
|
|
systems,
|
|
{ aasm }
|
|
cpubase,cpuinfo,aasmbase,aasmtai,
|
|
{ symtable }
|
|
symconst,symbase,symsym,symtype,symtable,defutil,
|
|
paramgr,
|
|
ppu,fmodule,
|
|
{ pass 1 }
|
|
nutils,nbas,nld,ncal,ncon,nflw,nadd,ncnv,nmem,
|
|
pass_1,
|
|
{$ifdef state_tracking}
|
|
nstate,
|
|
{$endif state_tracking}
|
|
{ pass 2 }
|
|
{$ifndef NOPASS2}
|
|
pass_2,
|
|
{$endif}
|
|
{ parser }
|
|
scanner,
|
|
pbase,pstatmnt,pdecl,pdecsub,pexports,
|
|
{ codegen }
|
|
tgobj,rgobj,
|
|
ncgutil
|
|
{$ifndef NOOPT}
|
|
{$ifdef i386}
|
|
,aopt386
|
|
{$else i386}
|
|
,aoptcpu
|
|
{$endif i386}
|
|
{$endif}
|
|
;
|
|
|
|
{****************************************************************************
|
|
PROCEDURE/FUNCTION BODY PARSING
|
|
****************************************************************************}
|
|
|
|
procedure initializevars(p:tnamedindexitem;arg:pointer);
|
|
var
|
|
b : tblocknode;
|
|
begin
|
|
if tsym(p).typ<>varsym then
|
|
exit;
|
|
with tvarsym(p) do
|
|
begin
|
|
if assigned(defaultconstsym) then
|
|
begin
|
|
b:=tblocknode(arg);
|
|
b.left:=cstatementnode.create(
|
|
cassignmentnode.create(
|
|
cloadnode.create(tsym(p),tsym(p).owner),
|
|
cloadnode.create(defaultconstsym,defaultconstsym.owner)),
|
|
b.left);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
function block(islibrary : boolean) : tnode;
|
|
begin
|
|
{ parse const,types and vars }
|
|
read_declarations(islibrary);
|
|
|
|
current_procinfo.handle_body_start;
|
|
|
|
{ do we have an assembler block without the po_assembler?
|
|
we should allow this for Delphi compatibility (PFV) }
|
|
if (token=_ASM) and (m_delphi in aktmodeswitches) then
|
|
include(current_procdef.procoptions,po_assembler);
|
|
|
|
{ Handle assembler block different }
|
|
if (po_assembler in current_procdef.procoptions) then
|
|
begin
|
|
block:=assembler_block;
|
|
exit;
|
|
end;
|
|
|
|
{Unit initialization?.}
|
|
if (
|
|
assigned(current_procdef.localst) and
|
|
(current_procdef.localst.symtablelevel=main_program_level) and
|
|
(current_module.is_unit)
|
|
) or
|
|
islibrary then
|
|
begin
|
|
if (token=_END) then
|
|
begin
|
|
consume(_END);
|
|
{ We need at least a node, else the entry/exit code is not
|
|
generated and thus no PASCALMAIN symbol which we need (PFV) }
|
|
if islibrary then
|
|
block:=cnothingnode.create
|
|
else
|
|
block:=nil;
|
|
end
|
|
else
|
|
begin
|
|
if token=_INITIALIZATION then
|
|
begin
|
|
{ The library init code is already called and does not
|
|
need to be in the initfinal table (PFV) }
|
|
if not islibrary then
|
|
current_module.flags:=current_module.flags or uf_init;
|
|
block:=statement_block(_INITIALIZATION);
|
|
end
|
|
else if (token=_FINALIZATION) then
|
|
begin
|
|
if (current_module.flags and uf_finalize)<>0 then
|
|
block:=statement_block(_FINALIZATION)
|
|
else
|
|
begin
|
|
{ can we allow no INITIALIZATION for DLL ??
|
|
I think it should work PM }
|
|
block:=nil;
|
|
exit;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
{ The library init code is already called and does not
|
|
need to be in the initfinal table (PFV) }
|
|
if not islibrary then
|
|
current_module.flags:=current_module.flags or uf_init;
|
|
block:=statement_block(_BEGIN);
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
block:=statement_block(_BEGIN);
|
|
if symtablestack.symtabletype=localsymtable then
|
|
symtablestack.foreach_static({$ifdef FPCPROCVAR}@{$endif}initializevars,block);
|
|
end;
|
|
if (current_procdef.localst.symtablelevel=main_program_level) and
|
|
(not current_module.is_unit) then
|
|
begin
|
|
{ there's always a call to FPC_DO_EXIT in the main program }
|
|
include(current_procinfo.flags,pi_do_call);
|
|
end;
|
|
end;
|
|
|
|
|
|
{****************************************************************************
|
|
PROCEDURE/FUNCTION COMPILING
|
|
****************************************************************************}
|
|
|
|
procedure printnode_reset;
|
|
begin
|
|
assign(printnodefile,treelogfilename);
|
|
{$I-}
|
|
rewrite(printnodefile);
|
|
{$I+}
|
|
if ioresult<>0 then
|
|
begin
|
|
Comment(V_Error,'Error creating '+treelogfilename);
|
|
exit;
|
|
end;
|
|
close(printnodefile);
|
|
end;
|
|
|
|
|
|
procedure printnode_procdef(pd:tprocdef);
|
|
begin
|
|
assign(printnodefile,treelogfilename);
|
|
{$I-}
|
|
append(printnodefile);
|
|
if ioresult<>0 then
|
|
rewrite(printnodefile);
|
|
{$I+}
|
|
if ioresult<>0 then
|
|
begin
|
|
Comment(V_Error,'Error creating '+treelogfilename);
|
|
exit;
|
|
end;
|
|
writeln(printnodefile);
|
|
writeln(printnodefile,'*******************************************************************************');
|
|
writeln(printnodefile,current_procdef.fullprocname(false));
|
|
writeln(printnodefile,'*******************************************************************************');
|
|
printnode(printnodefile,pd.code);
|
|
close(printnodefile);
|
|
end;
|
|
|
|
|
|
function generate_initialize_block:tnode;
|
|
var
|
|
srsym : tsym;
|
|
para : tcallparanode;
|
|
newstatement : tstatementnode;
|
|
htype : ttype;
|
|
begin
|
|
result:=internalstatements(newstatement,true);
|
|
|
|
if assigned(current_procdef._class) then
|
|
begin
|
|
{ a constructor needs a help procedure }
|
|
if (current_procdef.proctypeoption=potype_constructor) then
|
|
begin
|
|
if is_class(current_procdef._class) then
|
|
begin
|
|
if (cs_implicit_exceptions in aktmoduleswitches) then
|
|
include(current_procinfo.flags,pi_needs_implicit_finally);
|
|
srsym:=search_class_member(current_procdef._class,'NEWINSTANCE');
|
|
if assigned(srsym) and
|
|
(srsym.typ=procsym) then
|
|
begin
|
|
{ if vmt<>0 then newinstance }
|
|
addstatement(newstatement,cifnode.create(
|
|
caddnode.create(unequaln,
|
|
load_vmt_pointer_node,
|
|
cnilnode.create),
|
|
cassignmentnode.create(
|
|
ctypeconvnode.create_explicit(
|
|
load_self_pointer_node,
|
|
voidpointertype),
|
|
ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_vmt_pointer_node)),
|
|
nil));
|
|
end
|
|
else
|
|
internalerror(200305108);
|
|
end
|
|
else
|
|
if is_object(current_procdef._class) then
|
|
begin
|
|
htype.setdef(current_procdef._class);
|
|
htype.setdef(tpointerdef.create(htype));
|
|
{ parameter 3 : vmt_offset }
|
|
{ parameter 2 : address of pointer to vmt,
|
|
this is required to allow setting the vmt to -1 to indicate
|
|
that memory was allocated }
|
|
{ parameter 1 : self pointer }
|
|
para:=ccallparanode.create(
|
|
cordconstnode.create(current_procdef._class.vmt_offset,s32bittype,false),
|
|
ccallparanode.create(
|
|
ctypeconvnode.create_explicit(
|
|
load_vmt_pointer_node,
|
|
voidpointertype),
|
|
ccallparanode.create(
|
|
ctypeconvnode.create_explicit(
|
|
load_self_pointer_node,
|
|
voidpointertype),
|
|
nil)));
|
|
addstatement(newstatement,cassignmentnode.create(
|
|
ctypeconvnode.create_explicit(
|
|
load_self_pointer_node,
|
|
voidpointertype),
|
|
ccallnode.createintern('fpc_help_constructor',para)));
|
|
end
|
|
else
|
|
internalerror(200305103);
|
|
{ if self=nil then exit
|
|
calling fail instead of exit is useless because
|
|
there is nothing to dispose (PFV) }
|
|
addstatement(newstatement,cifnode.create(
|
|
caddnode.create(equaln,
|
|
load_self_pointer_node,
|
|
cnilnode.create),
|
|
cexitnode.create(nil),
|
|
nil));
|
|
end;
|
|
|
|
{ maybe call BeforeDestruction for classes }
|
|
if (current_procdef.proctypeoption=potype_destructor) and
|
|
is_class(current_procdef._class) then
|
|
begin
|
|
srsym:=search_class_member(current_procdef._class,'BEFOREDESTRUCTION');
|
|
if assigned(srsym) and
|
|
(srsym.typ=procsym) then
|
|
begin
|
|
{ if vmt<>0 then beforedestruction }
|
|
addstatement(newstatement,cifnode.create(
|
|
caddnode.create(unequaln,
|
|
load_vmt_pointer_node,
|
|
cnilnode.create),
|
|
ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node),
|
|
nil));
|
|
end
|
|
else
|
|
internalerror(200305104);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
function generate_finalize_block:tnode;
|
|
begin
|
|
result:=cnothingnode.create;
|
|
end;
|
|
|
|
|
|
function generate_entry_block:tnode;
|
|
begin
|
|
result:=cnothingnode.create;
|
|
end;
|
|
|
|
|
|
function generate_exit_block:tnode;
|
|
var
|
|
srsym : tsym;
|
|
para : tcallparanode;
|
|
newstatement : tstatementnode;
|
|
begin
|
|
generate_exit_block:=internalstatements(newstatement,true);
|
|
|
|
if assigned(current_procdef._class) then
|
|
begin
|
|
{ maybe call AfterConstruction for classes }
|
|
if (current_procdef.proctypeoption=potype_constructor) and
|
|
is_class(current_procdef._class) then
|
|
begin
|
|
srsym:=search_class_member(current_procdef._class,'AFTERCONSTRUCTION');
|
|
if assigned(srsym) and
|
|
(srsym.typ=procsym) then
|
|
begin
|
|
{ if vmt<>0 then afterconstruction }
|
|
addstatement(newstatement,cifnode.create(
|
|
caddnode.create(unequaln,
|
|
load_vmt_pointer_node,
|
|
cnilnode.create),
|
|
ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node),
|
|
nil));
|
|
end
|
|
else
|
|
internalerror(200305106);
|
|
end;
|
|
|
|
{ a destructor needs a help procedure }
|
|
if (current_procdef.proctypeoption=potype_destructor) then
|
|
begin
|
|
if is_class(current_procdef._class) then
|
|
begin
|
|
srsym:=search_class_member(current_procdef._class,'FREEINSTANCE');
|
|
if assigned(srsym) and
|
|
(srsym.typ=procsym) then
|
|
begin
|
|
{ if self<>0 and vmt=1 then freeinstance }
|
|
addstatement(newstatement,cifnode.create(
|
|
caddnode.create(andn,
|
|
caddnode.create(unequaln,
|
|
load_self_pointer_node,
|
|
cnilnode.create),
|
|
caddnode.create(equaln,
|
|
ctypeconvnode.create(
|
|
load_vmt_pointer_node,
|
|
voidpointertype),
|
|
cpointerconstnode.create(1,voidpointertype))),
|
|
ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node),
|
|
nil));
|
|
end
|
|
else
|
|
internalerror(200305108);
|
|
end
|
|
else
|
|
if is_object(current_procdef._class) then
|
|
begin
|
|
{ finalize object data }
|
|
if current_procdef._class.needs_inittable then
|
|
addstatement(newstatement,finalize_data_node(load_self_node));
|
|
{ parameter 3 : vmt_offset }
|
|
{ parameter 2 : pointer to vmt }
|
|
{ parameter 1 : self pointer }
|
|
para:=ccallparanode.create(
|
|
cordconstnode.create(current_procdef._class.vmt_offset,s32bittype,false),
|
|
ccallparanode.create(
|
|
ctypeconvnode.create_explicit(
|
|
load_vmt_pointer_node,
|
|
voidpointertype),
|
|
ccallparanode.create(
|
|
ctypeconvnode.create_explicit(
|
|
load_self_pointer_node,
|
|
voidpointertype),
|
|
nil)));
|
|
addstatement(newstatement,
|
|
ccallnode.createintern('fpc_help_destructor',para));
|
|
end
|
|
else
|
|
internalerror(200305105);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
function generate_except_block:tnode;
|
|
var
|
|
pd : tprocdef;
|
|
newstatement : tstatementnode;
|
|
begin
|
|
generate_except_block:=internalstatements(newstatement,true);
|
|
|
|
{ a constructor needs call destructor (if available) when it
|
|
is not inherited }
|
|
if assigned(current_procdef._class) and
|
|
(current_procdef.proctypeoption=potype_constructor) then
|
|
begin
|
|
pd:=current_procdef._class.searchdestructor;
|
|
if assigned(pd) then
|
|
begin
|
|
{ if vmt<>0 then call destructor }
|
|
addstatement(newstatement,cifnode.create(
|
|
caddnode.create(unequaln,
|
|
load_vmt_pointer_node,
|
|
cnilnode.create),
|
|
ccallnode.create(nil,tprocsym(pd.procsym),pd.procsym.owner,load_self_node),
|
|
nil));
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
{ no constructor }
|
|
{ must be the return value finalized before reraising the exception? }
|
|
if (not is_void(current_procdef.rettype.def)) and
|
|
(current_procdef.rettype.def.needs_inittable) and
|
|
(not is_class(current_procdef.rettype.def)) then
|
|
finalize_data_node(load_result_node);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure add_entry_exit_code(var code:tnode;const entrypos,exitpos:tfileposinfo);
|
|
var
|
|
initializecode,
|
|
finalizecode,
|
|
entrycode,
|
|
exitcode,
|
|
exceptcode : tnode;
|
|
codeblock,
|
|
newblock : tblocknode;
|
|
codestatement,
|
|
newstatement : tstatementnode;
|
|
oldfilepos : tfileposinfo;
|
|
begin
|
|
oldfilepos:=aktfilepos;
|
|
{ Generate entry,exit and init,final blocks }
|
|
aktfilepos:=entrypos;
|
|
initializecode:=generate_initialize_block;
|
|
entrycode:=generate_entry_block;
|
|
aktfilepos:=exitpos;
|
|
exitcode:=generate_exit_block;
|
|
finalizecode:=generate_finalize_block;
|
|
exceptcode:=generate_except_block;
|
|
|
|
{ Generate body of the procedure by combining entry+body+exit }
|
|
codeblock:=internalstatements(codestatement,true);
|
|
addstatement(codestatement,entrycode);
|
|
addstatement(codestatement,code);
|
|
addstatement(codestatement,exitcode);
|
|
|
|
{ Generate procedure by combining init+body+final,
|
|
depending on the implicit finally we need to add
|
|
an try...finally...end wrapper }
|
|
newblock:=internalstatements(newstatement,true);
|
|
if (pi_needs_implicit_finally in current_procinfo.flags) and
|
|
{ but it's useless in init/final code of units }
|
|
not(current_procdef.proctypeoption in [potype_unitfinalize,potype_unitinit]) then
|
|
begin
|
|
addstatement(newstatement,initializecode);
|
|
aktfilepos:=entrypos;
|
|
addstatement(newstatement,ctryfinallynode.create_implicit(
|
|
codeblock,
|
|
finalizecode,
|
|
exceptcode));
|
|
end
|
|
else
|
|
begin
|
|
addstatement(newstatement,initializecode);
|
|
addstatement(newstatement,codeblock);
|
|
addstatement(newstatement,finalizecode);
|
|
end;
|
|
resulttypepass(newblock);
|
|
code:=newblock;
|
|
aktfilepos:=oldfilepos;
|
|
end;
|
|
|
|
|
|
{****************************************************************************
|
|
TCGProcInfo
|
|
****************************************************************************}
|
|
|
|
constructor tcgprocinfo.create(aparent:tprocinfo);
|
|
begin
|
|
inherited Create(aparent);
|
|
nestedprocs:=tlinkedlist.create;
|
|
end;
|
|
|
|
|
|
destructor tcgprocinfo.destroy;
|
|
begin
|
|
nestedprocs.free;
|
|
inherited destroy;
|
|
end;
|
|
|
|
|
|
procedure tcgprocinfo.generate_code;
|
|
var
|
|
oldprocdef : tprocdef;
|
|
oldprocinfo : tprocinfo;
|
|
oldexitlabel : tasmlabel;
|
|
oldaktmaxfpuregisters : longint;
|
|
oldfilepos : tfileposinfo;
|
|
stackalloccode : Taasmoutput;
|
|
|
|
begin
|
|
{ the initialization procedure can be empty, then we
|
|
don't need to generate anything. When it was an empty
|
|
procedure there would be at least a blocknode }
|
|
if not assigned(code) then
|
|
exit;
|
|
|
|
oldprocinfo:=current_procinfo;
|
|
oldprocdef:=current_procdef;
|
|
oldfilepos:=aktfilepos;
|
|
oldaktmaxfpuregisters:=aktmaxfpuregisters;
|
|
|
|
current_procinfo:=self;
|
|
current_procdef:=procdef;
|
|
|
|
{ save old labels }
|
|
oldexitlabel:=aktexitlabel;
|
|
{ get new labels }
|
|
objectlibrary.getlabel(aktexitlabel);
|
|
aktbreaklabel:=nil;
|
|
aktcontinuelabel:=nil;
|
|
|
|
{ add parast/localst to symtablestack }
|
|
add_to_symtablestack;
|
|
|
|
{ reset the temporary memory }
|
|
rg.cleartempgen;
|
|
rg.usedinproc:=[];
|
|
rg.usedintinproc:=[];
|
|
rg.usedbyproc:=[];
|
|
{$ifndef newra}
|
|
rg.usedintbyproc:=[];
|
|
{$endif}
|
|
|
|
{ set the start offset to the start of the temp area in the stack }
|
|
tg.setfirsttemp(current_procinfo.firsttemp_offset);
|
|
|
|
generatecode(code);
|
|
|
|
{ first generate entry code with the correct position and switches }
|
|
aktfilepos:=current_procinfo.entrypos;
|
|
aktlocalswitches:=current_procinfo.entryswitches;
|
|
genentrycode(current_procinfo.aktentrycode,false);
|
|
|
|
{ now generate exit code with the correct position and switches }
|
|
aktfilepos:=current_procinfo.exitpos;
|
|
aktlocalswitches:=current_procinfo.exitswitches;
|
|
genexitcode(current_procinfo.aktexitcode,false);
|
|
|
|
{ now all the registers used are known }
|
|
{ current_procdef.usedintregisters:=rg.usedintinproc;
|
|
current_procdef.usedotherregisters:=rg.usedinproc;}
|
|
current_procinfo.aktproccode.insertlist(current_procinfo.aktentrycode);
|
|
current_procinfo.aktproccode.concatlist(current_procinfo.aktexitcode);
|
|
{$ifdef newra}
|
|
{ rg.writegraph;}
|
|
{$endif}
|
|
if not(cs_no_regalloc in aktglobalswitches) then
|
|
begin
|
|
{$ifdef newra}
|
|
{Do register allocation.}
|
|
repeat
|
|
rg.prepare_colouring;
|
|
rg.colour_registers;
|
|
rg.epilogue_colouring;
|
|
until (rg.spillednodes='') or not rg.spill_registers(current_procinfo.aktproccode,rg.spillednodes);
|
|
current_procinfo.aktproccode.translate_registers(rg.colour);
|
|
current_procinfo.aktproccode.convert_registers;
|
|
{$else newra}
|
|
current_procinfo.aktproccode.convert_registers;
|
|
{$ifndef NoOpt}
|
|
if (cs_optimize in aktglobalswitches) and
|
|
{ do not optimize pure assembler procedures }
|
|
not(pi_is_assembler in current_procinfo.flags) then
|
|
optimize(current_procinfo.aktproccode);
|
|
{$endif NoOpt}
|
|
{$endif newra}
|
|
end;
|
|
|
|
stackalloccode:=Taasmoutput.create;
|
|
gen_stackalloc_code(stackalloccode,0);
|
|
stackalloccode.convert_registers;
|
|
current_procinfo.aktproccode.insertlist(stackalloccode);
|
|
stackalloccode.destroy;
|
|
|
|
{ now all the registers used are known }
|
|
{ Remove all imaginary registers from the used list.}
|
|
{$ifdef newra}
|
|
current_procdef.usedintregisters:=rg.usedintinproc*ALL_INTREGISTERS-rg.savedbyproc;
|
|
{$else}
|
|
current_procdef.usedintregisters:=rg.usedintinproc;
|
|
{$endif}
|
|
current_procdef.usedotherregisters:=rg.usedinproc;
|
|
|
|
{ save local data (casetable) also in the same file }
|
|
if assigned(current_procinfo.aktlocaldata) and
|
|
(not current_procinfo.aktlocaldata.empty) then
|
|
begin
|
|
current_procinfo.aktproccode.concat(Tai_section.Create(sec_data));
|
|
current_procinfo.aktproccode.concatlist(current_procinfo.aktlocaldata);
|
|
current_procinfo.aktproccode.concat(Tai_section.Create(sec_code));
|
|
end;
|
|
|
|
{ add the procedure to the codesegment }
|
|
if (cs_create_smart in aktmoduleswitches) then
|
|
codesegment.concat(Tai_cut.Create);
|
|
codesegment.concatlist(current_procinfo.aktproccode);
|
|
|
|
{ all registers can be used again }
|
|
rg.resetusableregisters;
|
|
{ only now we can remove the temps }
|
|
tg.resettempgen;
|
|
|
|
{ restore symtablestack }
|
|
remove_from_symtablestack;
|
|
|
|
{ restore labels }
|
|
aktexitlabel:=oldexitlabel;
|
|
|
|
{ restore }
|
|
aktmaxfpuregisters:=oldaktmaxfpuregisters;
|
|
aktfilepos:=oldfilepos;
|
|
current_procdef:=oldprocdef;
|
|
current_procinfo:=oldprocinfo;
|
|
end;
|
|
|
|
|
|
procedure tcgprocinfo.add_to_symtablestack;
|
|
var
|
|
_class,hp : tobjectdef;
|
|
begin
|
|
{ insert symtables for the class, but only if it is no nested function }
|
|
if assigned(procdef._class) and
|
|
not(assigned(parent) and
|
|
assigned(parent.procdef) and
|
|
assigned(parent.procdef._class)) then
|
|
begin
|
|
{ insert them in the reverse order }
|
|
hp:=nil;
|
|
repeat
|
|
_class:=procdef._class;
|
|
while _class.childof<>hp do
|
|
_class:=_class.childof;
|
|
hp:=_class;
|
|
_class.symtable.next:=symtablestack;
|
|
symtablestack:=_class.symtable;
|
|
until hp=procdef._class;
|
|
end;
|
|
|
|
{ insert parasymtable in symtablestack when parsing
|
|
a function }
|
|
if procdef.parast.symtablelevel>=normal_function_level then
|
|
begin
|
|
procdef.parast.next:=symtablestack;
|
|
symtablestack:=procdef.parast;
|
|
end;
|
|
|
|
procdef.localst.next:=symtablestack;
|
|
symtablestack:=procdef.localst;
|
|
end;
|
|
|
|
|
|
procedure tcgprocinfo.remove_from_symtablestack;
|
|
begin
|
|
{ remove localst/parast }
|
|
if procdef.parast.symtablelevel>=normal_function_level then
|
|
symtablestack:=symtablestack.next.next
|
|
else
|
|
symtablestack:=symtablestack.next;
|
|
|
|
{ remove class member symbol tables }
|
|
while symtablestack.symtabletype=objectsymtable do
|
|
symtablestack:=symtablestack.next;
|
|
end;
|
|
|
|
|
|
procedure tcgprocinfo.resetprocdef;
|
|
begin
|
|
{ the local symtables can be deleted, but the parast }
|
|
{ doesn't, (checking definitons when calling a }
|
|
{ function }
|
|
{ not for a inline procedure !! (PM) }
|
|
{ at lexlevel = 1 localst is the staticsymtable itself }
|
|
{ so no dispose here !! }
|
|
if assigned(code) and
|
|
not(cs_browser in aktmoduleswitches) and
|
|
(procdef.proccalloption<>pocall_inline) then
|
|
begin
|
|
if procdef.parast.symtablelevel>=normal_function_level then
|
|
procdef.localst.free;
|
|
procdef.localst:=nil;
|
|
end;
|
|
|
|
{ remove code tree, if not inline procedure }
|
|
if assigned(code) then
|
|
begin
|
|
{ the inline procedure has already got a copy of the tree
|
|
stored in current_procdef.code }
|
|
code.free;
|
|
if (procdef.proccalloption<>pocall_inline) then
|
|
procdef.code:=nil;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure tcgprocinfo.parse_body;
|
|
var
|
|
oldprocdef : tprocdef;
|
|
stackalloccode : Taasmoutput;
|
|
oldprocinfo : tprocinfo;
|
|
begin
|
|
oldprocdef:=current_procdef;
|
|
oldprocinfo:=current_procinfo;
|
|
|
|
current_procinfo:=self;
|
|
current_procdef:=procdef;
|
|
|
|
{ calculate the lexical level }
|
|
if procdef.parast.symtablelevel>maxnesting then
|
|
Message(parser_e_too_much_lexlevel);
|
|
|
|
{ static is also important for local procedures !! }
|
|
if (po_staticmethod in procdef.procoptions) then
|
|
allow_only_static:=true
|
|
else if (procdef.parast.symtablelevel=normal_function_level) then
|
|
allow_only_static:=false;
|
|
|
|
{ reset break and continue labels }
|
|
block_type:=bt_general;
|
|
{$ifdef state_tracking}
|
|
{ aktstate:=Tstate_storage.create;}
|
|
{$endif state_tracking}
|
|
|
|
{ create a local symbol table for this routine }
|
|
if not assigned(procdef.localst) then
|
|
procdef.insert_localst;
|
|
|
|
{ add parast/localst to symtablestack }
|
|
add_to_symtablestack;
|
|
|
|
{ constant symbols are inserted in this symboltable }
|
|
constsymtable:=symtablestack;
|
|
|
|
{ reset the temporary memory }
|
|
rg.cleartempgen;
|
|
rg.usedintinproc:=[];
|
|
rg.usedinproc:=[];
|
|
rg.usedbyproc:=[];
|
|
|
|
{ save entry info }
|
|
entrypos:=aktfilepos;
|
|
entryswitches:=aktlocalswitches;
|
|
|
|
{ parse the code ... }
|
|
code:=block(current_module.islibrary);
|
|
|
|
{ save exit info }
|
|
exitswitches:=aktlocalswitches;
|
|
exitpos:=last_endtoken_filepos;
|
|
|
|
if assigned(code) then
|
|
begin
|
|
{ get a better entry point }
|
|
entrypos:=code.fileinfo;
|
|
|
|
{ the procedure is now defined }
|
|
procdef.forwarddef:=false;
|
|
|
|
{ add implicit entry and exit code }
|
|
add_entry_exit_code(code,entrypos,exitpos);
|
|
|
|
if (Errorcount=0) then
|
|
begin
|
|
{ check if forwards are resolved }
|
|
tstoredsymtable(procdef.localst).check_forwards;
|
|
{ check if all labels are used }
|
|
tstoredsymtable(procdef.localst).checklabels;
|
|
{ remove cross unit overloads }
|
|
tstoredsymtable(procdef.localst).unchain_overloaded;
|
|
end;
|
|
|
|
{ check for unused symbols, but only if there is no asm block }
|
|
if not(pi_uses_asm in flags) then
|
|
begin
|
|
{ not for unit init, becuase the var can be used in finalize,
|
|
it will be done in proc_unit }
|
|
if not(procdef.proctypeoption in [potype_proginit,potype_unitinit,potype_unitfinalize]) then
|
|
tstoredsymtable(procdef.localst).allsymbolsused;
|
|
tstoredsymtable(procdef.parast).allsymbolsused;
|
|
end;
|
|
|
|
{ Finish type checking pass }
|
|
do_resulttypepass(code);
|
|
|
|
{ Print the node to tree.log }
|
|
if paraprintnodetree=1 then
|
|
printnode_procdef(procdef);
|
|
end;
|
|
|
|
{ store a copy of the original tree for inline, for
|
|
normal procedures only store a reference to the
|
|
current tree }
|
|
if (procdef.proccalloption=pocall_inline) then
|
|
procdef.code:=code.getcopy
|
|
else
|
|
procdef.code:=code;
|
|
|
|
{ ... remove symbol tables }
|
|
remove_from_symtablestack;
|
|
|
|
{$ifdef state_tracking}
|
|
{ aktstate.destroy;}
|
|
{$endif state_tracking}
|
|
|
|
{ reset to normal non static function }
|
|
if (current_procdef.parast.symtablelevel=normal_function_level) then
|
|
allow_only_static:=false;
|
|
|
|
current_procdef:=oldprocdef;
|
|
current_procinfo:=oldprocinfo;
|
|
end;
|
|
|
|
|
|
{****************************************************************************
|
|
PROCEDURE/FUNCTION PARSING
|
|
****************************************************************************}
|
|
|
|
procedure insert_local_value_para(p:tnamedindexitem;arg:pointer);
|
|
var
|
|
vs : tvarsym;
|
|
pd : tprocdef;
|
|
begin
|
|
if tsym(p).typ<>varsym then
|
|
exit;
|
|
with tvarsym(p) do
|
|
begin
|
|
if copy(name,1,3)='val' then
|
|
begin
|
|
pd:=tprocdef(owner.defowner);
|
|
vs:=tvarsym.create(Copy(name,4,255),varspez,vartype);
|
|
vs.fileinfo:=fileinfo;
|
|
if not assigned(pd.localst) then
|
|
pd.insert_localst;
|
|
pd.localst.insert(vs);
|
|
pd.localst.insertvardata(vs);
|
|
include(vs.varoptions,vo_is_local_copy);
|
|
vs.varstate:=vs_assigned;
|
|
localvarsym:=vs;
|
|
inc(refs); { the para was used to set the local copy ! }
|
|
{ warnings only on local copy ! }
|
|
varstate:=vs_used;
|
|
end;
|
|
if is_shortstring(vartype.def) and
|
|
(varspez = vs_value) then
|
|
include(current_procinfo.flags,pi_do_call);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure check_init_paras(p:tnamedindexitem;arg:pointer);
|
|
var
|
|
vs : tvarsym;
|
|
pd : tprocdef;
|
|
begin
|
|
if tsym(p).typ<>varsym then
|
|
exit;
|
|
with tvarsym(p) do
|
|
if (not is_class(vartype.def) and
|
|
vartype.def.needs_inittable and
|
|
(varspez in [vs_value,vs_out])) then
|
|
include(current_procinfo.flags,pi_do_call);
|
|
end;
|
|
|
|
|
|
procedure read_proc;
|
|
{
|
|
Parses the procedure directives, then parses the procedure body, then
|
|
generates the code for it
|
|
}
|
|
|
|
procedure do_generate_code(pi:tcgprocinfo);
|
|
var
|
|
hpi : tcgprocinfo;
|
|
begin
|
|
{ generate code for this procedure }
|
|
pi.generate_code;
|
|
{ process nested procs }
|
|
hpi:=tcgprocinfo(pi.nestedprocs.first);
|
|
while assigned(hpi) do
|
|
begin
|
|
do_generate_code(hpi);
|
|
hpi:=tcgprocinfo(hpi.next);
|
|
end;
|
|
pi.resetprocdef;
|
|
end;
|
|
|
|
var
|
|
oldprocdef : tprocdef;
|
|
old_current_procinfo : tprocinfo;
|
|
oldconstsymtable : tsymtable;
|
|
oldselftokenmode,
|
|
oldfailtokenmode : tmodeswitch;
|
|
pdflags : tpdflags;
|
|
pd : tprocdef;
|
|
isnestedproc : boolean;
|
|
begin
|
|
{ save old state }
|
|
oldprocdef:=current_procdef;
|
|
oldconstsymtable:=constsymtable;
|
|
old_current_procinfo:=current_procinfo;
|
|
|
|
{ reset current_procdef to nil to be sure that nothing is writing
|
|
to an other procdef }
|
|
current_procdef:=nil;
|
|
current_procinfo:=nil;
|
|
|
|
{ parse procedure declaration }
|
|
if assigned(old_current_procinfo) and
|
|
assigned(old_current_procinfo.procdef) then
|
|
pd:=parse_proc_dec(old_current_procinfo.procdef._class)
|
|
else
|
|
pd:=parse_proc_dec(nil);
|
|
|
|
{ set the default function options }
|
|
if parse_only then
|
|
begin
|
|
pd.forwarddef:=true;
|
|
{ set also the interface flag, for better error message when the
|
|
implementation doesn't much this header }
|
|
pd.interfacedef:=true;
|
|
include(pd.procoptions,po_public);
|
|
pdflags:=[pd_interface];
|
|
end
|
|
else
|
|
begin
|
|
pdflags:=[pd_body];
|
|
if (not current_module.in_interface) then
|
|
include(pdflags,pd_implemen);
|
|
if (not current_module.is_unit) or
|
|
(cs_create_smart in aktmoduleswitches) then
|
|
include(pd.procoptions,po_public);
|
|
pd.forwarddef:=false;
|
|
end;
|
|
|
|
{ parse the directives that may follow }
|
|
parse_proc_directives(pd,pdflags);
|
|
|
|
{ hint directives, these can be separated by semicolons here,
|
|
that needs to be handled here with a loop (PFV) }
|
|
while try_consume_hintdirective(pd.symoptions) do
|
|
Consume(_SEMICOLON);
|
|
|
|
{ everything of the proc definition is known, we can now
|
|
calculate the parameters }
|
|
calc_parast(pd);
|
|
|
|
{ search for forward declarations }
|
|
if not proc_add_definition(pd) then
|
|
begin
|
|
{ A method must be forward defined (in the object declaration) }
|
|
if assigned(pd._class) and
|
|
(not assigned(old_current_procinfo.procdef._class)) then
|
|
begin
|
|
Message1(parser_e_header_dont_match_any_member,pd.fullprocname(false));
|
|
tprocsym(pd.procsym).write_parameter_lists(pd);
|
|
end
|
|
else
|
|
begin
|
|
{ Give a better error if there is a forward def in the interface and only
|
|
a single implementation }
|
|
if (not pd.forwarddef) and
|
|
(not pd.interfacedef) and
|
|
(tprocsym(pd.procsym).procdef_count>1) and
|
|
tprocsym(pd.procsym).first_procdef.forwarddef and
|
|
tprocsym(pd.procsym).first_procdef.interfacedef and
|
|
not(tprocsym(pd.procsym).procdef_count>2) then
|
|
begin
|
|
Message1(parser_e_header_dont_match_forward,pd.fullprocname(false));
|
|
tprocsym(pd.procsym).write_parameter_lists(pd);
|
|
end
|
|
else
|
|
begin
|
|
{ check the global flag, for delphi this is not
|
|
required }
|
|
{if not(m_delphi in aktmodeswitches) and
|
|
not(pd.procsym.owner.symtabletype=globalsymtable) then
|
|
Message(parser_e_overloaded_must_be_all_global);}
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ compile procedure when a body is needed }
|
|
if (pd_body in pdflags) then
|
|
begin
|
|
Message1(parser_d_procedure_start,pd.fullprocname(false));
|
|
|
|
{ create a new procedure }
|
|
current_procinfo:=cprocinfo.create(old_current_procinfo);
|
|
current_module.procinfo:=current_procinfo;
|
|
current_procinfo.procdef:=pd;
|
|
isnestedproc:=(current_procinfo.procdef.parast.symtablelevel>normal_function_level);
|
|
|
|
{ Insert mangledname }
|
|
pd.aliasnames.insert(pd.mangledname);
|
|
|
|
{ Insert result variables in the localst }
|
|
insert_funcret_local(pd);
|
|
|
|
{ Insert local copies for value para }
|
|
pd.parast.foreach_static({$ifdef FPCPROCVAR}@{$endif}insert_local_value_para,nil);
|
|
|
|
{ check if there are para's which require initing -> set }
|
|
{ pi_do_call (if not yet set) }
|
|
if not(pi_do_call in current_procinfo.flags) then
|
|
pd.parast.foreach_static({$ifdef FPCPROCVAR}@{$endif}check_init_paras,nil);
|
|
|
|
{ Update parameter information }
|
|
current_procinfo.allocate_implicit_parameter;
|
|
{$ifdef i386}
|
|
{ add implicit pushes for interrupt routines }
|
|
if (po_interrupt in pd.procoptions) then
|
|
current_procinfo.allocate_interrupt_stackframe;
|
|
{$endif i386}
|
|
|
|
{ Calculate offsets }
|
|
current_procinfo.after_header;
|
|
|
|
{ set _FAIL as keyword if constructor }
|
|
if (pd.proctypeoption=potype_constructor) then
|
|
begin
|
|
oldfailtokenmode:=tokeninfo^[_FAIL].keyword;
|
|
tokeninfo^[_FAIL].keyword:=m_all;
|
|
end;
|
|
{ set _SELF as keyword if methods }
|
|
if assigned(pd._class) then
|
|
begin
|
|
oldselftokenmode:=tokeninfo^[_SELF].keyword;
|
|
tokeninfo^[_SELF].keyword:=m_all;
|
|
end;
|
|
|
|
tcgprocinfo(current_procinfo).parse_body;
|
|
|
|
{ When it's a nested procedure then defer the code generation,
|
|
when back at normal function level then generate the code
|
|
for all defered nested procedures and the current procedure }
|
|
if isnestedproc then
|
|
tcgprocinfo(current_procinfo.parent).nestedprocs.insert(current_procinfo)
|
|
else
|
|
begin
|
|
if status.errorcount=0 then
|
|
do_generate_code(tcgprocinfo(current_procinfo));
|
|
end;
|
|
|
|
{ reset _FAIL as _SELF normal }
|
|
if (pd.proctypeoption=potype_constructor) then
|
|
tokeninfo^[_FAIL].keyword:=oldfailtokenmode;
|
|
if assigned(pd._class) then
|
|
tokeninfo^[_SELF].keyword:=oldselftokenmode;
|
|
consume(_SEMICOLON);
|
|
|
|
{ release procinfo }
|
|
if tprocinfo(current_module.procinfo)<>current_procinfo then
|
|
internalerror(200304274);
|
|
current_module.procinfo:=current_procinfo.parent;
|
|
if not isnestedproc then
|
|
current_procinfo.free;
|
|
end;
|
|
|
|
{ Restore old state }
|
|
constsymtable:=oldconstsymtable;
|
|
|
|
current_procdef:=oldprocdef;
|
|
current_procinfo:=old_current_procinfo;
|
|
end;
|
|
|
|
|
|
{****************************************************************************
|
|
DECLARATION PARSING
|
|
****************************************************************************}
|
|
|
|
{ search in symtablestack for not complete classes }
|
|
procedure check_forward_class(p : tnamedindexitem;arg:pointer);
|
|
begin
|
|
if (tsym(p).typ=typesym) and
|
|
(ttypesym(p).restype.def.deftype=objectdef) and
|
|
(oo_is_forward in tobjectdef(ttypesym(p).restype.def).objectoptions) then
|
|
MessagePos1(tsym(p).fileinfo,sym_e_forward_type_not_resolved,tsym(p).realname);
|
|
end;
|
|
|
|
|
|
procedure read_declarations(islibrary : boolean);
|
|
|
|
procedure Not_supported_for_inline(t : ttoken);
|
|
begin
|
|
if (current_procdef.proccalloption=pocall_inline) then
|
|
Begin
|
|
Message1(parser_w_not_supported_for_inline,tokenstring(t));
|
|
Message(parser_w_inlining_disabled);
|
|
current_procdef.proccalloption:=pocall_fpccall;
|
|
End;
|
|
end;
|
|
|
|
begin
|
|
repeat
|
|
if not assigned(current_procdef) then
|
|
internalerror(200304251);
|
|
case token of
|
|
_LABEL:
|
|
begin
|
|
Not_supported_for_inline(token);
|
|
label_dec;
|
|
end;
|
|
_CONST:
|
|
begin
|
|
Not_supported_for_inline(token);
|
|
const_dec;
|
|
end;
|
|
_TYPE:
|
|
begin
|
|
Not_supported_for_inline(token);
|
|
type_dec;
|
|
end;
|
|
_VAR:
|
|
var_dec;
|
|
_THREADVAR:
|
|
threadvar_dec;
|
|
_CONSTRUCTOR,_DESTRUCTOR,
|
|
_FUNCTION,_PROCEDURE,_OPERATOR,_CLASS:
|
|
begin
|
|
Not_supported_for_inline(token);
|
|
read_proc;
|
|
end;
|
|
_RESOURCESTRING:
|
|
resourcestring_dec;
|
|
_EXPORTS:
|
|
begin
|
|
Not_supported_for_inline(token);
|
|
if not(assigned(current_procdef.localst)) or
|
|
(current_procdef.localst.symtablelevel>main_program_level) or
|
|
(current_module.is_unit) then
|
|
begin
|
|
Message(parser_e_syntax_error);
|
|
consume_all_until(_SEMICOLON);
|
|
end
|
|
else if islibrary or
|
|
(target_info.system in [system_i386_WIN32,system_i386_wdosx,system_i386_Netware]) then
|
|
read_exports
|
|
else
|
|
begin
|
|
Message(parser_w_unsupported_feature);
|
|
consume(_BEGIN);
|
|
end;
|
|
end
|
|
else break;
|
|
end;
|
|
until false;
|
|
{ check for incomplete class definitions, this is only required
|
|
for fpc modes }
|
|
if (m_fpc in aktmodeswitches) then
|
|
symtablestack.foreach_static({$ifdef FPCPROCVAR}@{$endif}check_forward_class,nil);
|
|
end;
|
|
|
|
|
|
procedure read_interface_declarations;
|
|
begin
|
|
repeat
|
|
case token of
|
|
_CONST :
|
|
const_dec;
|
|
_TYPE :
|
|
type_dec;
|
|
_VAR :
|
|
var_dec;
|
|
_THREADVAR :
|
|
threadvar_dec;
|
|
_RESOURCESTRING:
|
|
resourcestring_dec;
|
|
_FUNCTION,
|
|
_PROCEDURE,
|
|
_OPERATOR :
|
|
read_proc;
|
|
else
|
|
break;
|
|
end;
|
|
until false;
|
|
{ check for incomplete class definitions, this is only required
|
|
for fpc modes }
|
|
if (m_fpc in aktmodeswitches) then
|
|
symtablestack.foreach_static({$ifdef FPCPROCVAR}@{$endif}check_forward_class,nil);
|
|
end;
|
|
|
|
|
|
begin
|
|
cprocinfo:=tcgprocinfo;
|
|
end.
|
|
{
|
|
$Log$
|
|
Revision 1.124 2003-06-07 19:37:43 jonas
|
|
* pi_do_call must always be set for the main program, since it always
|
|
ends with a call to FPC_DO_EXIT
|
|
|
|
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/03 13:01:59 daniel
|
|
* Register allocator finished
|
|
|
|
Revision 1.121 2003/05/31 20:23:39 jonas
|
|
* added pi_do_call if a procedure has a value shortstring parameter
|
|
(it's copied to the local stackframe with a helper)
|
|
|
|
Revision 1.120 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.119 2003/05/28 23:58:18 jonas
|
|
* added missing initialization of rg.usedintin,byproc
|
|
* ppc now also saves/restores used fpu registers
|
|
* ncgcal doesn't add used registers to usedby/inproc anymore, except for
|
|
i386
|
|
|
|
Revision 1.118 2003/05/26 21:17:18 peter
|
|
* procinlinenode removed
|
|
* aktexit2label removed, fast exit removed
|
|
+ tcallnode.inlined_pass_2 added
|
|
|
|
Revision 1.117 2003/05/25 08:59:47 peter
|
|
* do not generate code when there was an error
|
|
|
|
Revision 1.116 2003/05/23 18:49:55 jonas
|
|
* generate code for parent procedure before that of nested procedures as
|
|
well (I only need pass_1 to be done for the ppc, but pass_1 and pass_2
|
|
are grouped and it doesn't hurt that pass_2 is done as well)
|
|
|
|
Revision 1.115 2003/05/22 21:31:35 peter
|
|
* defer codegeneration for nested procedures
|
|
|
|
Revision 1.114 2003/05/16 20:00:39 jonas
|
|
* powerpc nested procedure fixes, should work completely now if all
|
|
local variables of the parent procedure are declared before the
|
|
nested procedures are declared
|
|
|
|
Revision 1.113 2003/05/16 14:33:31 peter
|
|
* regvar fixes
|
|
|
|
Revision 1.112 2003/05/13 21:26:38 peter
|
|
* only call destructor in except block when there is a destructor
|
|
available
|
|
|
|
Revision 1.111 2003/05/13 19:14:41 peter
|
|
* failn removed
|
|
* inherited result code check moven to pexpr
|
|
|
|
Revision 1.110 2003/05/13 15:18:49 peter
|
|
* fixed various crashes
|
|
|
|
Revision 1.109 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.108 2003/05/09 17:47:03 peter
|
|
* self moved to hidden parameter
|
|
* removed hdisposen,hnewn,selfn
|
|
|
|
Revision 1.107 2003/04/27 11:21:34 peter
|
|
* aktprocdef renamed to current_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.106 2003/04/27 07:29:50 peter
|
|
* current_procdef cleanup, current_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.105 2003/04/26 00:31:42 peter
|
|
* set return_offset moved to after_header
|
|
|
|
Revision 1.104 2003/04/25 20:59:34 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.103 2003/04/24 13:03:01 florian
|
|
* comp is now written with its bit pattern to the ppu instead as an extended
|
|
|
|
Revision 1.102 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.101 2003/04/22 14:33:38 peter
|
|
* removed some notes/hints
|
|
|
|
Revision 1.100 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.99 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.98 2003/04/17 07:50:24 daniel
|
|
* Some work on interference graph construction
|
|
|
|
Revision 1.97 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.96 2003/04/05 21:09:31 jonas
|
|
* several ppc/generic result offset related fixes. The "normal" result
|
|
offset seems now to be calculated correctly and a lot of duplicate
|
|
calculations have been removed. Nested functions accessing the parent's
|
|
function result don't work at all though :(
|
|
|
|
Revision 1.95 2003/04/02 16:11:34 peter
|
|
* give error when exports is not supported
|
|
|
|
Revision 1.94 2003/03/12 22:43:38 jonas
|
|
* more powerpc and generic fixes related to the new register allocator
|
|
|
|
Revision 1.93 2003/03/08 08:59:07 daniel
|
|
+ $define newra will enable new register allocator
|
|
+ getregisterint will return imaginary registers with $newra
|
|
+ -sr switch added, will skip register allocation so you can see
|
|
the direct output of the code generator before register allocation
|
|
|
|
Revision 1.92 2003/02/19 22:00:14 daniel
|
|
* Code generator converted to new register notation
|
|
- Horribily outdated todo.txt removed
|
|
|
|
Revision 1.91 2003/01/09 21:52:37 peter
|
|
* merged some verbosity options.
|
|
* V_LineInfo is a verbosity flag to include line info
|
|
|
|
Revision 1.90 2003/01/09 20:40:59 daniel
|
|
* Converted some code in cgx86.pas to new register numbering
|
|
|
|
Revision 1.89 2003/01/09 15:49:56 daniel
|
|
* Added register conversion
|
|
|
|
Revision 1.88 2003/01/08 18:43:56 daniel
|
|
* Tregister changed into a record
|
|
|
|
Revision 1.87 2003/01/03 20:35:08 peter
|
|
* check also interfacedef when checking for matching forwarddef
|
|
|
|
Revision 1.86 2003/01/02 11:14:02 michael
|
|
+ Patch from peter to support initial values for local variables
|
|
|
|
Revision 1.85 2002/12/29 18:59:34 peter
|
|
* fixed parsing of declarations before asm statement
|
|
|
|
Revision 1.84 2002/12/29 18:25:18 peter
|
|
* parse declarations before check _ASM token
|
|
|
|
Revision 1.83 2002/12/29 14:57:50 peter
|
|
* unit loading changed to first register units and load them
|
|
afterwards. This is needed to support uses xxx in yyy correctly
|
|
* unit dependency check fixed
|
|
|
|
Revision 1.82 2002/12/25 01:26:56 peter
|
|
* duplicate procsym-unitsym fix
|
|
|
|
Revision 1.81 2002/12/15 13:37:15 peter
|
|
* don't include uf_init for library. The code is already called and
|
|
does not need to be in the initfinal table
|
|
|
|
Revision 1.80 2002/12/07 14:27:09 carl
|
|
* 3% memory optimization
|
|
* changed some types
|
|
+ added type checking with different size for call node and for
|
|
parameters
|
|
|
|
Revision 1.79 2002/11/25 18:43:32 carl
|
|
- removed the invalid if <> checking (Delphi is strange on this)
|
|
+ implemented abstract warning on instance creation of class with
|
|
abstract methods.
|
|
* some error message cleanups
|
|
|
|
Revision 1.78 2002/11/25 17:43:23 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.77 2002/11/23 22:50:06 carl
|
|
* some small speed optimizations
|
|
+ added several new warnings/hints
|
|
|
|
Revision 1.76 2002/11/18 17:31:58 peter
|
|
* pass proccalloption to ret_in_xxx and push_xxx functions
|
|
|
|
Revision 1.75 2002/11/17 16:31:57 carl
|
|
* memory optimization (3-4%) : cleanup of tai fields,
|
|
cleanup of tdef and tsym fields.
|
|
* make it work for m68k
|
|
|
|
Revision 1.74 2002/11/15 01:58:53 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.73 2002/11/09 15:32:30 carl
|
|
* noopt for non-i386 targets
|
|
|
|
Revision 1.72 2002/09/10 20:31:48 florian
|
|
* call to current_procinfo.after_header added
|
|
|
|
Revision 1.71 2002/09/07 15:25:07 peter
|
|
* old logs removed and tabs fixed
|
|
|
|
Revision 1.70 2002/09/03 16:26:27 daniel
|
|
* Make Tprocdef.defs protected
|
|
|
|
Revision 1.69 2002/08/25 19:25:20 peter
|
|
* sym.insert_in_data removed
|
|
* symtable.insertvardata/insertconstdata added
|
|
* removed insert_in_data call from symtable.insert, it needs to be
|
|
called separatly. This allows to deref the address calculation
|
|
* procedures now calculate the parast addresses after the procedure
|
|
directives are parsed. This fixes the cdecl parast problem
|
|
* push_addr_param has an extra argument that specifies if cdecl is used
|
|
or not
|
|
|
|
Revision 1.68 2002/08/17 09:23:41 florian
|
|
* first part of procinfo rewrite
|
|
|
|
Revision 1.67 2002/08/16 14:24:59 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.66 2002/08/11 14:32:27 peter
|
|
* renamed current_library to objectlibrary
|
|
|
|
Revision 1.65 2002/08/11 13:24:13 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.64 2002/08/09 19:14:28 carl
|
|
* fixed stackframe parameter (should only contain local size),
|
|
set to zero currently
|
|
|
|
Revision 1.63 2002/08/06 20:55:22 florian
|
|
* first part of ppc calling conventions fix
|
|
|
|
Revision 1.62 2002/07/26 21:15:41 florian
|
|
* rewrote the system handling
|
|
|
|
Revision 1.61 2002/07/20 11:57:56 florian
|
|
* types.pas renamed to defbase.pas because D6 contains a types
|
|
unit so this would conflicts if D6 programms are compiled
|
|
+ Willamette/SSE2 instructions to assembler added
|
|
|
|
Revision 1.60 2002/07/19 11:41:36 daniel
|
|
* State tracker work
|
|
* The whilen and repeatn are now completely unified into whilerepeatn. This
|
|
allows the state tracker to change while nodes automatically into
|
|
repeat nodes.
|
|
* Resulttypepass improvements to the notn. 'not not a' is optimized away and
|
|
'not(a>b)' is optimized into 'a<=b'.
|
|
* Resulttypepass improvements to the whilerepeatn. 'while not a' is optimized
|
|
by removing the notn and later switchting the true and falselabels. The
|
|
same is done with 'repeat until not a'.
|
|
|
|
Revision 1.59 2002/07/15 18:03:15 florian
|
|
* readded removed changes
|
|
|
|
Revision 1.57 2002/07/11 14:41:28 florian
|
|
* start of the new generic parameter handling
|
|
|
|
Revision 1.58 2002/07/14 18:00:44 daniel
|
|
+ Added the beginning of a state tracker. This will track the values of
|
|
variables through procedures and optimize things away.
|
|
|
|
Revision 1.56 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.55 2002/07/04 20:43:01 florian
|
|
* first x86-64 patches
|
|
|
|
Revision 1.54 2002/07/01 18:46:25 peter
|
|
* internal linker
|
|
* reorganized aasm layer
|
|
|
|
Revision 1.53 2002/05/18 13:34:14 peter
|
|
* readded missing revisions
|
|
|
|
Revision 1.52 2002/05/16 19:46:44 carl
|
|
+ defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
|
|
+ try to fix temp allocation (still in ifdef)
|
|
+ generic constructor calls
|
|
+ start of tassembler / tmodulebase class cleanup
|
|
|
|
Revision 1.51 2002/05/14 19:34:49 peter
|
|
* removed old logs and updated copyright year
|
|
|
|
}
|