123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570 |
- {
- Copyright (c) 2000-2002 by Florian Klaempfl
- This unit implements some basic nodes
- 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 ncgbas;
- {$i fpcdefs.inc}
- interface
- uses
- cpubase,cgutils,
- node,nbas;
- type
- tcgnothingnode = class(tnothingnode)
- procedure pass_generate_code;override;
- end;
- tcgasmnode = class(tasmnode)
- procedure pass_generate_code;override;
- end;
- tcgstatementnode = class(tstatementnode)
- procedure pass_generate_code;override;
- end;
- tcgblocknode = class(tblocknode)
- procedure pass_generate_code;override;
- end;
- tcgtempcreatenode = class(ttempcreatenode)
- procedure pass_generate_code;override;
- end;
- tcgtemprefnode = class(ttemprefnode)
- procedure pass_generate_code;override;
- { Changes the location of this temp to ref. Useful when assigning }
- { another temp to this one. The current location will be freed. }
- { Can only be called in pass 2 (since earlier, the temp location }
- { isn't known yet) }
- procedure changelocation(const ref: treference);
- end;
- tcgtempdeletenode = class(ttempdeletenode)
- procedure pass_generate_code;override;
- end;
- implementation
- uses
- globtype,globals,systems,
- cutils,verbose,
- aasmbase,aasmtai,aasmdata,aasmcpu,
- symsym,symconst,symdef,defutil,
- nflw,pass_2,
- cgbase,cgobj,
- procinfo,
- tgobj
- ;
- {*****************************************************************************
- TNOTHING
- *****************************************************************************}
- procedure tcgnothingnode.pass_generate_code;
- begin
- location_reset(location,LOC_VOID,OS_NO);
- { avoid an abstract rte }
- end;
- {*****************************************************************************
- TSTATEMENTNODE
- *****************************************************************************}
- procedure tcgstatementnode.pass_generate_code;
- var
- hp : tstatementnode;
- begin
- location_reset(location,LOC_VOID,OS_NO);
- hp:=self;
- while assigned(hp) do
- begin
- if assigned(hp.left) then
- begin
- secondpass(hp.left);
- { Compiler inserted blocks can return values }
- location_copy(hp.location,hp.left.location);
- end;
- hp:=tstatementnode(hp.right);
- end;
- end;
- {*****************************************************************************
- TASMNODE
- *****************************************************************************}
- procedure tcgasmnode.pass_generate_code;
- procedure ReLabel(var p:tasmsymbol);
- begin
- { Only relabel local tasmlabels }
- if (p.bind = AB_LOCAL) and
- (p is tasmlabel) then
- begin
- if not assigned(p.altsymbol) then
- current_asmdata.GenerateAltSymbol(p);
- p:=p.altsymbol;
- p.increfs;
- end;
- end;
- procedure ResolveRef(var op:toper);
- var
- sym : tabstractnormalvarsym;
- {$ifdef x86}
- scale : byte;
- {$endif x86}
- forceref,
- getoffset : boolean;
- indexreg : tregister;
- sofs : longint;
- begin
- if (op.typ=top_local) then
- begin
- sofs:=op.localoper^.localsymofs;
- indexreg:=op.localoper^.localindexreg;
- {$ifdef x86}
- scale:=op.localoper^.localscale;
- {$endif x86}
- getoffset:=op.localoper^.localgetoffset;
- forceref:=op.localoper^.localforceref;
- sym:=tabstractnormalvarsym(pointer(op.localoper^.localsym));
- dispose(op.localoper);
- case sym.localloc.loc of
- LOC_REFERENCE :
- begin
- if getoffset then
- begin
- if indexreg=NR_NO then
- begin
- op.typ:=top_const;
- op.val:=sym.localloc.reference.offset+sofs;
- end
- else
- begin
- op.typ:=top_ref;
- new(op.ref);
- reference_reset_base(op.ref^,indexreg,sym.localloc.reference.offset+sofs);
- end;
- end
- else
- begin
- op.typ:=top_ref;
- new(op.ref);
- reference_reset_base(op.ref^,sym.localloc.reference.base,sym.localloc.reference.offset+sofs);
- op.ref^.index:=indexreg;
- {$ifdef x86}
- op.ref^.scalefactor:=scale;
- {$endif x86}
- end;
- end;
- LOC_REGISTER :
- begin
- if getoffset then
- Message(asmr_e_invalid_reference_syntax);
- { Subscribed access }
- if forceref or
- (sofs<>0) then
- begin
- op.typ:=top_ref;
- new(op.ref);
- reference_reset_base(op.ref^,sym.localloc.register,sofs);
- op.ref^.index:=indexreg;
- {$ifdef x86}
- op.ref^.scalefactor:=scale;
- {$endif x86}
- end
- else
- begin
- op.typ:=top_reg;
- op.reg:=sym.localloc.register;
- end;
- end;
- end;
- end;
- end;
- var
- hp,hp2 : tai;
- i : longint;
- skipnode : boolean;
- begin
- location_reset(location,LOC_VOID,OS_NO);
- if (nf_get_asm_position in flags) then
- begin
- { Add a marker, to be sure the list is not empty }
- current_asmdata.CurrAsmList.concat(tai_marker.create(mark_Position));
- currenttai:=tai(current_asmdata.CurrAsmList.last);
- exit;
- end;
- { Allocate registers used in the assembler block }
- cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,used_regs_int);
- if (po_inline in current_procinfo.procdef.procoptions) then
- begin
- hp:=tai(p_asm.first);
- while assigned(hp) do
- begin
- hp2:=tai(hp.getcopy);
- skipnode:=false;
- case hp2.typ of
- ait_label :
- ReLabel(tasmsymbol(tai_label(hp2).labsym));
- ait_const :
- begin
- if assigned(tai_const(hp2).sym) then
- ReLabel(tai_const(hp2).sym);
- if assigned(tai_const(hp2).endsym) then
- ReLabel(tai_const(hp2).endsym);
- end;
- ait_instruction :
- begin
- { remove cached insentry, because the new code can
- require an other less optimized instruction }
- {$ifdef i386}
- {$ifndef NOAG386BIN}
- taicpu(hp2).ResetPass1;
- {$endif}
- {$endif}
- { fixup the references }
- for i:=1 to taicpu(hp2).ops do
- begin
- ResolveRef(taicpu(hp2).oper[i-1]^);
- with taicpu(hp2).oper[i-1]^ do
- begin
- case typ of
- top_ref :
- begin
- if assigned(ref^.symbol) then
- ReLabel(ref^.symbol);
- if assigned(ref^.relsymbol) then
- ReLabel(ref^.relsymbol);
- end;
- end;
- end;
- end;
- {$ifdef x86}
- { can only be checked now that all local operands }
- { have been resolved }
- taicpu(hp2).CheckIfValid;
- {$endif x86}
- end;
- ait_marker :
- begin
- { it's not an assembler block anymore }
- if (tai_marker(hp2).kind in [mark_AsmBlockStart, mark_AsmBlockEnd]) then
- skipnode:=true;
- end;
- end;
- if not skipnode then
- current_asmdata.CurrAsmList.concat(hp2)
- else
- hp2.free;
- hp:=tai(hp.next);
- end;
- { restore used symbols }
- current_asmdata.ResetAltSymbols;
- end
- else
- begin
- hp:=tai(p_asm.first);
- while assigned(hp) do
- begin
- case hp.typ of
- ait_instruction :
- begin
- { remove cached insentry, because the new code can
- require an other less optimized instruction }
- {$ifdef i386}
- {$ifndef NOAG386BIN}
- taicpu(hp).ResetPass1;
- {$endif}
- {$endif}
- { fixup the references }
- for i:=1 to taicpu(hp).ops do
- ResolveRef(taicpu(hp).oper[i-1]^);
- {$ifdef x86}
- { can only be checked now that all local operands }
- { have been resolved }
- taicpu(hp).CheckIfValid;
- {$endif x86}
- end;
- end;
- hp:=tai(hp.next);
- end;
- { insert the list }
- current_asmdata.CurrAsmList.concatlist(p_asm);
- end;
- { Release register used in the assembler block }
- cg.dealloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,used_regs_int);
- end;
- {*****************************************************************************
- TBLOCKNODE
- *****************************************************************************}
- procedure tcgblocknode.pass_generate_code;
- var
- hp : tstatementnode;
- oldexitlabel : tasmlabel;
- begin
- location_reset(location,LOC_VOID,OS_NO);
- { replace exitlabel? }
- if nf_block_with_exit in flags then
- begin
- oldexitlabel:=current_procinfo.CurrExitLabel;
- current_asmdata.getjumplabel(current_procinfo.CurrExitLabel);
- end;
- { do second pass on left node }
- if assigned(left) then
- begin
- hp:=tstatementnode(left);
- while assigned(hp) do
- begin
- if assigned(hp.left) then
- begin
- secondpass(hp.left);
- location_copy(hp.location,hp.left.location);
- end;
- location_copy(location,hp.location);
- hp:=tstatementnode(hp.right);
- end;
- end;
- { write exitlabel }
- if nf_block_with_exit in flags then
- begin
- cg.a_label(current_asmdata.CurrAsmList,current_procinfo.CurrExitLabel);
- current_procinfo.CurrExitLabel:=oldexitlabel;
- end;
- end;
- {*****************************************************************************
- TTEMPCREATENODE
- *****************************************************************************}
- procedure tcgtempcreatenode.pass_generate_code;
- begin
- location_reset(location,LOC_VOID,OS_NO);
- { if we're secondpassing the same tcgtempcreatenode twice, we have a bug }
- if tempinfo^.valid then
- internalerror(200108222);
- { get a (persistent) temp }
- if tempinfo^.typedef.needs_inittable then
- begin
- location_reset(tempinfo^.location,LOC_REFERENCE,def_cgsize(tempinfo^.typedef));
- tg.GetTempTyped(current_asmdata.CurrAsmList,tempinfo^.typedef,tempinfo^.temptype,tempinfo^.location.reference);
- { the temp could have been used previously either because the memory location was reused or
- because we're in a loop }
- cg.g_finalize(current_asmdata.CurrAsmList,tempinfo^.typedef,tempinfo^.location.reference);
- end
- else if tempinfo^.may_be_in_reg then
- begin
- if tempinfo^.typedef.typ=floatdef then
- begin
- {$ifdef x86}
- if use_sse(tempinfo^.typedef) then
- begin
- if (tempinfo^.temptype = tt_persistent) then
- location_reset(tempinfo^.location,LOC_CMMREGISTER,def_cgsize(tempinfo^.typedef))
- else
- location_reset(tempinfo^.location,LOC_MMREGISTER,def_cgsize(tempinfo^.typedef));
- tempinfo^.location.register:=cg.getmmregister(current_asmdata.CurrAsmList,tempinfo^.location.size);
- end
- else
- {$endif x86}
- begin
- if (tempinfo^.temptype = tt_persistent) then
- location_reset(tempinfo^.location,LOC_CFPUREGISTER,def_cgsize(tempinfo^.typedef))
- else
- location_reset(tempinfo^.location,LOC_FPUREGISTER,def_cgsize(tempinfo^.typedef));
- tempinfo^.location.register:=cg.getfpuregister(current_asmdata.CurrAsmList,tempinfo^.location.size);
- end;
- end
- else
- begin
- if (tempinfo^.temptype = tt_persistent) then
- location_reset(tempinfo^.location,LOC_CREGISTER,def_cgsize(tempinfo^.typedef))
- else
- location_reset(tempinfo^.location,LOC_REGISTER,def_cgsize(tempinfo^.typedef));
- {$ifndef cpu64bit}
- if tempinfo^.location.size in [OS_64,OS_S64] then
- begin
- tempinfo^.location.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
- tempinfo^.location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
- end
- else
- {$endif cpu64bit}
- tempinfo^.location.register:=cg.getintregister(current_asmdata.CurrAsmList,tempinfo^.location.size);
- end;
- end
- else
- begin
- location_reset(tempinfo^.location,LOC_REFERENCE,def_cgsize(tempinfo^.typedef));
- tg.GetTemp(current_asmdata.CurrAsmList,size,tempinfo^.temptype,tempinfo^.location.reference);
- end;
- tempinfo^.valid := true;
- end;
- {*****************************************************************************
- TTEMPREFNODE
- *****************************************************************************}
- procedure tcgtemprefnode.pass_generate_code;
- begin
- { check if the temp is valid }
- if not tempinfo^.valid then
- internalerror(200108231);
- location:=tempinfo^.location;
- case tempinfo^.location.loc of
- LOC_REFERENCE:
- begin
- inc(location.reference.offset,offset);
- { tempinfo^.valid should be set to false it it's a normal temp }
- end;
- LOC_REGISTER,
- LOC_FPUREGISTER,
- LOC_MMREGISTER :
- tempinfo^.valid := false;
- end;
- end;
- procedure tcgtemprefnode.changelocation(const ref: treference);
- begin
- { check if the temp is valid }
- if not tempinfo^.valid then
- internalerror(200306081);
- if (tempinfo^.location.loc<>LOC_REFERENCE) then
- internalerror(2004020203);
- if (tempinfo^.temptype = tt_persistent) then
- tg.ChangeTempType(current_asmdata.CurrAsmList,tempinfo^.location.reference,tt_normal);
- tg.ungettemp(current_asmdata.CurrAsmList,tempinfo^.location.reference);
- tempinfo^.location.reference := ref;
- tg.ChangeTempType(current_asmdata.CurrAsmList,tempinfo^.location.reference,tempinfo^.temptype);
- { adapt location }
- location.reference := ref;
- inc(location.reference.offset,offset);
- end;
- {*****************************************************************************
- TTEMPDELETENODE
- *****************************************************************************}
- procedure tcgtempdeletenode.pass_generate_code;
- begin
- location_reset(location,LOC_VOID,OS_NO);
- case tempinfo^.location.loc of
- LOC_REFERENCE:
- begin
- if release_to_normal then
- tg.ChangeTempType(current_asmdata.CurrAsmList,tempinfo^.location.reference,tt_normal)
- else
- begin
- tg.UnGetTemp(current_asmdata.CurrAsmList,tempinfo^.location.reference);
- tempinfo^.valid := false;
- end;
- end;
- LOC_CREGISTER,
- LOC_REGISTER:
- begin
- if not(cs_opt_regvar in current_settings.optimizerswitches) or
- (pi_has_goto in current_procinfo.flags) then
- begin
- { make sure the register allocator doesn't reuse the }
- { register e.g. in the middle of a loop }
- {$ifndef cpu64bit}
- if tempinfo^.location.size in [OS_64,OS_S64] then
- begin
- cg.a_reg_sync(current_asmdata.CurrAsmList,tempinfo^.location.register64.reghi);
- cg.a_reg_sync(current_asmdata.CurrAsmList,tempinfo^.location.register64.reglo);
- end
- else
- {$endif cpu64bit}
- cg.a_reg_sync(current_asmdata.CurrAsmList,tempinfo^.location.register);
- end;
- if release_to_normal then
- tempinfo^.location.loc := LOC_REGISTER
- else
- tempinfo^.valid := false;
- end;
- LOC_CFPUREGISTER,
- LOC_FPUREGISTER:
- begin
- if not(cs_opt_regvar in current_settings.optimizerswitches) or
- (pi_has_goto in current_procinfo.flags) then
- begin
- { make sure the register allocator doesn't reuse the }
- { register e.g. in the middle of a loop }
- cg.a_reg_sync(current_asmdata.CurrAsmList,tempinfo^.location.register);
- end;
- if release_to_normal then
- tempinfo^.location.loc := LOC_FPUREGISTER
- else
- tempinfo^.valid := false;
- end;
- LOC_CMMREGISTER,
- LOC_MMREGISTER:
- begin
- if not(cs_opt_regvar in current_settings.optimizerswitches) or
- (pi_has_goto in current_procinfo.flags) then
- begin
- { make sure the register allocator doesn't reuse the }
- { register e.g. in the middle of a loop }
- cg.a_reg_sync(current_asmdata.CurrAsmList,tempinfo^.location.register);
- end;
- if release_to_normal then
- tempinfo^.location.loc := LOC_MMREGISTER
- else
- tempinfo^.valid := false;
- end;
- else
- internalerror(200507161);
- end;
- end;
- begin
- cnothingnode:=tcgnothingnode;
- casmnode:=tcgasmnode;
- cstatementnode:=tcgstatementnode;
- cblocknode:=tcgblocknode;
- ctempcreatenode:=tcgtempcreatenode;
- ctemprefnode:=tcgtemprefnode;
- ctempdeletenode:=tcgtempdeletenode;
- end.
|