{ $Id$ Copyright (C) 1998-2000 by Florian Klaempfl This unit handles the temporary variables stuff for i386 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 temp_gen; {$i defines.inc} interface uses cpubase,cpuinfo,cobjects,globals, hcodegen,verbose,fmodule,aasm; {$ifdef newcg} const countusableregint : byte = c_countusableregsint; countusableregfpu : byte = c_countusableregsfpu; countusableregmm : byte = c_countusableregsmm; {$endif newcg} type ttemptype = (tt_none,tt_free,tt_normal,tt_persistant, tt_ansistring,tt_freeansistring,tt_widestring,tt_freewidestring, tt_interfacecom,tt_freeinterfacecom); ttemptypeset = set of ttemptype; ptemprecord = ^ttemprecord; ttemprecord = record temptype : ttemptype; pos : longint; size : longint; next : ptemprecord; nextfree : ptemprecord; { for faster freeblock checking } {$ifdef EXTDEBUG} posinfo, releaseposinfo : tfileposinfo; {$endif} end; var { contains all temps } templist : ptemprecord; { contains all free temps using nextfree links } tempfreelist : ptemprecord; { Offsets of the first/last temp } firsttemp, lasttemp : longint; { generates temporary variables } procedure resettempgen; procedure setfirsttemp(l : longint); function gettempsize : longint; function newtempofsize(size : longint) : longint; function gettempofsize(size : longint) : longint; { special call for inlined procedures } function gettempofsizepersistant(size : longint) : longint; procedure gettempofsizereferencepersistant(l : longint;var ref : treference); { for parameter func returns } procedure normaltemptopersistant(pos : longint); procedure persistanttemptonormal(pos : longint); {procedure ungettemp(pos : longint;size : longint);} procedure ungetpersistanttemp(pos : longint); procedure ungetpersistanttempreference(const ref : treference); procedure gettempofsizereference(l : longint;var ref : treference); function istemp(const ref : treference) : boolean; procedure ungetiftemp(const ref : treference); function getsizeoftemp(const ref: treference): longint; function ungetiftempansi(const ref : treference) : boolean; procedure gettempansistringreference(var ref : treference); function ungetiftempintfcom(const ref : treference) : boolean; procedure gettempintfcomreference(var ref : treference); implementation uses cutils,systems; procedure resettempgen; var hp : ptemprecord; begin { Clear the old templist } while assigned(templist) do begin {$ifdef EXTDEBUG} case tempList^.temptype of tt_normal, tt_persistant : Comment(V_Warning,'temporary assignment of size '+ tostr(templist^.size)+' from pos '+tostr(templist^.posinfo.line)+ ':'+tostr(templist^.posinfo.column)+ ' at pos '+tostr(templist^.pos)+ ' not freed at the end of the procedure'); tt_ansistring : Comment(V_Warning,'temporary ANSI assignment of size '+ tostr(templist^.size)+' from pos '+tostr(templist^.posinfo.line)+ ':'+tostr(templist^.posinfo.column)+ ' at pos '+tostr(templist^.pos)+ ' not freed at the end of the procedure'); end; {$endif} hp:=templist; templist:=hp^.next; dispose(hp); end; templist:=nil; tempfreelist:=nil; firsttemp:=0; lasttemp:=0; end; procedure setfirsttemp(l : longint); begin { this is a negative value normally } if l < 0 then Begin if odd(l) then Dec(l); end else Begin if odd(l) then Inc(l); end; firsttemp:=l; lasttemp:=l; end; function newtempofsize(size : longint) : longint; var tl : ptemprecord; begin { Just extend the temp, everything below has been use already } dec(lasttemp,size); { now we can create the templist entry } new(tl); tl^.temptype:=tt_normal; tl^.pos:=lasttemp; tl^.size:=size; tl^.next:=templist; tl^.nextfree:=nil; templist:=tl; newtempofsize:=tl^.pos; end; const lasttempofsize : ptemprecord = nil; function gettempofsize(size : longint) : longint; var tl, bestslot,bestprev, hprev,hp : ptemprecord; bestsize,ofs : longint; begin bestprev:=nil; bestslot:=nil; tl:=nil; bestsize:=0; { Align needed size on 4 bytes } if (size mod 4)<>0 then size:=size+(4-(size mod 4)); { First check the tmpfreelist } if assigned(tempfreelist) then begin { Check for a slot with the same size first } hprev:=nil; hp:=tempfreelist; while assigned(hp) do begin {$ifdef EXTDEBUG} if hp^.temptype<>tt_free then Comment(V_Warning,'Temp in freelist is not set to tt_free'); {$endif} if hp^.size>=size then begin { Slot is the same size, then leave immediatly } if hp^.size=size then begin bestprev:=hprev; bestslot:=hp; bestsize:=size; break; end else begin if (bestsize=0) or (hp^.size 0 (PM) } istemp:=((ref.base=procinfo^.framepointer) and {$ifdef i386} (ref.index=R_NO) and {$endif} (ref.offsetallowtype then begin exit; end; exprasmList.concat(Taitempalloc.dealloc(hp^.pos,hp^.size)); { set this block to free } hp^.temptype:=tt_free; { Update tempfreelist } if assigned(hprevfree) then begin { Connect with previous? } if assigned(hprev) and (hprev^.temptype=tt_free) then begin inc(hprev^.size,hp^.size); hprev^.next:=hp^.next; dispose(hp); hp:=hprev; end else hprevfree^.nextfree:=hp; end else begin hp^.nextfree:=tempfreelist; tempfreelist:=hp; end; { Next block free ? Yes, then concat } hnext:=hp^.next; if assigned(hnext) and (hnext^.temptype=tt_free) then begin inc(hp^.size,hnext^.size); hp^.nextfree:=hnext^.nextfree; hp^.next:=hnext^.next; dispose(hnext); end; exit; end; if (hp^.temptype=tt_free) then hprevfree:=hp; hprev:=hp; hp:=hp^.next; end; ungettemp:=tt_none; end; function getsizeoftemp(const ref: treference): longint; var hp : ptemprecord; begin hp:=templist; while assigned(hp) do begin if (hp^.pos=ref.offset) then begin getsizeoftemp := hp^.size; exit; end; hp := hp^.next; end; getsizeoftemp := -1; end; procedure ungetpersistanttemp(pos : longint); begin {$ifdef EXTDEBUG} if ungettemp(pos,tt_persistant)<>tt_persistant then Comment(V_Warning,'temp managment problem : ungetpersistanttemp()'+ ' at pos '+tostr(pos)+ ' not found !'); {$else} ungettemp(pos,tt_persistant); {$endif} end; procedure ungetpersistanttempreference(const ref : treference); begin ungetpersistanttemp(ref.offset); end; procedure ungetiftemp(const ref : treference); {$ifdef EXTDEBUG} var tt : ttemptype; {$endif} begin if istemp(ref) then begin { first check if ansistring } if ungetiftempansi(ref) then exit; {$ifndef EXTDEBUG} ungettemp(ref.offset,tt_normal); {$else} tt:=ungettemp(ref.offset,tt_normal); if tt=tt_persistant then Comment(V_Debug,'temp at pos '+tostr(ref.offset)+ ' not released because persistant!'); if tt=tt_none then Comment(V_Warning,'temp not found for release at offset '+tostr(ref.offset)); {$endif} end; end; procedure inittemps; begin tempfreelist:=nil; templist:=nil; end; begin InitTemps; end. { $Log$ Revision 1.11 2001-01-05 17:36:58 florian * the info about exception frames is stored now on the stack instead on the heap Revision 1.10 2000/12/31 11:04:43 jonas + sizeoftemp() function Revision 1.9 2000/12/25 00:07:30 peter + new tlinkedlist class (merge of old tstringqueue,tcontainer and tlinkedlist objects) Revision 1.8 2000/11/30 22:16:50 florian * moved to i386 Revision 1.7 2000/11/29 00:30:42 florian * unused units removed from uses clause * some changes for widestrings Revision 1.6 2000/11/04 14:25:22 florian + merged Attila's changes for interfaces, not tested yet Revision 1.5 2000/09/30 16:08:45 peter * more cg11 updates Revision 1.4 2000/09/24 15:06:31 peter * use defines.inc Revision 1.3 2000/08/27 16:11:55 peter * moved some util functions from globals,cobjects to cutils * splitted files into finput,fmodule Revision 1.2 2000/07/13 11:32:52 michael + removed logs }