* call firstpass before allocation and codegeneration is started

* move leftover code from pass_2.generatecode() to psub
This commit is contained in:
peter 2003-10-30 16:22:40 +00:00
parent 1953a4a4f2
commit 9e66b09843
4 changed files with 219 additions and 219 deletions

View File

@ -37,10 +37,6 @@ uses
allow_multi_pass2 : boolean; allow_multi_pass2 : boolean;
flowcontrol : tflowcontrol; flowcontrol : tflowcontrol;
{ produces assembler for the expression in variable p }
{ and produces an assembler node at the end }
procedure generatecode(var p : tnode);
{ produces the actual code } { produces the actual code }
function do_secondpass(var p : tnode) : boolean; function do_secondpass(var p : tnode) : boolean;
procedure secondpass(var p : tnode); procedure secondpass(var p : tnode);
@ -210,78 +206,15 @@ implementation
do_secondpass:=codegenerror; do_secondpass:=codegenerror;
end; end;
procedure clearrefs(p : tnamedindexitem;arg:pointer);
begin
if (tsym(p).typ=varsym) then
if tvarsym(p).refs>1 then
tvarsym(p).refs:=1;
end;
procedure generatecode(var p : tnode);
begin
flowcontrol:=[];
{ when size optimization only count occurrence }
if cs_littlesize in aktglobalswitches then
cg.t_times:=1
else
{ reference for repetition is 100 }
cg.t_times:=100;
{ clear register count }
symtablestack.foreach_static({$ifdef FPCPROCVAR}@{$endif}clearrefs,nil);
symtablestack.next.foreach_static({$ifdef FPCPROCVAR}@{$endif}clearrefs,nil);
{ firstpass everything }
do_firstpass(p);
{ after pass 1, we should have all necessary information to set the temp. start location }
current_procinfo.set_first_temp_offset;
{ only do secondpass if there are no errors }
if ErrorCount=0 then
begin
{ caller paraloc info is also necessary in the stackframe_entry }
{ code of the ppc (and possibly other processors) }
if not current_procinfo.procdef.has_paraloc_info then
begin
paramanager.create_paraloc_info(current_procinfo.procdef,callerside);
current_procinfo.procdef.has_paraloc_info:=true;
end;
{ process register variable stuff (JM) }
{ assign_regvars(p);}
{ load_regvars(current_procinfo.aktentrycode,p);}
{ for the i386 it must be done in genexitcode because it has }
{ to add 'fstp' instructions when using fpu regvars and those }
{ must come after the "exitlabel" (JM) }
{$ifndef i386}
{ cleanup_regvars(current_procinfo.aktexitcode);}
{$endif i386}
{ current_procinfo.allocate_framepointer_reg;}
do_secondpass(p);
{$ifdef EXTDEBUG}
{
for sr:=first_int_imreg to last_int_imreg do
if not(sr in rg.unusedregsint) then
Comment(V_Warning,'Register '+std_regname(newreg(R_INTREGISTER,sr,R_SUBNONE))+' not released');
}
{$endif EXTDEBUG}
{$ifdef i386}
if assigned(current_procinfo.procdef) then
current_procinfo.procdef.fpu_used:=p.registersfpu;
{$endif i386}
end;
current_procinfo.aktproccode.concatlist(exprasmlist);
end;
end. end.
{ {
$Log$ $Log$
Revision 1.72 2003-10-19 01:34:30 florian Revision 1.73 2003-10-30 16:22:40 peter
* call firstpass before allocation and codegeneration is started
* move leftover code from pass_2.generatecode() to psub
Revision 1.72 2003/10/19 01:34:30 florian
* some ppc stuff fixed * some ppc stuff fixed
* memory leak fixed * memory leak fixed

View File

@ -566,6 +566,14 @@ implementation
end; end;
procedure clearrefs(p : tnamedindexitem;arg:pointer);
begin
if (tsym(p).typ=varsym) then
if tvarsym(p).refs>1 then
tvarsym(p).refs:=1;
end;
procedure tcgprocinfo.generate_code; procedure tcgprocinfo.generate_code;
var var
oldprocinfo : tprocinfo; oldprocinfo : tprocinfo;
@ -605,168 +613,197 @@ implementation
{ add parast/localst to symtablestack } { add parast/localst to symtablestack }
add_to_symtablestack; add_to_symtablestack;
{ set the start offset to the start of the temp area in the stack } { when size optimization only count occurrence }
tg:=ttgobj.create; if cs_littlesize in aktglobalswitches then
cg.t_times:=1
{ Create register allocator }
cg.init_register_allocators;
current_procinfo.set_first_temp_offset;
current_procinfo.generate_parameter_info;
{ Allocate space in temp/registers for parast and localst }
aktfilepos:=entrypos;
gen_alloc_parast(aktproccode,tparasymtable(current_procinfo.procdef.parast));
if current_procinfo.procdef.localst.symtabletype=localsymtable then
gen_alloc_localst(aktproccode,tlocalsymtable(current_procinfo.procdef.localst));
if (cs_asm_source in aktglobalswitches) then
aktproccode.concat(Tai_comment.Create(strpnew('Temps start at '+std_regname(current_procinfo.framepointer)+
tostr_with_plus(tg.lasttemp))));
{ Generate code to load register parameters in temps and insert local
copies for values parameters. This must be done before the code for the
body is generated because the localloc is updated.
Note: The generated code will be inserted after the code generation of
the body is finished, because only then the position is known }
aktfilepos:=entrypos;
gen_load_para_value(templist);
{ generate code for the body }
generatecode(code);
{ The position of the loadpara_asmnode is now known }
aktproccode.insertlistafter(loadpara_asmnode.currenttai,templist);
{ first generate entry and initialize code with the correct
position and switches }
aktfilepos:=entrypos;
aktlocalswitches:=entryswitches;
gen_entry_code(templist);
aktproccode.insertlistafter(entry_asmnode.currenttai,templist);
gen_initialize_code(templist,false);
aktproccode.insertlistafter(init_asmnode.currenttai,templist);
{ now generate finalize and exit code with the correct position
and switches }
aktfilepos:=exitpos;
aktlocalswitches:=exitswitches;
gen_finalize_code(templist,false);
{ the finalcode must be concated if there was no position available,
using insertlistafter will result in an insert at the start
when currentai=nil }
if assigned(final_asmnode.currenttai) then
aktproccode.insertlistafter(final_asmnode.currenttai,templist)
else else
aktproccode.concatlist(templist); { reference for repetition is 100 }
{ insert exit label at the correct position } cg.t_times:=100;
cg.a_label(templist,current_procinfo.aktexitlabel);
if assigned(exitlabel_asmnode.currenttai) then { clear register count }
aktproccode.insertlistafter(exitlabel_asmnode.currenttai,templist) symtablestack.foreach_static({$ifdef FPCPROCVAR}@{$endif}clearrefs,nil);
else symtablestack.next.foreach_static({$ifdef FPCPROCVAR}@{$endif}clearrefs,nil);
aktproccode.concatlist(templist);
{ exit code } { firstpass everything }
gen_exit_code(templist); flowcontrol:=[];
aktproccode.concatlist(templist); do_firstpass(code);
{ only do secondpass if there are no errors }
if ErrorCount=0 then
begin
{ set the start offset to the start of the temp area in the stack }
tg:=ttgobj.create;
{ Create register allocator }
cg.init_register_allocators;
current_procinfo.set_first_temp_offset;
current_procinfo.generate_parameter_info;
{ Allocate space in temp/registers for parast and localst }
aktfilepos:=entrypos;
gen_alloc_parast(aktproccode,tparasymtable(current_procinfo.procdef.parast));
if current_procinfo.procdef.localst.symtabletype=localsymtable then
gen_alloc_localst(aktproccode,tlocalsymtable(current_procinfo.procdef.localst));
if (cs_asm_source in aktglobalswitches) then
aktproccode.concat(Tai_comment.Create(strpnew('Temps start at '+std_regname(current_procinfo.framepointer)+
tostr_with_plus(tg.lasttemp))));
{ Generate code to load register parameters in temps and insert local
copies for values parameters. This must be done before the code for the
body is generated because the localloc is updated.
Note: The generated code will be inserted after the code generation of
the body is finished, because only then the position is known }
aktfilepos:=entrypos;
gen_load_para_value(templist);
{ caller paraloc info is also necessary in the stackframe_entry
code of the ppc (and possibly other processors) }
if not procdef.has_paraloc_info then
begin
paramanager.create_paraloc_info(procdef,callerside);
procdef.has_paraloc_info:=true;
end;
{ generate code for the node tree }
do_secondpass(code);
current_procinfo.aktproccode.concatlist(exprasmlist);
{$ifdef i386}
procdef.fpu_used:=code.registersfpu;
{$endif i386}
{ The position of the loadpara_asmnode is now known }
aktproccode.insertlistafter(loadpara_asmnode.currenttai,templist);
{ first generate entry and initialize code with the correct
position and switches }
aktfilepos:=entrypos;
aktlocalswitches:=entryswitches;
gen_entry_code(templist);
aktproccode.insertlistafter(entry_asmnode.currenttai,templist);
gen_initialize_code(templist,false);
aktproccode.insertlistafter(init_asmnode.currenttai,templist);
{ now generate finalize and exit code with the correct position
and switches }
aktfilepos:=exitpos;
aktlocalswitches:=exitswitches;
gen_finalize_code(templist,false);
{ the finalcode must be concated if there was no position available,
using insertlistafter will result in an insert at the start
when currentai=nil }
if assigned(final_asmnode.currenttai) then
aktproccode.insertlistafter(final_asmnode.currenttai,templist)
else
aktproccode.concatlist(templist);
{ insert exit label at the correct position }
cg.a_label(templist,current_procinfo.aktexitlabel);
if assigned(exitlabel_asmnode.currenttai) then
aktproccode.insertlistafter(exitlabel_asmnode.currenttai,templist)
else
aktproccode.concatlist(templist);
{ exit code }
gen_exit_code(templist);
aktproccode.concatlist(templist);
{$ifdef OLDREGVARS} {$ifdef OLDREGVARS}
{ note: this must be done only after as much code as possible has } { note: this must be done only after as much code as possible has }
{ been generated. The result is that when you ungetregister() a } { been generated. The result is that when you ungetregister() a }
{ regvar, it will actually free the regvar (and alse free the } { regvar, it will actually free the regvar (and alse free the }
{ the regvars at the same time). Doing this too early will } { the regvars at the same time). Doing this too early will }
{ confuse the register allocator, as the regvars will still be } { confuse the register allocator, as the regvars will still be }
{ used. It should be done before loading the result regs (so } { used. It should be done before loading the result regs (so }
{ they don't conflict with the regvars) and before } { they don't conflict with the regvars) and before }
{ gen_entry_code (that one has to be able to allocate the } { gen_entry_code (that one has to be able to allocate the }
{ regvars again) (JM) } { regvars again) (JM) }
free_regvars(aktproccode); free_regvars(aktproccode);
{$endif OLDREGVARS} {$endif OLDREGVARS}
{ add code that will load the return value, this is not done { add code that will load the return value, this is not done
for assembler routines when they didn't reference the result for assembler routines when they didn't reference the result
variable } variable }
usesacc:=false; usesacc:=false;
usesfpu:=false; usesfpu:=false;
usesacchi:=false; usesacchi:=false;
gen_load_return_value(templist,usesacc,usesacchi,usesfpu); gen_load_return_value(templist,usesacc,usesacchi,usesfpu);
aktproccode.concatlist(templist); aktproccode.concatlist(templist);
{ generate symbol and save end of header position } { generate symbol and save end of header position }
aktfilepos:=entrypos; aktfilepos:=entrypos;
gen_proc_symbol(templist); gen_proc_symbol(templist);
headertai:=tai(templist.last); headertai:=tai(templist.last);
{ insert symbol } { insert symbol }
aktproccode.insertlist(templist); aktproccode.insertlist(templist);
{ Free space in temp/registers for parast and localst, must be { Free space in temp/registers for parast and localst, must be
done after gen_entry_code } done after gen_entry_code }
aktfilepos:=exitpos; aktfilepos:=exitpos;
if current_procinfo.procdef.localst.symtabletype=localsymtable then if current_procinfo.procdef.localst.symtabletype=localsymtable then
gen_free_localst(aktproccode,tlocalsymtable(current_procinfo.procdef.localst)); gen_free_localst(aktproccode,tlocalsymtable(current_procinfo.procdef.localst));
gen_free_parast(aktproccode,tparasymtable(current_procinfo.procdef.parast)); gen_free_parast(aktproccode,tparasymtable(current_procinfo.procdef.parast));
{ The procedure body is finished, we can now { The procedure body is finished, we can now
allocate the registers } allocate the registers }
if not(cs_no_regalloc in aktglobalswitches) then if not(cs_no_regalloc in aktglobalswitches) then
begin begin
cg.do_register_allocation(aktproccode,headertai); cg.do_register_allocation(aktproccode,headertai);
(* (*
{$ifndef NoOpt} {$ifndef NoOpt}
if (cs_optimize in aktglobalswitches) and if (cs_optimize in aktglobalswitches) and
{ do not optimize pure assembler procedures } { do not optimize pure assembler procedures }
not(pi_is_assembler in current_procinfo.flags) then not(pi_is_assembler in current_procinfo.flags) then
optimize(aktproccode); optimize(aktproccode);
{$endif NoOpt} {$endif NoOpt}
*) *)
end; end;
{$warning fixme translate_regvars} { Add save and restore of used registers }
{ translate_regvars(aktproccode,rg.colour);} aktfilepos:=entrypos;
{ Add save and restore of used registers } gen_save_used_regs(templist);
aktfilepos:=entrypos; aktproccode.insertlistafter(headertai,templist);
gen_save_used_regs(templist); aktfilepos:=exitpos;
aktproccode.insertlistafter(headertai,templist); gen_restore_used_regs(aktproccode,usesacc,usesacchi,usesfpu);
aktfilepos:=exitpos; { Add stack allocation code after header }
gen_restore_used_regs(aktproccode,usesacc,usesacchi,usesfpu); aktfilepos:=entrypos;
{ Add stack allocation code after header } gen_stackalloc_code(templist);
aktfilepos:=entrypos; aktproccode.insertlistafter(headertai,templist);
gen_stackalloc_code(templist); { Add exit code at the end }
aktproccode.insertlistafter(headertai,templist); aktfilepos:=exitpos;
{ Add exit code at the end } gen_stackfree_code(templist,usesacc,usesacchi);
aktfilepos:=exitpos; aktproccode.concatlist(templist);
gen_stackfree_code(templist,usesacc,usesacchi); { Add end symbol and debug info }
aktproccode.concatlist(templist); aktfilepos:=exitpos;
{ Add end symbol and debug info } gen_proc_symbol_end(templist);
aktfilepos:=exitpos; aktproccode.concatlist(templist);
gen_proc_symbol_end(templist);
aktproccode.concatlist(templist);
{ save local data (casetable) also in the same file } { save local data (casetable) also in the same file }
if assigned(aktlocaldata) and if assigned(aktlocaldata) and
(not aktlocaldata.empty) then (not aktlocaldata.empty) then
begin
{ because of the limited constant size of the arm, all data access is done pc relative }
if target_info.cpu=cpu_arm then
aktproccode.concatlist(aktlocaldata)
else
begin begin
aktproccode.concat(Tai_section.Create(sec_data)); { because of the limited constant size of the arm, all data access is done pc relative }
aktproccode.concatlist(aktlocaldata); if target_info.cpu=cpu_arm then
aktproccode.concat(Tai_section.Create(sec_code)); aktproccode.concatlist(aktlocaldata)
end; else
end; begin
aktproccode.concat(Tai_section.Create(sec_data));
aktproccode.concatlist(aktlocaldata);
aktproccode.concat(Tai_section.Create(sec_code));
end;
end;
{ add the procedure to the codesegment } { add the procedure to the codesegment }
if (cs_create_smart in aktmoduleswitches) then if (cs_create_smart in aktmoduleswitches) then
codesegment.concat(Tai_cut.Create); codesegment.concat(Tai_cut.Create);
codesegment.concatlist(aktproccode); codesegment.concatlist(aktproccode);
{ only now we can remove the temps } { only now we can remove the temps }
tg.resettempgen; tg.resettempgen;
{ stop tempgen and ra } { stop tempgen and ra }
tg.free; tg.free;
cg.done_register_allocators; cg.done_register_allocators;
tg:=nil; tg:=nil;
end;
{ restore symtablestack } { restore symtablestack }
remove_from_symtablestack; remove_from_symtablestack;
@ -1266,7 +1303,11 @@ implementation
end. end.
{ {
$Log$ $Log$
Revision 1.167 2003-10-24 17:40:23 peter Revision 1.168 2003-10-30 16:22:40 peter
* call firstpass before allocation and codegeneration is started
* move leftover code from pass_2.generatecode() to psub
Revision 1.167 2003/10/24 17:40:23 peter
* cleanup of the entry and exit code insertion * cleanup of the entry and exit code insertion
Revision 1.166 2003/10/21 15:14:33 peter Revision 1.166 2003/10/21 15:14:33 peter

View File

@ -235,6 +235,7 @@ unit rgobj;
procedure translate_registers(list:Taasmoutput); procedure translate_registers(list:Taasmoutput);
{# Adds an interference edge.} {# Adds an interference edge.}
procedure add_edge(u,v:Tsuperregister); procedure add_edge(u,v:Tsuperregister);
procedure check_unreleasedregs;
unusedregs : Tsuperregisterset; unusedregs : Tsuperregisterset;
@ -1801,10 +1802,29 @@ implementation
end; end;
end; end;
procedure Trgobj.check_unreleasedregs;
{$ifdef EXTDEBUG}
var
sr : tsuperregister;
{$endif EXTDEBUG}
begin
{$ifdef EXTDEBUG}
for sr:=first_imaginary to maxreg-1 do
if not(supregset_in(unusedregs,sr)) then
Comment(V_Warning,'Register '+std_regname(newreg(R_INTREGISTER,sr,R_SUBNONE))+' not released');
{$endif EXTDEBUG}
end;
end. end.
{ {
$Log$ $Log$
Revision 1.92 2003-10-29 21:29:14 jonas Revision 1.93 2003-10-30 16:22:40 peter
* call firstpass before allocation and codegeneration is started
* move leftover code from pass_2.generatecode() to psub
Revision 1.92 2003/10/29 21:29:14 jonas
* some ALLOWDUPREG improvements * some ALLOWDUPREG improvements
Revision 1.91 2003/10/21 15:15:36 peter Revision 1.91 2003/10/21 15:15:36 peter

View File

@ -310,9 +310,11 @@ unit cgx86;
begin begin
{ Int } { Int }
rgint.check_unreleasedregs;
rgint.do_register_allocation(list,headertai); rgint.do_register_allocation(list,headertai);
rgint.translate_registers(list); rgint.translate_registers(list);
{ SSE } { SSE }
rgmm.check_unreleasedregs;
rgmm.do_register_allocation(list,headertai); rgmm.do_register_allocation(list,headertai);
rgmm.translate_registers(list); rgmm.translate_registers(list);
end; end;
@ -1735,7 +1737,11 @@ unit cgx86;
end. end.
{ {
$Log$ $Log$
Revision 1.84 2003-10-29 21:24:14 jonas Revision 1.85 2003-10-30 16:22:40 peter
* call firstpass before allocation and codegeneration is started
* move leftover code from pass_2.generatecode() to psub
Revision 1.84 2003/10/29 21:24:14 jonas
+ support for fpu temp parameters + support for fpu temp parameters
+ saving/restoring of fpu register before/after a procedure call + saving/restoring of fpu register before/after a procedure call