{ $Id$ Copyright (c) 1998-2002 by Florian Klaempfl Generate i386 assembler for in memory related 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 n386mem; {$i fpcdefs.inc} interface uses node,nmem,ncgmem; type ti386addrnode = class(tcgaddrnode) procedure pass_2;override; end; ti386derefnode = class(tcgderefnode) procedure pass_2;override; end; ti386vecnode = class(tcgvecnode) procedure pass_2;override; end; implementation uses {$ifdef delphi} sysutils, {$endif} globtype,systems, cutils,verbose,globals, symconst,symtype,symdef,symsym,symtable,defbase,paramgr, aasmbase,aasmtai,aasmcpu, cginfo,cgbase,pass_2, pass_1,nld,ncon,nadd, cpubase, cgobj,cga,tgobj,rgobj,ncgutil; {***************************************************************************** TI386ADDRNODE *****************************************************************************} procedure ti386addrnode.pass_2; begin inherited pass_2; { for use of other segments } if left.location.reference.segment<>R_NO then location.segment:=left.location.reference.segment; end; {***************************************************************************** TI386DEREFNODE *****************************************************************************} procedure ti386derefnode.pass_2; var oldglobalswitches : tglobalswitches; begin oldglobalswitches:=aktglobalswitches; exclude(aktglobalswitches,cs_checkpointer); inherited pass_2; aktglobalswitches:=oldglobalswitches; if tpointerdef(left.resulttype.def).is_far then location.reference.segment:=R_FS; if not tpointerdef(left.resulttype.def).is_far and (cs_gdb_heaptrc in aktglobalswitches) and (cs_checkpointer in aktglobalswitches) then begin cg.a_param_reg(exprasmlist, OS_ADDR,location.reference.base,paramanager.getintparaloc(1)); cg.a_call_name(exprasmlist,'FPC_CHECKPOINTER'); end; end; {***************************************************************************** TI386VECNODE *****************************************************************************} procedure ti386vecnode.pass_2; procedure calc_emit_mul; var l1,l2 : longint; begin l1:=get_mul_size; case l1 of 1,2,4,8 : location.reference.scalefactor:=l1; else begin if ispowerof2(l1,l2) then emit_const_reg(A_SHL,S_L,l2,right.location.register) else emit_const_reg(A_IMUL,S_L,l1,right.location.register); end; end; end; var extraoffset : longint; { rl stores the resulttype.def of the left node, this is necessary } { to detect if it is an ansistring } { because in constant nodes which constant index } { the left tree is removed } t : tnode; href : treference; srsym : tsym; pushed : tpushedsaved; hightree : tnode; isjump : boolean; otl,ofl : tasmlabel; newsize : tcgsize; pushedregs : tmaybesave; begin newsize:=def_cgsize(resulttype.def); location_reset(location,LOC_REFERENCE,newsize); secondpass(left); { we load the array reference to location } { an ansistring needs to be dereferenced } if is_ansistring(left.resulttype.def) or is_widestring(left.resulttype.def) then begin if nf_callunique in flags then begin if left.location.loc<>LOC_REFERENCE then begin CGMessage(cg_e_illegal_expression); exit; end; rg.saveusedregisters(exprasmlist,pushed,all_registers); cg.a_paramaddr_ref(exprasmlist,left.location.reference,paramanager.getintparaloc(1)); rg.saveregvars(exprasmlist,all_registers); cg.a_call_name(exprasmlist,'FPC_'+Upper(tstringdef(left.resulttype.def).stringtypname)+'_UNIQUE'); cg.g_maybe_loadself(exprasmlist); rg.restoreusedregisters(exprasmlist,pushed); end; case left.location.loc of LOC_REGISTER, LOC_CREGISTER : location.reference.base:=left.location.register; LOC_CREFERENCE, LOC_REFERENCE : begin location_release(exprasmlist,left.location); location.reference.base:=rg.getregisterint(exprasmlist); cg.a_load_ref_reg(exprasmlist,OS_ADDR,left.location.reference,location.reference.base); end; else internalerror(2002032218); end; { check for a zero length string, we can use the ansistring routine here } if (cs_check_range in aktlocalswitches) then begin rg.saveusedregisters(exprasmlist,pushed,all_registers); cg.a_param_reg(exprasmlist,OS_ADDR,location.reference.base,paramanager.getintparaloc(1)); rg.saveregvars(exprasmlist,all_registers); cg.a_call_name(exprasmlist,'FPC_'+Upper(tstringdef(left.resulttype.def).stringtypname)+'_CHECKZERO'); cg.g_maybe_loadself(exprasmlist); rg.restoreusedregisters(exprasmlist,pushed); end; { in ansistrings/widestrings S[1] is pchar(S)[0] !! } if is_ansistring(left.resulttype.def) then dec(location.reference.offset) else dec(location.reference.offset,2); { we've also to keep left up-to-date, because it is used } { if a constant array index occurs, subject to change (FK) } location_copy(left.location,location); end else if is_dynamic_array(left.resulttype.def) then { ... also a dynamic string } begin case left.location.loc of LOC_REGISTER, LOC_CREGISTER : location.reference.base:=left.location.register; LOC_REFERENCE, LOC_CREFERENCE : begin location_release(exprasmlist,left.location); location.reference.base:=rg.getregisterint(exprasmlist); emit_ref_reg(A_MOV,S_L, left.location.reference,location.reference.base); end; else internalerror(2002032219); end; {$warning FIXME} { check for a zero length string, we can use the ansistring routine here } if (cs_check_range in aktlocalswitches) then begin rg.saveusedregisters(exprasmlist,pushed,all_registers); emit_reg(A_PUSH,S_L,location.reference.base); rg.saveregvars(exprasmlist,all_registers); cg.a_call_name(exprasmlist,'FPC_ANSISTR_CHECKZERO'); cg.g_maybe_loadself(exprasmlist); rg.restoreusedregisters(exprasmlist,pushed); end; { we've also to keep left up-to-date, because it is used } { if a constant array index occurs, subject to change (FK) } location_copy(left.location,location); end else location_copy(location,left.location); { offset can only differ from 0 if arraydef } if (left.resulttype.def.deftype=arraydef) and not(is_dynamic_array(left.resulttype.def)) then dec(location.reference.offset, get_mul_size*tarraydef(left.resulttype.def).lowrange); if right.nodetype=ordconstn then begin { offset can only differ from 0 if arraydef } if (left.resulttype.def.deftype=arraydef) then begin if not(is_open_array(left.resulttype.def)) and not(is_array_of_const(left.resulttype.def)) and not(is_dynamic_array(left.resulttype.def)) then begin if (tordconstnode(right).value>tarraydef(left.resulttype.def).highrange) or (tordconstnode(right).value 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.30 2002/05/13 19:54:38 peter * removed n386ld and n386util units * maybe_save/maybe_restore added instead of the old maybe_push Revision 1.29 2002/05/12 16:53:17 peter * moved entry and exitcode to ncgutil and cgobj * foreach gets extra argument for passing local data to the iterator function * -CR checks also class typecasts at runtime by changing them into as * fixed compiler to cycle with the -CR option * fixed stabs with elf writer, finally the global variables can be watched * removed a lot of routines from cga unit and replaced them by calls to cgobj * u32bit-s32bit updates for and,or,xor nodes. When one element is u32bit then the other is typecasted also to u32bit without giving a rangecheck warning/error. * fixed pascal calling method with reversing also the high tree in the parast, detected by tcalcst3 test Revision 1.28 2002/04/21 19:02:07 peter * removed newn and disposen nodes, the code is now directly inlined from pexpr * -an option that will write the secondpass nodes to the .s file, this requires EXTDEBUG define to actually write the info * fixed various internal errors and crashes due recent code changes Revision 1.27 2002/04/20 21:37:07 carl + generic FPC_CHECKPOINTER + first parameter offset in stack now portable * rename some constants + move some cpu stuff to other units - remove unused constents * fix stacksize for some targets * fix generic size problems which depend now on EXTEND_SIZE constant * removing frame pointer in routines is only available for : i386,m68k and vis targets Revision 1.26 2002/04/19 15:39:35 peter * removed some more routines from cga * moved location_force_reg/mem to ncgutil * moved arrayconstructnode secondpass to ncgld Revision 1.25 2002/04/15 19:12:09 carl + target_info.size_of_pointer -> pointer_size + some cleanup of unused types/variables * move several constants from cpubase to their specific units (where they are used) + att_Reg2str -> gas_reg2str + int_reg2str -> std_reg2str Revision 1.24 2002/04/04 19:06:12 peter * removed unused units * use tlocation.size in cg.a_*loc*() routines Revision 1.23 2002/04/02 17:11:36 peter * tlocation,treference update * LOC_CONSTANT added for better constant handling * secondadd splitted in multiple routines * location_force_reg added for loading a location to a register of a specified size * secondassignment parses now first the right and then the left node (this is compatible with Kylix). This saves a lot of push/pop especially with string operations * adapted some routines to use the new cg methods Revision 1.22 2002/04/01 09:44:04 jonas * better fix for new/dispose bug with init/final data Revision 1.21 2002/03/31 20:26:39 jonas + a_loadfpu_* and a_loadmm_* methods in tcg * register allocation is now handled by a class and is mostly processor independent (+rgobj.pas and i386/rgcpu.pas) * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas) * some small improvements and fixes to the optimizer * some register allocation fixes * some fpuvaroffset fixes in the unary minus node * push/popusedregisters is now called rg.save/restoreusedregisters and (for i386) uses temps instead of push/pop's when using -Op3 (that code is also better optimizable) * fixed and optimized register saving/restoring for new/dispose nodes * LOC_FPU locations now also require their "register" field to be set to R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only) - list field removed of the tnode class because it's not used currently and can cause hard-to-find bugs Revision 1.20 2002/03/04 19:10:14 peter * removed compiler warnings }