cga.pas 116 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. Helper routines for the i386 code generator
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit cga;
  19. {$i defines.inc}
  20. interface
  21. uses
  22. cpubase,cpuasm,
  23. symconst,symtype,symdef,aasm;
  24. {$define TESTGETTEMP to store const that
  25. are written into temps for later release PM }
  26. function def_opsize(p1:tdef):topsize;
  27. function def2def_opsize(p1,p2:tdef):topsize;
  28. function def_getreg(p1:tdef):tregister;
  29. function makereg8(r:tregister):tregister;
  30. function makereg16(r:tregister):tregister;
  31. function makereg32(r:tregister):tregister;
  32. procedure locflags2reg(var l:tlocation;opsize:topsize);
  33. procedure locjump2reg(var l:tlocation;opsize:topsize; otl, ofl: tasmlabel);
  34. procedure emitlab(var l : tasmlabel);
  35. procedure emitjmp(c : tasmcond;var l : tasmlabel);
  36. procedure emit_flag2reg(flag:tresflags;hregister:tregister);
  37. procedure emit_none(i : tasmop;s : topsize);
  38. procedure emit_const(i : tasmop;s : topsize;c : longint);
  39. procedure emit_reg(i : tasmop;s : topsize;reg : tregister);
  40. procedure emit_ref(i : tasmop;s : topsize;ref : preference);
  41. procedure emit_const_reg(i : tasmop;s : topsize;c : longint;reg : tregister);
  42. procedure emit_const_ref(i : tasmop;s : topsize;c : longint;ref : preference);
  43. procedure emit_ref_reg(i : tasmop;s : topsize;ref : preference;reg : tregister);
  44. procedure emit_reg_ref(i : tasmop;s : topsize;reg : tregister;ref : preference);
  45. procedure emit_reg_reg(i : tasmop;s : topsize;reg1,reg2 : tregister);
  46. procedure emit_const_reg_reg(i : tasmop;s : topsize;c : longint;reg1,reg2 : tregister);
  47. procedure emit_reg_reg_reg(i : tasmop;s : topsize;reg1,reg2,reg3 : tregister);
  48. procedure emit_sym(i : tasmop;s : topsize;op : tasmsymbol);
  49. procedure emit_sym_ofs(i : tasmop;s : topsize;op : tasmsymbol;ofs : longint);
  50. procedure emit_sym_ofs_reg(i : tasmop;s : topsize;op : tasmsymbol;ofs:longint;reg : tregister);
  51. procedure emit_sym_ofs_ref(i : tasmop;s : topsize;op : tasmsymbol;ofs:longint;ref : preference);
  52. procedure emitcall(const routine:string);
  53. procedure emit_mov_loc_ref(const t:tlocation;const ref:treference;siz:topsize;freetemp:boolean);
  54. procedure emit_mov_loc_reg(const t:tlocation;reg:tregister);
  55. procedure emit_mov_ref_reg64(r : treference;rl,rh : tregister);
  56. procedure emit_lea_loc_ref(const t:tlocation;const ref:treference;freetemp:boolean);
  57. procedure emit_lea_loc_reg(const t:tlocation;reg:tregister;freetemp:boolean);
  58. procedure emit_push_loc(const t:tlocation);
  59. procedure emit_push_mem_size(const t: treference; size: longint);
  60. { pushes qword location to the stack }
  61. procedure emit_pushq_loc(const t : tlocation);
  62. procedure release_qword_loc(const t : tlocation);
  63. { remove non regvar registers in loc from regs (in the format }
  64. { pushusedregisters uses) }
  65. procedure remove_non_regvars_from_loc(const t: tlocation; var regs: byte);
  66. { releases the registers of a location }
  67. procedure release_loc(const t : tlocation);
  68. procedure emit_pushw_loc(const t:tlocation);
  69. procedure emit_push_lea_loc(const t:tlocation;freetemp:boolean);
  70. procedure emit_to_mem(var t:tlocation;def:tdef);
  71. procedure emit_to_reg16(var hr:tregister);
  72. procedure emit_to_reg32(var hr:tregister);
  73. procedure emit_mov_reg_loc(reg: TRegister; const t:tlocation);
  74. procedure emit_movq_reg_loc(reghigh,reglow: TRegister;t:tlocation);
  75. procedure copyshortstring(const dref,sref : treference;len : byte;
  76. loadref, del_sref: boolean);
  77. procedure finalize(t : tdef;const ref : treference;is_already_ref : boolean);
  78. procedure incrstringref(t : tdef;const ref : treference);
  79. procedure decrstringref(t : tdef;const ref : treference);
  80. procedure push_int(l : longint);
  81. procedure emit_push_mem(const ref : treference);
  82. procedure emitpushreferenceaddr(const ref : treference);
  83. procedure incrcomintfref(t: tdef; const ref: treference);
  84. procedure decrcomintfref(t: tdef; const ref: treference);
  85. procedure floatload(t : tfloattype;const ref : treference);
  86. procedure floatstore(t : tfloattype;const ref : treference);
  87. procedure floatloadops(t : tfloattype;var op : tasmop;var s : topsize);
  88. procedure floatstoreops(t : tfloattype;var op : tasmop;var s : topsize);
  89. procedure maybe_loadself;
  90. procedure emitloadord2reg(const location:Tlocation;orddef:torddef;destreg:Tregister;delloc:boolean);
  91. procedure concatcopy(source,dest : treference;size : longint;delsource : boolean;loadref:boolean);
  92. procedure genentrycode(alist : TAAsmoutput;make_global:boolean;
  93. stackframe:longint;
  94. var parasize:longint;var nostackframe:boolean;
  95. inlined : boolean);
  96. procedure genexitcode(alist : TAAsmoutput;parasize:longint;
  97. nostackframe,inlined:boolean);
  98. { if a unit doesn't have a explicit init/final code, }
  99. { we've to generate one, if the units has ansistrings }
  100. { in the interface or implementation }
  101. procedure genimplicitunitfinal(alist : TAAsmoutput);
  102. procedure genimplicitunitinit(alist : TAAsmoutput);
  103. {$ifdef test_dest_loc}
  104. const
  105. { used to avoid temporary assignments }
  106. dest_loc_known : boolean = false;
  107. in_dest_loc : boolean = false;
  108. dest_loc_tree : ptree = nil;
  109. var
  110. dest_loc : tlocation;
  111. procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister);
  112. {$endif test_dest_loc}
  113. implementation
  114. uses
  115. {$ifdef delphi}
  116. sysutils,
  117. {$else}
  118. strings,
  119. {$endif}
  120. cutils,cclasses,
  121. globtype,systems,globals,verbose,
  122. fmodule,
  123. symbase,symsym,symtable,types,
  124. tainst,tgcpu,temp_gen,cgbase,regvars
  125. {$ifdef GDB}
  126. ,gdb
  127. {$endif}
  128. ;
  129. {$ifndef NOTARGETWIN32}
  130. const
  131. winstackpagesize = 4096;
  132. {$endif}
  133. {*****************************************************************************
  134. Helpers
  135. *****************************************************************************}
  136. function def_opsize(p1:tdef):topsize;
  137. begin
  138. case p1.size of
  139. 1 : def_opsize:=S_B;
  140. 2 : def_opsize:=S_W;
  141. 4 : def_opsize:=S_L;
  142. { I don't know if we need it (FK) }
  143. 8 : def_opsize:=S_L;
  144. else
  145. internalerror(130820001);
  146. end;
  147. end;
  148. function def2def_opsize(p1,p2:tdef):topsize;
  149. var
  150. o1 : topsize;
  151. begin
  152. case p1.size of
  153. 1 : o1:=S_B;
  154. 2 : o1:=S_W;
  155. 4 : o1:=S_L;
  156. { I don't know if we need it (FK) }
  157. 8 : o1:=S_L;
  158. else
  159. internalerror(130820002);
  160. end;
  161. if assigned(p2) then
  162. begin
  163. case p2.size of
  164. 1 : o1:=S_B;
  165. 2 : begin
  166. if o1=S_B then
  167. o1:=S_BW
  168. else
  169. o1:=S_W;
  170. end;
  171. 4,8:
  172. begin
  173. case o1 of
  174. S_B : o1:=S_BL;
  175. S_W : o1:=S_WL;
  176. end;
  177. end;
  178. end;
  179. end;
  180. def2def_opsize:=o1;
  181. end;
  182. function def_getreg(p1:tdef):tregister;
  183. begin
  184. case p1.size of
  185. 1 : def_getreg:=reg32toreg8(getregisterint);
  186. 2 : def_getreg:=reg32toreg16(getregisterint);
  187. 4 : def_getreg:=getregisterint;
  188. else
  189. internalerror(130820003);
  190. end;
  191. end;
  192. function makereg8(r:tregister):tregister;
  193. begin
  194. case r of
  195. R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
  196. makereg8:=reg32toreg8(r);
  197. R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
  198. makereg8:=reg16toreg8(r);
  199. R_AL,R_BL,R_CL,R_DL :
  200. makereg8:=r;
  201. end;
  202. end;
  203. function makereg16(r:tregister):tregister;
  204. begin
  205. case r of
  206. R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
  207. makereg16:=reg32toreg16(r);
  208. R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
  209. makereg16:=r;
  210. R_AL,R_BL,R_CL,R_DL :
  211. makereg16:=reg8toreg16(r);
  212. end;
  213. end;
  214. function makereg32(r:tregister):tregister;
  215. begin
  216. case r of
  217. R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
  218. makereg32:=r;
  219. R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
  220. makereg32:=reg16toreg32(r);
  221. R_AL,R_BL,R_CL,R_DL :
  222. makereg32:=reg8toreg32(r);
  223. end;
  224. end;
  225. procedure locflags2reg(var l:tlocation;opsize:topsize);
  226. var
  227. hregister : tregister;
  228. begin
  229. if (l.loc=LOC_FLAGS) then
  230. begin
  231. hregister:=getregisterint;
  232. case opsize of
  233. S_W : hregister:=reg32toreg16(hregister);
  234. S_B : hregister:=reg32toreg8(hregister);
  235. end;
  236. emit_flag2reg(l.resflags,hregister);
  237. l.loc:=LOC_REGISTER;
  238. l.register:=hregister;
  239. end
  240. else internalerror(270720001);
  241. end;
  242. procedure locjump2reg(var l:tlocation;opsize:topsize; otl, ofl: tasmlabel);
  243. var
  244. hregister : tregister;
  245. hl : tasmlabel;
  246. begin
  247. if l.loc = LOC_JUMP then
  248. begin
  249. hregister:=getregisterint;
  250. case opsize of
  251. S_W : hregister:=reg32toreg16(hregister);
  252. S_B : hregister:=reg32toreg8(hregister);
  253. end;
  254. l.loc:=LOC_REGISTER;
  255. l.register:=hregister;
  256. emitlab(truelabel);
  257. truelabel:=otl;
  258. emit_const_reg(A_MOV,opsize,1,hregister);
  259. getlabel(hl);
  260. emitjmp(C_None,hl);
  261. emitlab(falselabel);
  262. falselabel:=ofl;
  263. emit_reg_reg(A_XOR,S_L,makereg32(hregister),
  264. makereg32(hregister));
  265. emitlab(hl);
  266. end
  267. else internalerror(270720002);
  268. end;
  269. {*****************************************************************************
  270. Emit Assembler
  271. *****************************************************************************}
  272. procedure emitlab(var l : tasmlabel);
  273. begin
  274. if not l.is_set then
  275. exprasmList.concat(Tai_label.Create(l))
  276. else
  277. internalerror(7453984);
  278. end;
  279. procedure emitjmp(c : tasmcond;var l : tasmlabel);
  280. var
  281. ai : taicpu;
  282. begin
  283. if c=C_None then
  284. ai := Taicpu.Op_sym(A_JMP,S_NO,l)
  285. else
  286. begin
  287. ai:=Taicpu.Op_sym(A_Jcc,S_NO,l);
  288. ai.SetCondition(c);
  289. end;
  290. ai.is_jmp:=true;
  291. exprasmList.concat(ai);
  292. end;
  293. procedure emit_flag2reg(flag:tresflags;hregister:tregister);
  294. var
  295. ai : taicpu;
  296. hreg : tregister;
  297. begin
  298. hreg:=makereg8(hregister);
  299. ai:=Taicpu.Op_reg(A_Setcc,S_B,hreg);
  300. ai.SetCondition(flags_to_cond(flag));
  301. exprasmList.concat(ai);
  302. if hreg<>hregister then
  303. begin
  304. if hregister in regset16bit then
  305. emit_to_reg16(hreg)
  306. else
  307. emit_to_reg32(hreg);
  308. end;
  309. end;
  310. procedure emit_none(i : tasmop;s : topsize);
  311. begin
  312. exprasmList.concat(Taicpu.Op_none(i,s));
  313. end;
  314. procedure emit_reg(i : tasmop;s : topsize;reg : tregister);
  315. begin
  316. exprasmList.concat(Taicpu.Op_reg(i,s,reg));
  317. end;
  318. procedure emit_ref(i : tasmop;s : topsize;ref : preference);
  319. begin
  320. exprasmList.concat(Taicpu.Op_ref(i,s,ref));
  321. end;
  322. procedure emit_const(i : tasmop;s : topsize;c : longint);
  323. begin
  324. exprasmList.concat(Taicpu.Op_const(i,s,c));
  325. end;
  326. procedure emit_const_reg(i : tasmop;s : topsize;c : longint;reg : tregister);
  327. begin
  328. exprasmList.concat(Taicpu.Op_const_reg(i,s,c,reg));
  329. end;
  330. procedure emit_const_ref(i : tasmop;s : topsize;c : longint;ref : preference);
  331. begin
  332. exprasmList.concat(Taicpu.Op_const_ref(i,s,c,ref));
  333. end;
  334. procedure emit_ref_reg(i : tasmop;s : topsize;ref : preference;reg : tregister);
  335. begin
  336. exprasmList.concat(Taicpu.Op_ref_reg(i,s,ref,reg));
  337. end;
  338. procedure emit_reg_ref(i : tasmop;s : topsize;reg : tregister;ref : preference);
  339. begin
  340. exprasmList.concat(Taicpu.Op_reg_ref(i,s,reg,ref));
  341. end;
  342. procedure emit_reg_reg(i : tasmop;s : topsize;reg1,reg2 : tregister);
  343. begin
  344. if (reg1<>reg2) or (i<>A_MOV) then
  345. exprasmList.concat(Taicpu.Op_reg_reg(i,s,reg1,reg2));
  346. end;
  347. procedure emit_const_reg_reg(i : tasmop;s : topsize;c : longint;reg1,reg2 : tregister);
  348. begin
  349. exprasmList.concat(Taicpu.Op_const_reg_reg(i,s,c,reg1,reg2));
  350. end;
  351. procedure emit_reg_reg_reg(i : tasmop;s : topsize;reg1,reg2,reg3 : tregister);
  352. begin
  353. exprasmList.concat(Taicpu.Op_reg_reg_reg(i,s,reg1,reg2,reg3));
  354. end;
  355. procedure emit_sym(i : tasmop;s : topsize;op : tasmsymbol);
  356. begin
  357. exprasmList.concat(Taicpu.Op_sym(i,s,op));
  358. end;
  359. procedure emit_sym_ofs(i : tasmop;s : topsize;op : tasmsymbol;ofs : longint);
  360. begin
  361. exprasmList.concat(Taicpu.Op_sym_ofs(i,s,op,ofs));
  362. end;
  363. procedure emit_sym_ofs_reg(i : tasmop;s : topsize;op : tasmsymbol;ofs:longint;reg : tregister);
  364. begin
  365. exprasmList.concat(Taicpu.Op_sym_ofs_reg(i,s,op,ofs,reg));
  366. end;
  367. procedure emit_sym_ofs_ref(i : tasmop;s : topsize;op : tasmsymbol;ofs:longint;ref : preference);
  368. begin
  369. exprasmList.concat(Taicpu.Op_sym_ofs_ref(i,s,op,ofs,ref));
  370. end;
  371. procedure emitcall(const routine:string);
  372. begin
  373. exprasmList.concat(Taicpu.Op_sym(A_CALL,S_NO,newasmsymbol(routine)));
  374. end;
  375. { only usefull in startup code }
  376. procedure emitinsertcall(const routine:string);
  377. begin
  378. exprasmList.insert(Taicpu.Op_sym(A_CALL,S_NO,newasmsymbol(routine)));
  379. end;
  380. procedure emit_mov_loc_ref(const t:tlocation;const ref:treference;siz:topsize;freetemp:boolean);
  381. var
  382. hreg : tregister;
  383. pushedeax : boolean;
  384. begin
  385. pushedeax:=false;
  386. case t.loc of
  387. LOC_REGISTER,
  388. LOC_CREGISTER : begin
  389. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,siz,
  390. t.register,newreference(ref)));
  391. ungetregister32(t.register); { the register is not needed anymore }
  392. end;
  393. LOC_MEM,
  394. LOC_REFERENCE : begin
  395. if t.reference.is_immediate then
  396. emit_const_ref(A_MOV,siz,
  397. t.reference.offset,newreference(ref))
  398. else
  399. begin
  400. case siz of
  401. S_B : begin
  402. { we can't do a getregister in the code generator }
  403. { without problems!!! }
  404. if usablereg32>0 then
  405. hreg:=reg32toreg8(getregisterint)
  406. else
  407. begin
  408. emit_reg(A_PUSH,S_L,R_EAX);
  409. pushedeax:=true;
  410. hreg:=R_AL;
  411. end;
  412. end;
  413. S_W : hreg:=R_DI;
  414. S_L : hreg:=R_EDI;
  415. end;
  416. if hreg in [R_DI,R_EDI] then
  417. getexplicitregister32(R_EDI);
  418. emit_ref_reg(A_MOV,siz,
  419. newreference(t.reference),hreg);
  420. del_reference(t.reference);
  421. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,siz,
  422. hreg,newreference(ref)));
  423. if siz=S_B then
  424. begin
  425. if pushedeax then
  426. emit_reg(A_POP,S_L,R_EAX)
  427. else
  428. ungetregister(hreg);
  429. end;
  430. if hreg in [R_DI,R_EDI] then
  431. ungetregister32(R_EDI);
  432. { we can release the registers }
  433. { but only AFTER the MOV! Important for the optimizer!
  434. (JM)}
  435. del_reference(ref);
  436. end;
  437. if freetemp then
  438. ungetiftemp(t.reference);
  439. end;
  440. else
  441. internalerror(330);
  442. end;
  443. end;
  444. procedure emit_mov_loc_reg(const t:tlocation;reg:tregister);
  445. begin
  446. case t.loc of
  447. LOC_REGISTER,
  448. LOC_CREGISTER : begin
  449. emit_reg_reg(A_MOV,S_L,t.register,reg);
  450. ungetregister32(t.register); { the register is not needed anymore }
  451. end;
  452. LOC_MEM,
  453. LOC_REFERENCE : begin
  454. if t.reference.is_immediate then
  455. emit_const_reg(A_MOV,S_L,
  456. t.reference.offset,reg)
  457. else
  458. begin
  459. emit_ref_reg(A_MOV,S_L,
  460. newreference(t.reference),reg);
  461. end;
  462. end;
  463. else
  464. internalerror(330);
  465. end;
  466. end;
  467. procedure emit_mov_reg_loc(reg: TRegister; const t:tlocation);
  468. begin
  469. case t.loc of
  470. LOC_REGISTER,
  471. LOC_CREGISTER : begin
  472. emit_reg_reg(A_MOV,RegSize(Reg),
  473. reg,t.register);
  474. end;
  475. LOC_MEM,
  476. LOC_REFERENCE : begin
  477. if t.reference.is_immediate then
  478. internalerror(334)
  479. else
  480. begin
  481. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,RegSize(Reg),
  482. Reg,newreference(t.reference)));
  483. end;
  484. end;
  485. else
  486. internalerror(330);
  487. end;
  488. end;
  489. procedure emit_lea_loc_reg(const t:tlocation;reg:tregister;freetemp:boolean);
  490. begin
  491. case t.loc of
  492. LOC_MEM,
  493. LOC_REFERENCE : begin
  494. if t.reference.is_immediate then
  495. internalerror(331)
  496. else
  497. begin
  498. emit_ref_reg(A_LEA,S_L,
  499. newreference(t.reference),reg);
  500. end;
  501. if freetemp then
  502. ungetiftemp(t.reference);
  503. end;
  504. else
  505. internalerror(332);
  506. end;
  507. end;
  508. procedure emit_movq_reg_loc(reghigh,reglow: TRegister;t:tlocation);
  509. begin
  510. case t.loc of
  511. LOC_REGISTER,
  512. LOC_CREGISTER : begin
  513. emit_reg_reg(A_MOV,S_L,
  514. reglow,t.registerlow);
  515. emit_reg_reg(A_MOV,S_L,
  516. reghigh,t.registerhigh);
  517. end;
  518. LOC_MEM,
  519. LOC_REFERENCE : begin
  520. if t.reference.is_immediate then
  521. internalerror(334)
  522. else
  523. begin
  524. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,
  525. Reglow,newreference(t.reference)));
  526. inc(t.reference.offset,4);
  527. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,
  528. Reghigh,newreference(t.reference)));
  529. end;
  530. end;
  531. else
  532. internalerror(330);
  533. end;
  534. end;
  535. procedure emit_pushq_loc(const t : tlocation);
  536. var
  537. hr : preference;
  538. begin
  539. case t.loc of
  540. LOC_REGISTER,
  541. LOC_CREGISTER:
  542. begin
  543. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,
  544. t.registerhigh));
  545. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,
  546. t.registerlow));
  547. end;
  548. LOC_MEM,
  549. LOC_REFERENCE:
  550. begin
  551. hr:=newreference(t.reference);
  552. inc(hr^.offset,4);
  553. exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_L,
  554. hr));
  555. exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_L,
  556. newreference(t.reference)));
  557. ungetiftemp(t.reference);
  558. end;
  559. else internalerror(331);
  560. end;
  561. end;
  562. procedure remove_non_regvars_from_loc(const t: tlocation; var regs: byte);
  563. begin
  564. case t.loc of
  565. LOC_REGISTER:
  566. begin
  567. { can't be a regvar, since it would be LOC_CREGISTER then }
  568. regs := regs and not($80 shr byte(t.register));
  569. if t.registerhigh <> R_NO then
  570. regs := regs and not($80 shr byte(t.registerhigh));
  571. end;
  572. LOC_MEM,LOC_REFERENCE:
  573. begin
  574. if not(cs_regalloc in aktglobalswitches) or
  575. (t.reference.base in usableregs) then
  576. regs := regs and
  577. not($80 shr byte(t.reference.base));
  578. if not(cs_regalloc in aktglobalswitches) or
  579. (t.reference.index in usableregs) then
  580. regs := regs and
  581. not($80 shr byte(t.reference.index));
  582. end;
  583. end;
  584. end;
  585. procedure release_loc(const t : tlocation);
  586. begin
  587. case t.loc of
  588. LOC_REGISTER,
  589. LOC_CREGISTER:
  590. begin
  591. ungetregister32(t.register);
  592. end;
  593. LOC_MEM,
  594. LOC_REFERENCE:
  595. del_reference(t.reference);
  596. else internalerror(332);
  597. end;
  598. end;
  599. procedure release_qword_loc(const t : tlocation);
  600. begin
  601. case t.loc of
  602. LOC_REGISTER,
  603. LOC_CREGISTER:
  604. begin
  605. ungetregister32(t.registerhigh);
  606. ungetregister32(t.registerlow);
  607. end;
  608. LOC_MEM,
  609. LOC_REFERENCE:
  610. del_reference(t.reference);
  611. else internalerror(331);
  612. end;
  613. end;
  614. procedure emit_push_loc(const t:tlocation);
  615. begin
  616. case t.loc of
  617. LOC_REGISTER,
  618. LOC_CREGISTER : begin
  619. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,makereg32(t.register)));
  620. ungetregister(t.register); { the register is not needed anymore }
  621. end;
  622. LOC_MEM,
  623. LOC_REFERENCE : begin
  624. if t.reference.is_immediate then
  625. exprasmList.concat(Taicpu.Op_const(A_PUSH,S_L,t.reference.offset))
  626. else
  627. exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_L,newreference(t.reference)));
  628. del_reference(t.reference);
  629. ungetiftemp(t.reference);
  630. end;
  631. else
  632. internalerror(330);
  633. end;
  634. end;
  635. procedure emit_pushw_loc(const t:tlocation);
  636. var
  637. opsize : topsize;
  638. begin
  639. case t.loc of
  640. LOC_REGISTER,
  641. LOC_CREGISTER : begin
  642. if aktalignment.paraalign=4 then
  643. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,makereg32(t.register)))
  644. else
  645. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_W,makereg16(t.register)));
  646. ungetregister(t.register); { the register is not needed anymore }
  647. end;
  648. LOC_MEM,
  649. LOC_REFERENCE : begin
  650. if aktalignment.paraalign=4 then
  651. opsize:=S_L
  652. else
  653. opsize:=S_W;
  654. if t.reference.is_immediate then
  655. exprasmList.concat(Taicpu.Op_const(A_PUSH,opsize,t.reference.offset))
  656. else
  657. exprasmList.concat(Taicpu.Op_ref(A_PUSH,opsize,newreference(t.reference)));
  658. del_reference(t.reference);
  659. ungetiftemp(t.reference);
  660. end;
  661. else
  662. internalerror(330);
  663. end;
  664. end;
  665. procedure emit_lea_loc_ref(const t:tlocation;const ref:treference;freetemp:boolean);
  666. begin
  667. case t.loc of
  668. LOC_MEM,
  669. LOC_REFERENCE : begin
  670. if t.reference.is_immediate then
  671. internalerror(331)
  672. else
  673. begin
  674. getexplicitregister32(R_EDI);
  675. emit_ref_reg(A_LEA,S_L,
  676. newreference(t.reference),R_EDI);
  677. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,
  678. R_EDI,newreference(ref)));
  679. ungetregister32(R_EDI);
  680. end;
  681. { release the registers }
  682. del_reference(t.reference);
  683. if freetemp then
  684. ungetiftemp(t.reference);
  685. end;
  686. else
  687. internalerror(332);
  688. end;
  689. end;
  690. procedure emit_push_lea_loc(const t:tlocation;freetemp:boolean);
  691. begin
  692. case t.loc of
  693. LOC_MEM,
  694. LOC_REFERENCE : begin
  695. if t.reference.is_immediate then
  696. internalerror(331)
  697. else
  698. begin
  699. getexplicitregister32(R_EDI);
  700. emit_ref_reg(A_LEA,S_L,
  701. newreference(t.reference),R_EDI);
  702. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
  703. ungetregister32(R_EDI);
  704. end;
  705. if freetemp then
  706. ungetiftemp(t.reference);
  707. end;
  708. else
  709. internalerror(332);
  710. end;
  711. end;
  712. procedure emit_push_mem_size(const t: treference; size: longint);
  713. var
  714. s: topsize;
  715. begin
  716. if t.is_immediate then
  717. begin
  718. if (size=4) or
  719. (aktalignment.paraalign=4) then
  720. exprasmList.concat(Taicpu.Op_const(A_PUSH,S_L,t.offset))
  721. else
  722. exprasmList.concat(Taicpu.Op_const(A_PUSH,S_W,t.offset));
  723. end
  724. else
  725. if size < 4 then
  726. begin
  727. getexplicitregister32(R_EDI);
  728. case size of
  729. 1: s := S_BL;
  730. 2: s := S_WL;
  731. else internalerror(200008071);
  732. end;
  733. exprasmList.concat(Taicpu.Op_ref_reg(A_MOVZX,s,
  734. newreference(t),R_EDI));
  735. if aktalignment.paraalign=4 then
  736. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI))
  737. else
  738. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_W,R_DI));
  739. ungetregister32(R_EDI);
  740. end
  741. else
  742. if size = 4 then
  743. emit_push_mem(t)
  744. else
  745. internalerror(200008072);
  746. end;
  747. procedure emit_to_mem(var t:tlocation;def:tdef);
  748. var
  749. r : treference;
  750. begin
  751. case t.loc of
  752. LOC_FPU : begin
  753. reset_reference(t.reference);
  754. gettempofsizereference(10,t.reference);
  755. floatstore(tfloatdef(def).typ,t.reference);
  756. end;
  757. LOC_REGISTER:
  758. begin
  759. if is_64bitint(def) then
  760. begin
  761. gettempofsizereference(8,r);
  762. emit_reg_ref(A_MOV,S_L,t.registerlow,newreference(r));
  763. inc(r.offset,4);
  764. emit_reg_ref(A_MOV,S_L,t.registerhigh,newreference(r));
  765. dec(r.offset,4);
  766. t.reference:=r;
  767. end
  768. else
  769. internalerror(1405001);
  770. end;
  771. LOC_MEM,
  772. LOC_REFERENCE : ;
  773. LOC_CFPUREGISTER : begin
  774. emit_reg(A_FLD,S_NO,correct_fpuregister(t.register,fpuvaroffset));
  775. inc(fpuvaroffset);
  776. reset_reference(t.reference);
  777. gettempofsizereference(10,t.reference);
  778. floatstore(tfloatdef(def).typ,t.reference);
  779. end;
  780. else
  781. internalerror(333);
  782. end;
  783. t.loc:=LOC_MEM;
  784. end;
  785. procedure emit_to_reg16(var hr:tregister);
  786. begin
  787. { ranges are a little bit bug sensitive ! }
  788. case hr of
  789. R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP,R_EBP:
  790. begin
  791. hr:=reg32toreg16(hr);
  792. end;
  793. R_AL,R_BL,R_CL,R_DL:
  794. begin
  795. hr:=reg8toreg16(hr);
  796. emit_const_reg(A_AND,S_W,$ff,hr);
  797. end;
  798. R_AH,R_BH,R_CH,R_DH:
  799. begin
  800. hr:=reg8toreg16(hr);
  801. emit_const_reg(A_AND,S_W,$ff00,hr);
  802. end;
  803. end;
  804. end;
  805. procedure emit_to_reg32(var hr:tregister);
  806. begin
  807. { ranges are a little bit bug sensitive ! }
  808. case hr of
  809. R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP,R_BP:
  810. begin
  811. hr:=reg16toreg32(hr);
  812. emit_const_reg(A_AND,S_L,$ffff,hr);
  813. end;
  814. R_AL,R_BL,R_CL,R_DL:
  815. begin
  816. hr:=reg8toreg32(hr);
  817. emit_const_reg(A_AND,S_L,$ff,hr);
  818. end;
  819. R_AH,R_BH,R_CH,R_DH:
  820. begin
  821. hr:=reg8toreg32(hr);
  822. emit_const_reg(A_AND,S_L,$ff00,hr);
  823. end;
  824. end;
  825. end;
  826. procedure emit_mov_ref_reg64(r : treference;rl,rh : tregister);
  827. var
  828. hr : preference;
  829. begin
  830. { if we load a 64 bit reference, we must be careful because }
  831. { we could overwrite the registers of the reference by }
  832. { accident }
  833. getexplicitregister32(R_EDI);
  834. if r.base=rl then
  835. begin
  836. emit_reg_reg(A_MOV,S_L,r.base,
  837. R_EDI);
  838. r.base:=R_EDI;
  839. end
  840. else if r.index=rl then
  841. begin
  842. emit_reg_reg(A_MOV,S_L,r.index,
  843. R_EDI);
  844. r.index:=R_EDI;
  845. end;
  846. emit_ref_reg(A_MOV,S_L,
  847. newreference(r),rl);
  848. hr:=newreference(r);
  849. inc(hr^.offset,4);
  850. emit_ref_reg(A_MOV,S_L,
  851. hr,rh);
  852. ungetregister32(R_EDI);
  853. end;
  854. {*****************************************************************************
  855. Emit String Functions
  856. *****************************************************************************}
  857. procedure incrcomintfref(t: tdef; const ref: treference);
  858. var
  859. pushedregs : tpushed;
  860. begin
  861. pushusedregisters(pushedregs,$ff);
  862. emit_ref(A_PUSH,S_L,newreference(ref));
  863. saveregvars($ff);
  864. if is_interfacecom(t) then
  865. emitcall('FPC_INTF_INCR_REF')
  866. else
  867. internalerror(1859);
  868. popusedregisters(pushedregs);
  869. end;
  870. procedure decrcomintfref(t: tdef; const ref: treference);
  871. var
  872. pushedregs : tpushed;
  873. begin
  874. pushusedregisters(pushedregs,$ff);
  875. emitpushreferenceaddr(ref);
  876. saveregvars($ff);
  877. if is_interfacecom(t) then
  878. begin
  879. emitcall('FPC_INTF_DECR_REF');
  880. end
  881. else internalerror(1859);
  882. popusedregisters(pushedregs);
  883. end;
  884. procedure copyshortstring(const dref,sref : treference;len : byte;
  885. loadref, del_sref: boolean);
  886. begin
  887. emitpushreferenceaddr(dref);
  888. { if it's deleted right before it's used, the optimizer can move }
  889. { the reg deallocations to the right places (JM) }
  890. if del_sref then
  891. del_reference(sref);
  892. if loadref then
  893. emit_push_mem(sref)
  894. else
  895. emitpushreferenceaddr(sref);
  896. push_int(len);
  897. emitcall('FPC_SHORTSTR_COPY');
  898. maybe_loadself;
  899. end;
  900. {$ifdef unused}
  901. procedure copylongstring(const dref,sref : treference;len : longint;loadref:boolean);
  902. begin
  903. emitpushreferenceaddr(dref);
  904. if loadref then
  905. emit_push_mem(sref)
  906. else
  907. emitpushreferenceaddr(sref);
  908. push_int(len);
  909. saveregvars($ff);
  910. emitcall('FPC_LONGSTR_COPY');
  911. maybe_loadself;
  912. end;
  913. {$endif unused}
  914. procedure incrstringref(t : tdef;const ref : treference);
  915. var
  916. pushedregs : tpushed;
  917. begin
  918. pushusedregisters(pushedregs,$ff);
  919. emitpushreferenceaddr(ref);
  920. saveregvars($ff);
  921. if is_ansistring(t) then
  922. begin
  923. emitcall('FPC_ANSISTR_INCR_REF');
  924. end
  925. else if is_widestring(t) then
  926. begin
  927. emitcall('FPC_WIDESTR_INCR_REF');
  928. end
  929. else internalerror(1859);
  930. popusedregisters(pushedregs);
  931. end;
  932. procedure decrstringref(t : tdef;const ref : treference);
  933. var
  934. pushedregs : tpushed;
  935. begin
  936. pushusedregisters(pushedregs,$ff);
  937. emitpushreferenceaddr(ref);
  938. saveregvars($ff);
  939. if is_ansistring(t) then
  940. begin
  941. emitcall('FPC_ANSISTR_DECR_REF');
  942. end
  943. else if is_widestring(t) then
  944. begin
  945. emitcall('FPC_WIDESTR_DECR_REF');
  946. end
  947. else internalerror(1859);
  948. popusedregisters(pushedregs);
  949. end;
  950. {*****************************************************************************
  951. Emit Push Functions
  952. *****************************************************************************}
  953. procedure push_int(l : longint);
  954. begin
  955. if (l = 0) and
  956. not(aktoptprocessor in [Class386, ClassP6]) and
  957. not(cs_littlesize in aktglobalswitches)
  958. Then
  959. begin
  960. getexplicitregister32(R_EDI);
  961. emit_reg_reg(A_XOR,S_L,R_EDI,R_EDI);
  962. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
  963. ungetregister32(R_EDI);
  964. end
  965. else
  966. exprasmList.concat(Taicpu.Op_const(A_PUSH,S_L,l));
  967. end;
  968. procedure emit_push_mem(const ref : treference);
  969. begin
  970. if ref.is_immediate then
  971. push_int(ref.offset)
  972. else
  973. begin
  974. if not(aktoptprocessor in [Class386, ClassP6]) and
  975. not(cs_littlesize in aktglobalswitches)
  976. then
  977. begin
  978. getexplicitregister32(R_EDI);
  979. emit_ref_reg(A_MOV,S_L,newreference(ref),R_EDI);
  980. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
  981. ungetregister32(R_EDI);
  982. end
  983. else exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_L,newreference(ref)));
  984. end;
  985. end;
  986. procedure emitpushreferenceaddr(const ref : treference);
  987. var
  988. href : treference;
  989. begin
  990. { this will fail for references to other segments !!! }
  991. if ref.is_immediate then
  992. { is this right ? }
  993. begin
  994. { push_int(ref.offset)}
  995. gettempofsizereference(4,href);
  996. emit_const_ref(A_MOV,S_L,ref.offset,newreference(href));
  997. emitpushreferenceaddr(href);
  998. del_reference(href);
  999. end
  1000. else
  1001. begin
  1002. if ref.segment<>R_NO then
  1003. CGMessage(cg_e_cant_use_far_pointer_there);
  1004. if (ref.base=R_NO) and (ref.index=R_NO) then
  1005. exprasmList.concat(Taicpu.Op_sym_ofs(A_PUSH,S_L,ref.symbol,ref.offset))
  1006. else if (ref.base=R_NO) and (ref.index<>R_NO) and
  1007. (ref.offset=0) and (ref.scalefactor=0) and (ref.symbol=nil) then
  1008. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,ref.index))
  1009. else if (ref.base<>R_NO) and (ref.index=R_NO) and
  1010. (ref.offset=0) and (ref.symbol=nil) then
  1011. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,ref.base))
  1012. else
  1013. begin
  1014. getexplicitregister32(R_EDI);
  1015. emit_ref_reg(A_LEA,S_L,newreference(ref),R_EDI);
  1016. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
  1017. ungetregister32(R_EDI);
  1018. end;
  1019. end;
  1020. end;
  1021. {*****************************************************************************
  1022. Emit Float Functions
  1023. *****************************************************************************}
  1024. procedure floatloadops(t : tfloattype;var op : tasmop;var s : topsize);
  1025. begin
  1026. case t of
  1027. s32real : begin
  1028. op:=A_FLD;
  1029. s:=S_FS;
  1030. end;
  1031. s64real : begin
  1032. op:=A_FLD;
  1033. { ???? }
  1034. s:=S_FL;
  1035. end;
  1036. s80real : begin
  1037. op:=A_FLD;
  1038. s:=S_FX;
  1039. end;
  1040. s64comp : begin
  1041. op:=A_FILD;
  1042. s:=S_IQ;
  1043. end;
  1044. else internalerror(17);
  1045. end;
  1046. end;
  1047. procedure floatload(t : tfloattype;const ref : treference);
  1048. var
  1049. op : tasmop;
  1050. s : topsize;
  1051. begin
  1052. floatloadops(t,op,s);
  1053. exprasmList.concat(Taicpu.Op_ref(op,s,
  1054. newreference(ref)));
  1055. inc(fpuvaroffset);
  1056. end;
  1057. procedure floatstoreops(t : tfloattype;var op : tasmop;var s : topsize);
  1058. begin
  1059. case t of
  1060. s32real : begin
  1061. op:=A_FSTP;
  1062. s:=S_FS;
  1063. end;
  1064. s64real : begin
  1065. op:=A_FSTP;
  1066. s:=S_FL;
  1067. end;
  1068. s80real : begin
  1069. op:=A_FSTP;
  1070. s:=S_FX;
  1071. end;
  1072. s64comp : begin
  1073. op:=A_FISTP;
  1074. s:=S_IQ;
  1075. end;
  1076. else
  1077. internalerror(17);
  1078. end;
  1079. end;
  1080. procedure floatstore(t : tfloattype;const ref : treference);
  1081. var
  1082. op : tasmop;
  1083. s : topsize;
  1084. begin
  1085. floatstoreops(t,op,s);
  1086. exprasmList.concat(Taicpu.Op_ref(op,s,
  1087. newreference(ref)));
  1088. dec(fpuvaroffset);
  1089. end;
  1090. {*****************************************************************************
  1091. Emit Functions
  1092. *****************************************************************************}
  1093. procedure concatcopy(source,dest : treference;size : longint;delsource,loadref : boolean);
  1094. const
  1095. isizes : array[0..3] of topsize=(S_L,S_B,S_W,S_B);
  1096. ishr : array[0..3] of byte=(2,0,1,0);
  1097. var
  1098. ecxpushed : boolean;
  1099. oldsourceoffset,
  1100. helpsize : longint;
  1101. i : byte;
  1102. reg8,reg32 : tregister;
  1103. swap : boolean;
  1104. procedure maybepushecx;
  1105. begin
  1106. if not(R_ECX in unused) then
  1107. begin
  1108. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_ECX));
  1109. ecxpushed:=true;
  1110. end
  1111. else getexplicitregister32(R_ECX);
  1112. end;
  1113. begin
  1114. oldsourceoffset:=source.offset;
  1115. if (not loadref) and
  1116. ((size<=8) or
  1117. (not(cs_littlesize in aktglobalswitches ) and (size<=12))) then
  1118. begin
  1119. helpsize:=size shr 2;
  1120. getexplicitregister32(R_EDI);
  1121. for i:=1 to helpsize do
  1122. begin
  1123. emit_ref_reg(A_MOV,S_L,newreference(source),R_EDI);
  1124. If (size = 4) and delsource then
  1125. del_reference(source);
  1126. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,newreference(dest)));
  1127. inc(source.offset,4);
  1128. inc(dest.offset,4);
  1129. dec(size,4);
  1130. end;
  1131. if size>1 then
  1132. begin
  1133. emit_ref_reg(A_MOV,S_W,newreference(source),R_DI);
  1134. If (size = 2) and delsource then
  1135. del_reference(source);
  1136. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_W,R_DI,newreference(dest)));
  1137. inc(source.offset,2);
  1138. inc(dest.offset,2);
  1139. dec(size,2);
  1140. end;
  1141. ungetregister32(R_EDI);
  1142. if size>0 then
  1143. begin
  1144. { and now look for an 8 bit register }
  1145. swap:=false;
  1146. if R_EAX in unused then reg8:=reg32toreg8(getexplicitregister32(R_EAX))
  1147. else if R_EDX in unused then reg8:=reg32toreg8(getexplicitregister32(R_EDX))
  1148. else if R_EBX in unused then reg8:=reg32toreg8(getexplicitregister32(R_EBX))
  1149. else if R_ECX in unused then reg8:=reg32toreg8(getexplicitregister32(R_ECX))
  1150. else
  1151. begin
  1152. swap:=true;
  1153. { we need only to check 3 registers, because }
  1154. { one is always not index or base }
  1155. if (dest.base<>R_EAX) and (dest.index<>R_EAX) then
  1156. begin
  1157. reg8:=R_AL;
  1158. reg32:=R_EAX;
  1159. end
  1160. else if (dest.base<>R_EBX) and (dest.index<>R_EBX) then
  1161. begin
  1162. reg8:=R_BL;
  1163. reg32:=R_EBX;
  1164. end
  1165. else if (dest.base<>R_ECX) and (dest.index<>R_ECX) then
  1166. begin
  1167. reg8:=R_CL;
  1168. reg32:=R_ECX;
  1169. end;
  1170. end;
  1171. if swap then
  1172. { was earlier XCHG, of course nonsense }
  1173. begin
  1174. getexplicitregister32(R_EDI);
  1175. emit_reg_reg(A_MOV,S_L,reg32,R_EDI);
  1176. end;
  1177. emit_ref_reg(A_MOV,S_B,newreference(source),reg8);
  1178. If delsource then
  1179. del_reference(source);
  1180. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_B,reg8,newreference(dest)));
  1181. if swap then
  1182. begin
  1183. emit_reg_reg(A_MOV,S_L,R_EDI,reg32);
  1184. ungetregister32(R_EDI);
  1185. end
  1186. else
  1187. ungetregister(reg8);
  1188. end;
  1189. end
  1190. else
  1191. begin
  1192. getexplicitregister32(R_EDI);
  1193. emit_ref_reg(A_LEA,S_L,newreference(dest),R_EDI);
  1194. exprasmList.concat(Tairegalloc.Alloc(R_ESI));
  1195. if loadref then
  1196. emit_ref_reg(A_MOV,S_L,newreference(source),R_ESI)
  1197. else
  1198. begin
  1199. emit_ref_reg(A_LEA,S_L,newreference(source),R_ESI);
  1200. if delsource then
  1201. del_reference(source);
  1202. end;
  1203. exprasmList.concat(Taicpu.Op_none(A_CLD,S_NO));
  1204. ecxpushed:=false;
  1205. if cs_littlesize in aktglobalswitches then
  1206. begin
  1207. maybepushecx;
  1208. emit_const_reg(A_MOV,S_L,size,R_ECX);
  1209. exprasmList.concat(Taicpu.Op_none(A_REP,S_NO));
  1210. exprasmList.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  1211. end
  1212. else
  1213. begin
  1214. helpsize:=size shr 2;
  1215. size:=size and 3;
  1216. if helpsize>1 then
  1217. begin
  1218. maybepushecx;
  1219. emit_const_reg(A_MOV,S_L,helpsize,R_ECX);
  1220. exprasmList.concat(Taicpu.Op_none(A_REP,S_NO));
  1221. end;
  1222. if helpsize>0 then
  1223. exprasmList.concat(Taicpu.Op_none(A_MOVSD,S_NO));
  1224. if size>1 then
  1225. begin
  1226. dec(size,2);
  1227. exprasmList.concat(Taicpu.Op_none(A_MOVSW,S_NO));
  1228. end;
  1229. if size=1 then
  1230. exprasmList.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  1231. end;
  1232. ungetregister32(R_EDI);
  1233. exprasmList.concat(Tairegalloc.DeAlloc(R_ESI));
  1234. if ecxpushed then
  1235. exprasmList.concat(Taicpu.Op_reg(A_POP,S_L,R_ECX))
  1236. else
  1237. ungetregister32(R_ECX);
  1238. { loading SELF-reference again }
  1239. maybe_loadself;
  1240. end;
  1241. if delsource then
  1242. begin
  1243. source.offset:=oldsourceoffset;
  1244. ungetiftemp(source);
  1245. end;
  1246. end;
  1247. procedure emitloadord2reg(const location:Tlocation;orddef:torddef;
  1248. destreg:Tregister;delloc:boolean);
  1249. {A lot smaller and less bug sensitive than the original unfolded loads.}
  1250. var tai:Taicpu;
  1251. r:Preference;
  1252. begin
  1253. tai := nil;
  1254. case location.loc of
  1255. LOC_REGISTER,LOC_CREGISTER:
  1256. begin
  1257. case orddef.typ of
  1258. u8bit,uchar,bool8bit:
  1259. tai:=Taicpu.Op_reg_reg(A_MOVZX,S_BL,location.register,destreg);
  1260. s8bit:
  1261. tai:=Taicpu.Op_reg_reg(A_MOVSX,S_BL,location.register,destreg);
  1262. u16bit,uwidechar,bool16bit:
  1263. tai:=Taicpu.Op_reg_reg(A_MOVZX,S_WL,location.register,destreg);
  1264. s16bit:
  1265. tai:=Taicpu.Op_reg_reg(A_MOVSX,S_WL,location.register,destreg);
  1266. u32bit,bool32bit,s32bit:
  1267. if location.register <> destreg then
  1268. tai:=Taicpu.Op_reg_reg(A_MOV,S_L,location.register,destreg);
  1269. else
  1270. internalerror(330);
  1271. end;
  1272. if delloc then
  1273. ungetregister(location.register);
  1274. end;
  1275. LOC_MEM,
  1276. LOC_REFERENCE:
  1277. begin
  1278. if location.reference.is_immediate then
  1279. tai:=Taicpu.Op_const_reg(A_MOV,S_L,location.reference.offset,destreg)
  1280. else
  1281. begin
  1282. r:=newreference(location.reference);
  1283. case orddef.typ of
  1284. u8bit,uchar,bool8bit:
  1285. tai:=Taicpu.Op_ref_reg(A_MOVZX,S_BL,r,destreg);
  1286. s8bit:
  1287. tai:=Taicpu.Op_ref_reg(A_MOVSX,S_BL,r,destreg);
  1288. u16bit,uwidechar,bool16bit:
  1289. tai:=Taicpu.Op_ref_reg(A_MOVZX,S_WL,r,destreg);
  1290. s16bit:
  1291. tai:=Taicpu.Op_ref_reg(A_MOVSX,S_WL,r,destreg);
  1292. u32bit,bool32bit:
  1293. tai:=Taicpu.Op_ref_reg(A_MOV,S_L,r,destreg);
  1294. s32bit:
  1295. tai:=Taicpu.Op_ref_reg(A_MOV,S_L,r,destreg);
  1296. else
  1297. internalerror(330);
  1298. end;
  1299. end;
  1300. if delloc then
  1301. del_reference(location.reference);
  1302. end
  1303. else
  1304. internalerror(6);
  1305. end;
  1306. if assigned(tai) then
  1307. exprasmList.concat(tai);
  1308. end;
  1309. { if necessary ESI is reloaded after a call}
  1310. procedure maybe_loadself;
  1311. var
  1312. hp : preference;
  1313. p : pprocinfo;
  1314. i : longint;
  1315. begin
  1316. if assigned(procinfo^._class) then
  1317. begin
  1318. exprasmList.concat(Tairegalloc.Alloc(R_ESI));
  1319. if lexlevel>normal_function_level then
  1320. begin
  1321. new(hp);
  1322. reset_reference(hp^);
  1323. hp^.offset:=procinfo^.framepointer_offset;
  1324. hp^.base:=procinfo^.framepointer;
  1325. emit_ref_reg(A_MOV,S_L,hp,R_ESI);
  1326. p:=procinfo^.parent;
  1327. for i:=3 to lexlevel-1 do
  1328. begin
  1329. new(hp);
  1330. reset_reference(hp^);
  1331. hp^.offset:=p^.framepointer_offset;
  1332. hp^.base:=R_ESI;
  1333. emit_ref_reg(A_MOV,S_L,hp,R_ESI);
  1334. p:=p^.parent;
  1335. end;
  1336. new(hp);
  1337. reset_reference(hp^);
  1338. hp^.offset:=p^.selfpointer_offset;
  1339. hp^.base:=R_ESI;
  1340. emit_ref_reg(A_MOV,S_L,hp,R_ESI);
  1341. end
  1342. else
  1343. begin
  1344. new(hp);
  1345. reset_reference(hp^);
  1346. hp^.offset:=procinfo^.selfpointer_offset;
  1347. hp^.base:=procinfo^.framepointer;
  1348. emit_ref_reg(A_MOV,S_L,hp,R_ESI);
  1349. end;
  1350. end;
  1351. end;
  1352. {*****************************************************************************
  1353. Entry/Exit Code Functions
  1354. *****************************************************************************}
  1355. procedure genprofilecode;
  1356. var
  1357. pl : tasmlabel;
  1358. begin
  1359. if (po_assembler in aktprocdef.procoptions) then
  1360. exit;
  1361. case target_info.target of
  1362. target_i386_win32,
  1363. target_i386_freebsd,
  1364. target_i386_linux:
  1365. begin
  1366. getaddrlabel(pl);
  1367. emitinsertcall(target_info.Cprefix+'mcount');
  1368. usedinproc:=usedinproc or ($80 shr byte(R_EDX));
  1369. exprasmList.insert(Taicpu.Op_sym_ofs_reg(A_MOV,S_L,pl,0,R_EDX));
  1370. exprasmList.insert(Tai_section.Create(sec_code));
  1371. exprasmList.insert(Tai_const.Create_32bit(0));
  1372. exprasmList.insert(Tai_label.Create(pl));
  1373. exprasmList.insert(Tai_align.Create(4));
  1374. exprasmList.insert(Tai_section.Create(sec_data));
  1375. end;
  1376. target_i386_go32v2:
  1377. begin
  1378. emitinsertcall('MCOUNT');
  1379. end;
  1380. end;
  1381. end;
  1382. procedure generate_interrupt_stackframe_entry;
  1383. begin
  1384. { save the registers of an interrupt procedure }
  1385. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EAX));
  1386. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EBX));
  1387. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_ECX));
  1388. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EDX));
  1389. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_ESI));
  1390. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
  1391. { .... also the segment registers }
  1392. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_W,R_DS));
  1393. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_W,R_ES));
  1394. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_W,R_FS));
  1395. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_W,R_GS));
  1396. end;
  1397. procedure generate_interrupt_stackframe_exit;
  1398. begin
  1399. { restore the registers of an interrupt procedure }
  1400. { this was all with entrycode instead of exitcode !!}
  1401. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_EAX));
  1402. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_EBX));
  1403. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_ECX));
  1404. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_EDX));
  1405. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_ESI));
  1406. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_EDI));
  1407. { .... also the segment registers }
  1408. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_W,R_DS));
  1409. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_W,R_ES));
  1410. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_W,R_FS));
  1411. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_W,R_GS));
  1412. { this restores the flags }
  1413. procinfo^.aktexitcode.concat(Taicpu.Op_none(A_IRET,S_NO));
  1414. end;
  1415. { generates the code for threadvar initialisation }
  1416. procedure initialize_threadvar(p : tnamedindexitem);
  1417. var
  1418. hr : treference;
  1419. begin
  1420. if (tsym(p).typ=varsym) and
  1421. (vo_is_thread_var in tvarsym(p).varoptions) then
  1422. begin
  1423. exprasmList.concat(Taicpu.Op_const(A_PUSH,S_L,tvarsym(p).getsize));
  1424. reset_reference(hr);
  1425. hr.symbol:=newasmsymbol(tvarsym(p).mangledname);
  1426. emitpushreferenceaddr(hr);
  1427. saveregvars($ff);
  1428. emitcall('FPC_INIT_THREADVAR');
  1429. end;
  1430. end;
  1431. { initilizes data of type t }
  1432. { if is_already_ref is true then the routines assumes }
  1433. { that r points to the data to initialize }
  1434. procedure initialize(t : tdef;const ref : treference;is_already_ref : boolean);
  1435. var
  1436. hr : treference;
  1437. begin
  1438. if is_ansistring(t) or
  1439. is_widestring(t) or
  1440. is_interfacecom(t) then
  1441. begin
  1442. emit_const_ref(A_MOV,S_L,0,
  1443. newreference(ref));
  1444. end
  1445. else
  1446. begin
  1447. reset_reference(hr);
  1448. hr.symbol:=tstoreddef(t).get_rtti_label(initrtti);
  1449. emitpushreferenceaddr(hr);
  1450. if is_already_ref then
  1451. exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_L,newreference(ref)))
  1452. else
  1453. emitpushreferenceaddr(ref);
  1454. emitcall('FPC_INITIALIZE');
  1455. end;
  1456. end;
  1457. { finalizes data of type t }
  1458. { if is_already_ref is true then the routines assumes }
  1459. { that r points to the data to finalizes }
  1460. procedure finalize(t : tdef;const ref : treference;is_already_ref : boolean);
  1461. var
  1462. r : treference;
  1463. begin
  1464. if is_ansistring(t) or
  1465. is_widestring(t) then
  1466. begin
  1467. decrstringref(t,ref);
  1468. end
  1469. else if is_interfacecom(t) then
  1470. begin
  1471. decrcomintfref(t,ref);
  1472. end
  1473. else
  1474. begin
  1475. reset_reference(r);
  1476. r.symbol:=tstoreddef(t).get_rtti_label(initrtti);
  1477. emitpushreferenceaddr(r);
  1478. if is_already_ref then
  1479. exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_L,
  1480. newreference(ref)))
  1481. else
  1482. emitpushreferenceaddr(ref);
  1483. emitcall('FPC_FINALIZE');
  1484. end;
  1485. end;
  1486. { generates the code for initialisation of local data }
  1487. procedure initialize_data(p : tnamedindexitem);
  1488. var
  1489. hr : treference;
  1490. begin
  1491. if (tsym(p).typ=varsym) and
  1492. assigned(tvarsym(p).vartype.def) and
  1493. not(is_class(tvarsym(p).vartype.def)) and
  1494. tvarsym(p).vartype.def.needs_inittable then
  1495. begin
  1496. if assigned(procinfo) then
  1497. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1498. reset_reference(hr);
  1499. if tsym(p).owner.symtabletype in [localsymtable,inlinelocalsymtable] then
  1500. begin
  1501. hr.base:=procinfo^.framepointer;
  1502. hr.offset:=-tvarsym(p).address+tvarsym(p).owner.address_fixup;
  1503. end
  1504. else
  1505. begin
  1506. hr.symbol:=newasmsymbol(tvarsym(p).mangledname);
  1507. end;
  1508. initialize(tvarsym(p).vartype.def,hr,false);
  1509. end;
  1510. end;
  1511. { generates the code for incrementing the reference count of parameters and
  1512. initialize out parameters }
  1513. procedure init_paras(p : tnamedindexitem);
  1514. var
  1515. hrv : treference;
  1516. hr: treference;
  1517. begin
  1518. if (tsym(p).typ=varsym) and
  1519. not is_class(tvarsym(p).vartype.def) and
  1520. tvarsym(p).vartype.def.needs_inittable then
  1521. begin
  1522. if (tvarsym(p).varspez=vs_value) then
  1523. begin
  1524. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1525. reset_reference(hrv);
  1526. hrv.base:=procinfo^.framepointer;
  1527. if assigned(tvarsym(p).localvarsym) then
  1528. hrv.offset:=-tvarsym(p).localvarsym.address+tvarsym(p).localvarsym.owner.address_fixup
  1529. else
  1530. hrv.offset:=tvarsym(p).address+procinfo^.para_offset;
  1531. if is_ansistring(tvarsym(p).vartype.def) or
  1532. is_widestring(tvarsym(p).vartype.def) then
  1533. begin
  1534. incrstringref(tvarsym(p).vartype.def,hrv)
  1535. end
  1536. else if is_interfacecom(tvarsym(p).vartype.def) then
  1537. begin
  1538. incrcomintfref(tvarsym(p).vartype.def,hrv)
  1539. end
  1540. else
  1541. begin
  1542. reset_reference(hr);
  1543. hr.symbol:=tstoreddef(tvarsym(p).vartype.def).get_rtti_label(initrtti);
  1544. emitpushreferenceaddr(hr);
  1545. emitpushreferenceaddr(hrv);
  1546. emitcall('FPC_ADDREF');
  1547. end;
  1548. end
  1549. else if (tvarsym(p).varspez=vs_out) then
  1550. begin
  1551. reset_reference(hrv);
  1552. hrv.base:=procinfo^.framepointer;
  1553. hrv.offset:=tvarsym(p).address+procinfo^.para_offset;
  1554. getexplicitregister32(R_EDI);
  1555. exprasmList.concat(Taicpu.Op_ref_reg(A_MOV,S_L,newreference(hrv),R_EDI));
  1556. reset_reference(hr);
  1557. hr.base:=R_EDI;
  1558. initialize(tvarsym(p).vartype.def,hr,false);
  1559. end;
  1560. end;
  1561. end;
  1562. { generates the code for decrementing the reference count of parameters }
  1563. procedure final_paras(p : tnamedindexitem);
  1564. var
  1565. hrv : treference;
  1566. hr: treference;
  1567. begin
  1568. if (tsym(p).typ=varsym) and
  1569. not is_class(tvarsym(p).vartype.def) and
  1570. tvarsym(p).vartype.def.needs_inittable then
  1571. begin
  1572. if (tvarsym(p).varspez=vs_value) then
  1573. begin
  1574. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1575. reset_reference(hrv);
  1576. hrv.base:=procinfo^.framepointer;
  1577. if assigned(tvarsym(p).localvarsym) then
  1578. hrv.offset:=-tvarsym(p).localvarsym.address+tvarsym(p).localvarsym.owner.address_fixup
  1579. else
  1580. hrv.offset:=tvarsym(p).address+procinfo^.para_offset;
  1581. if is_ansistring(tvarsym(p).vartype.def) or
  1582. is_widestring(tvarsym(p).vartype.def) then
  1583. begin
  1584. decrstringref(tvarsym(p).vartype.def,hrv)
  1585. end
  1586. else if is_interfacecom(tvarsym(p).vartype.def) then
  1587. begin
  1588. decrcomintfref(tvarsym(p).vartype.def,hrv)
  1589. end
  1590. else
  1591. begin
  1592. reset_reference(hr);
  1593. hr.symbol:=tstoreddef(tvarsym(p).vartype.def).get_rtti_label(initrtti);
  1594. emitpushreferenceaddr(hr);
  1595. emitpushreferenceaddr(hrv);
  1596. emitcall('FPC_DECREF');
  1597. end;
  1598. end;
  1599. end;
  1600. end;
  1601. { generates the code for finalisation of local data }
  1602. procedure finalize_data(p : tnamedindexitem);
  1603. var
  1604. hr : treference;
  1605. begin
  1606. if (tsym(p).typ=varsym) and
  1607. assigned(tvarsym(p).vartype.def) and
  1608. not(is_class(tvarsym(p).vartype.def)) and
  1609. tvarsym(p).vartype.def.needs_inittable then
  1610. begin
  1611. if assigned(procinfo) then
  1612. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1613. reset_reference(hr);
  1614. case tsym(p).owner.symtabletype of
  1615. localsymtable,inlinelocalsymtable:
  1616. begin
  1617. hr.base:=procinfo^.framepointer;
  1618. hr.offset:=-tvarsym(p).address+tvarsym(p).owner.address_fixup;
  1619. end;
  1620. else
  1621. hr.symbol:=newasmsymbol(tvarsym(p).mangledname);
  1622. end;
  1623. finalize(tvarsym(p).vartype.def,hr,false);
  1624. end;
  1625. end;
  1626. { generates the code to make local copies of the value parameters }
  1627. procedure copyvalueparas(p : tnamedindexitem);
  1628. var
  1629. href1,href2 : treference;
  1630. r : preference;
  1631. power,len : longint;
  1632. opsize : topsize;
  1633. {$ifndef NOTARGETWIN32}
  1634. again,ok : tasmlabel;
  1635. {$endif}
  1636. begin
  1637. if (tsym(p).typ=varsym) and
  1638. (tvarsym(p).varspez=vs_value) and
  1639. (push_addr_param(tvarsym(p).vartype.def)) then
  1640. begin
  1641. if is_open_array(tvarsym(p).vartype.def) or
  1642. is_array_of_const(tvarsym(p).vartype.def) then
  1643. begin
  1644. { get stack space }
  1645. new(r);
  1646. reset_reference(r^);
  1647. r^.base:=procinfo^.framepointer;
  1648. r^.offset:=tvarsym(p).address+4+procinfo^.para_offset;
  1649. getexplicitregister32(R_EDI);
  1650. exprasmList.concat(Taicpu.op_ref_reg(A_MOV,S_L,r,R_EDI));
  1651. exprasmList.concat(Taicpu.op_reg(A_INC,S_L,R_EDI));
  1652. if (tarraydef(tvarsym(p).vartype.def).elesize<>1) then
  1653. begin
  1654. if ispowerof2(tarraydef(tvarsym(p).vartype.def).elesize, power) then
  1655. exprasmList.concat(Taicpu.op_const_reg(A_SHL,S_L,power,R_EDI))
  1656. else
  1657. exprasmList.concat(Taicpu.op_const_reg(A_IMUL,S_L,
  1658. tarraydef(tvarsym(p).vartype.def).elesize,R_EDI));
  1659. end;
  1660. {$ifndef NOTARGETWIN32}
  1661. { windows guards only a few pages for stack growing, }
  1662. { so we have to access every page first }
  1663. if target_info.target=target_i386_win32 then
  1664. begin
  1665. getlabel(again);
  1666. getlabel(ok);
  1667. emitlab(again);
  1668. exprasmList.concat(Taicpu.op_const_reg(A_CMP,S_L,winstackpagesize,R_EDI));
  1669. emitjmp(C_C,ok);
  1670. exprasmList.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,R_ESP));
  1671. exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
  1672. exprasmList.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize,R_EDI));
  1673. emitjmp(C_None,again);
  1674. emitlab(ok);
  1675. exprasmList.concat(Taicpu.op_reg_reg(A_SUB,S_L,R_EDI,R_ESP));
  1676. ungetregister32(R_EDI);
  1677. { now reload EDI }
  1678. new(r);
  1679. reset_reference(r^);
  1680. r^.base:=procinfo^.framepointer;
  1681. r^.offset:=tvarsym(p).address+4+procinfo^.para_offset;
  1682. getexplicitregister32(R_EDI);
  1683. exprasmList.concat(Taicpu.op_ref_reg(A_MOV,S_L,r,R_EDI));
  1684. exprasmList.concat(Taicpu.op_reg(A_INC,S_L,R_EDI));
  1685. if (tarraydef(tvarsym(p).vartype.def).elesize<>1) then
  1686. begin
  1687. if ispowerof2(tarraydef(tvarsym(p).vartype.def).elesize, power) then
  1688. exprasmList.concat(Taicpu.op_const_reg(A_SHL,S_L,power,R_EDI))
  1689. else
  1690. exprasmList.concat(Taicpu.op_const_reg(A_IMUL,S_L,
  1691. tarraydef(tvarsym(p).vartype.def).elesize,R_EDI));
  1692. end;
  1693. end
  1694. else
  1695. {$endif NOTARGETWIN32}
  1696. exprasmList.concat(Taicpu.op_reg_reg(A_SUB,S_L,R_EDI,R_ESP));
  1697. { load destination }
  1698. exprasmList.concat(Taicpu.op_reg_reg(A_MOV,S_L,R_ESP,R_EDI));
  1699. { don't destroy the registers! }
  1700. exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_ECX));
  1701. exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_ESI));
  1702. { load count }
  1703. new(r);
  1704. reset_reference(r^);
  1705. r^.base:=procinfo^.framepointer;
  1706. r^.offset:=tvarsym(p).address+4+procinfo^.para_offset;
  1707. exprasmList.concat(Taicpu.op_ref_reg(A_MOV,S_L,r,R_ECX));
  1708. { load source }
  1709. new(r);
  1710. reset_reference(r^);
  1711. r^.base:=procinfo^.framepointer;
  1712. r^.offset:=tvarsym(p).address+procinfo^.para_offset;
  1713. exprasmList.concat(Taicpu.op_ref_reg(A_MOV,S_L,r,R_ESI));
  1714. { scheduled .... }
  1715. exprasmList.concat(Taicpu.op_reg(A_INC,S_L,R_ECX));
  1716. { calculate size }
  1717. len:=tarraydef(tvarsym(p).vartype.def).elesize;
  1718. opsize:=S_B;
  1719. if (len and 3)=0 then
  1720. begin
  1721. opsize:=S_L;
  1722. len:=len shr 2;
  1723. end
  1724. else
  1725. if (len and 1)=0 then
  1726. begin
  1727. opsize:=S_W;
  1728. len:=len shr 1;
  1729. end;
  1730. if ispowerof2(len, power) then
  1731. exprasmList.concat(Taicpu.op_const_reg(A_SHL,S_L,power,R_ECX))
  1732. else
  1733. exprasmList.concat(Taicpu.op_const_reg(A_IMUL,S_L,len,R_ECX));
  1734. exprasmList.concat(Taicpu.op_none(A_REP,S_NO));
  1735. case opsize of
  1736. S_B : exprasmList.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  1737. S_W : exprasmList.concat(Taicpu.Op_none(A_MOVSW,S_NO));
  1738. S_L : exprasmList.concat(Taicpu.Op_none(A_MOVSD,S_NO));
  1739. end;
  1740. ungetregister32(R_EDI);
  1741. exprasmList.concat(Taicpu.op_reg(A_POP,S_L,R_ESI));
  1742. exprasmList.concat(Taicpu.op_reg(A_POP,S_L,R_ECX));
  1743. { patch the new address }
  1744. new(r);
  1745. reset_reference(r^);
  1746. r^.base:=procinfo^.framepointer;
  1747. r^.offset:=tvarsym(p).address+procinfo^.para_offset;
  1748. exprasmList.concat(Taicpu.op_reg_ref(A_MOV,S_L,R_ESP,r));
  1749. end
  1750. else
  1751. if is_shortstring(tvarsym(p).vartype.def) then
  1752. begin
  1753. reset_reference(href1);
  1754. href1.base:=procinfo^.framepointer;
  1755. href1.offset:=tvarsym(p).address+procinfo^.para_offset;
  1756. reset_reference(href2);
  1757. href2.base:=procinfo^.framepointer;
  1758. href2.offset:=-tvarsym(p).localvarsym.address+tvarsym(p).localvarsym.owner.address_fixup;
  1759. copyshortstring(href2,href1,tstringdef(tvarsym(p).vartype.def).len,true,false);
  1760. end
  1761. else
  1762. begin
  1763. reset_reference(href1);
  1764. href1.base:=procinfo^.framepointer;
  1765. href1.offset:=tvarsym(p).address+procinfo^.para_offset;
  1766. reset_reference(href2);
  1767. href2.base:=procinfo^.framepointer;
  1768. href2.offset:=-tvarsym(p).localvarsym.address+tvarsym(p).localvarsym.owner.address_fixup;
  1769. concatcopy(href1,href2,tvarsym(p).vartype.def.size,true,true);
  1770. end;
  1771. end;
  1772. end;
  1773. procedure inittempvariables;
  1774. var
  1775. hp : ptemprecord;
  1776. r : preference;
  1777. begin
  1778. hp:=templist;
  1779. while assigned(hp) do
  1780. begin
  1781. if hp^.temptype in [tt_ansistring,tt_freeansistring,
  1782. tt_widestring,tt_freewidestring,
  1783. tt_interfacecom] then
  1784. begin
  1785. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1786. new(r);
  1787. reset_reference(r^);
  1788. r^.base:=procinfo^.framepointer;
  1789. r^.offset:=hp^.pos;
  1790. emit_const_ref(A_MOV,S_L,0,r);
  1791. end;
  1792. hp:=hp^.next;
  1793. end;
  1794. end;
  1795. procedure finalizetempvariables;
  1796. var
  1797. hp : ptemprecord;
  1798. hr : treference;
  1799. begin
  1800. hp:=templist;
  1801. while assigned(hp) do
  1802. begin
  1803. if hp^.temptype in [tt_ansistring,tt_freeansistring] then
  1804. begin
  1805. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1806. reset_reference(hr);
  1807. hr.base:=procinfo^.framepointer;
  1808. hr.offset:=hp^.pos;
  1809. emitpushreferenceaddr(hr);
  1810. emitcall('FPC_ANSISTR_DECR_REF');
  1811. end
  1812. else if hp^.temptype in [tt_widestring,tt_freewidestring] then
  1813. begin
  1814. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1815. reset_reference(hr);
  1816. hr.base:=procinfo^.framepointer;
  1817. hr.offset:=hp^.pos;
  1818. emitpushreferenceaddr(hr);
  1819. emitcall('FPC_WIDESTR_DECR_REF');
  1820. end
  1821. else if hp^.temptype=tt_interfacecom then
  1822. begin
  1823. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1824. reset_reference(hr);
  1825. hr.base:=procinfo^.framepointer;
  1826. hr.offset:=hp^.pos;
  1827. emitpushreferenceaddr(hr);
  1828. emitcall('FPC_INTF_DECR_REF');
  1829. end;
  1830. hp:=hp^.next;
  1831. end;
  1832. end;
  1833. {$ifdef dummy}
  1834. var
  1835. ls : longint;
  1836. procedure largest_size(p : tnamedindexitem);
  1837. begin
  1838. if (tsym(p).typ=varsym) and
  1839. (tvarsym(p).getvaluesize>ls) then
  1840. ls:=tvarsym(p).getvaluesize;
  1841. end;
  1842. {$endif dummy}
  1843. procedure alignstack(alist : TAAsmoutput);
  1844. begin
  1845. {$ifdef dummy}
  1846. if (cs_optimize in aktglobalswitches) and
  1847. (aktoptprocessor in [classp5,classp6]) then
  1848. begin
  1849. ls:=0;
  1850. aktprocdef.localst.foreach({$ifndef TP}@{$endif}largest_size);
  1851. if ls>=8 then
  1852. aList.insert(Taicpu.Op_const_reg(A_AND,S_L,-8,R_ESP));
  1853. end;
  1854. {$endif dummy}
  1855. end;
  1856. procedure genentrycode(alist : TAAsmoutput;make_global:boolean;
  1857. stackframe:longint;
  1858. var parasize:longint;var nostackframe:boolean;
  1859. inlined : boolean);
  1860. {
  1861. Generates the entry code for a procedure
  1862. }
  1863. var
  1864. hs : string;
  1865. {$ifdef GDB}
  1866. stab_function_name : tai_stab_function_name;
  1867. {$endif GDB}
  1868. hr : preference;
  1869. p : tsymtable;
  1870. r : treference;
  1871. oldlist,
  1872. oldexprasmlist : TAAsmoutput;
  1873. again : tasmlabel;
  1874. i : longint;
  1875. tempbuf,tempaddr : treference;
  1876. begin
  1877. oldexprasmlist:=exprasmlist;
  1878. exprasmlist:=alist;
  1879. if (not inlined) and (aktprocdef.proctypeoption=potype_proginit) then
  1880. begin
  1881. emitinsertcall('FPC_INITIALIZEUNITS');
  1882. { initialize profiling for win32 }
  1883. if (target_info.target=target_I386_WIN32) and
  1884. (cs_profile in aktmoduleswitches) then
  1885. emitinsertcall('__monstartup');
  1886. { add threadvars }
  1887. oldlist:=exprasmlist;
  1888. exprasmlist:=TAAsmoutput.Create;
  1889. p:=symtablestack;
  1890. while assigned(p) do
  1891. begin
  1892. p.foreach_static({$ifndef TP}@{$endif}initialize_threadvar);
  1893. p:=p.next;
  1894. end;
  1895. oldList.insertlist(exprasmlist);
  1896. exprasmlist.free;
  1897. exprasmlist:=oldlist;
  1898. end;
  1899. {$ifdef GDB}
  1900. if (not inlined) and (cs_debuginfo in aktmoduleswitches) then
  1901. exprasmList.insert(Tai_force_line.Create);
  1902. {$endif GDB}
  1903. { a constructor needs a help procedure }
  1904. if (aktprocdef.proctypeoption=potype_constructor) then
  1905. begin
  1906. if is_class(procinfo^._class) then
  1907. begin
  1908. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1909. exprasmList.insert(Taicpu.Op_cond_sym(A_Jcc,C_Z,S_NO,faillabel));
  1910. emitinsertcall('FPC_NEW_CLASS');
  1911. end
  1912. else if is_object(procinfo^._class) then
  1913. begin
  1914. exprasmList.insert(Taicpu.Op_cond_sym(A_Jcc,C_Z,S_NO,faillabel));
  1915. emitinsertcall('FPC_HELP_CONSTRUCTOR');
  1916. getexplicitregister32(R_EDI);
  1917. exprasmList.insert(Taicpu.Op_const_reg(A_MOV,S_L,procinfo^._class.vmt_offset,R_EDI));
  1918. end
  1919. else
  1920. Internalerror(200006161);
  1921. end;
  1922. { don't load ESI, does the caller }
  1923. { we must do it for local function }
  1924. { that can be called from a foreach_static }
  1925. { of another object than self !! PM }
  1926. if assigned(procinfo^._class) and { !!!!! shouldn't we load ESI always? }
  1927. (lexlevel>normal_function_level) then
  1928. maybe_loadself;
  1929. { When message method contains self as a parameter,
  1930. we must load it into ESI }
  1931. If (po_containsself in aktprocdef.procoptions) then
  1932. begin
  1933. new(hr);
  1934. reset_reference(hr^);
  1935. hr^.offset:=procinfo^.selfpointer_offset;
  1936. hr^.base:=procinfo^.framepointer;
  1937. exprasmList.insert(Taicpu.Op_ref_reg(A_MOV,S_L,hr,R_ESI));
  1938. exprasmList.insert(Tairegalloc.Alloc(R_ESI));
  1939. end;
  1940. { should we save edi,esi,ebx like C ? }
  1941. if (po_savestdregs in aktprocdef.procoptions) then
  1942. begin
  1943. if (aktprocdef.usedregisters and ($80 shr byte(R_EBX)))<>0 then
  1944. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EBX));
  1945. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_ESI));
  1946. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
  1947. end;
  1948. { for the save all registers we can simply use a pusha,popa which
  1949. push edi,esi,ebp,esp(ignored),ebx,edx,ecx,eax }
  1950. if (po_saveregisters in aktprocdef.procoptions) then
  1951. begin
  1952. exprasmList.insert(Taicpu.Op_none(A_PUSHA,S_L));
  1953. end;
  1954. { omit stack frame ? }
  1955. if (not inlined) then
  1956. if (procinfo^.framepointer=stack_pointer) then
  1957. begin
  1958. CGMessage(cg_d_stackframe_omited);
  1959. nostackframe:=true;
  1960. if (aktprocdef.proctypeoption in [potype_unitinit,potype_proginit,potype_unitfinalize]) then
  1961. parasize:=0
  1962. else
  1963. parasize:=aktprocdef.parast.datasize+procinfo^.para_offset-4;
  1964. if stackframe<>0 then
  1965. exprasmList.insert(Taicpu.op_const_reg(A_SUB,S_L,stackframe,R_ESP));
  1966. end
  1967. else
  1968. begin
  1969. alignstack(alist);
  1970. if (aktprocdef.proctypeoption in [potype_unitinit,potype_proginit,potype_unitfinalize]) then
  1971. parasize:=0
  1972. else
  1973. parasize:=aktprocdef.parast.datasize+procinfo^.para_offset-8;
  1974. nostackframe:=false;
  1975. if stackframe<>0 then
  1976. begin
  1977. {$ifndef NOTARGETWIN32}
  1978. { windows guards only a few pages for stack growing, }
  1979. { so we have to access every page first }
  1980. if (target_info.target=target_i386_win32) and
  1981. (stackframe>=winstackpagesize) then
  1982. begin
  1983. if stackframe div winstackpagesize<=5 then
  1984. begin
  1985. exprasmList.insert(Taicpu.Op_const_reg(A_SUB,S_L,stackframe-4,R_ESP));
  1986. for i:=1 to stackframe div winstackpagesize do
  1987. begin
  1988. hr:=new_reference(R_ESP,stackframe-i*winstackpagesize);
  1989. exprasmList.concat(Taicpu.op_const_ref(A_MOV,S_L,0,hr));
  1990. end;
  1991. exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
  1992. end
  1993. else
  1994. begin
  1995. getlabel(again);
  1996. getexplicitregister32(R_EDI);
  1997. exprasmList.concat(Taicpu.op_const_reg(A_MOV,S_L,stackframe div winstackpagesize,R_EDI));
  1998. emitlab(again);
  1999. exprasmList.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,R_ESP));
  2000. exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
  2001. exprasmList.concat(Taicpu.op_reg(A_DEC,S_L,R_EDI));
  2002. emitjmp(C_NZ,again);
  2003. ungetregister32(R_EDI);
  2004. exprasmList.concat(Taicpu.op_const_reg(A_SUB,S_L,stackframe mod winstackpagesize,R_ESP));
  2005. end
  2006. end
  2007. else
  2008. {$endif NOTARGETWIN32}
  2009. exprasmList.insert(Taicpu.Op_const_reg(A_SUB,S_L,stackframe,R_ESP));
  2010. if (cs_check_stack in aktlocalswitches) and
  2011. not(target_info.target in [target_i386_freebsd,target_i386_netbsd,
  2012. target_i386_linux,target_i386_win32]) then
  2013. begin
  2014. emitinsertcall('FPC_STACKCHECK');
  2015. exprasmList.insert(Taicpu.Op_const(A_PUSH,S_L,stackframe));
  2016. end;
  2017. if cs_profile in aktmoduleswitches then
  2018. genprofilecode;
  2019. exprasmList.insert(Taicpu.Op_reg_reg(A_MOV,S_L,R_ESP,R_EBP));
  2020. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EBP));
  2021. end { endif stackframe <> 0 }
  2022. else
  2023. begin
  2024. if cs_profile in aktmoduleswitches then
  2025. genprofilecode;
  2026. exprasmList.insert(Taicpu.Op_reg_reg(A_MOV,S_L,R_ESP,R_EBP));
  2027. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EBP));
  2028. end;
  2029. end;
  2030. if (po_interrupt in aktprocdef.procoptions) then
  2031. generate_interrupt_stackframe_entry;
  2032. { initialize return value }
  2033. if (not is_void(aktprocdef.rettype.def)) and
  2034. (aktprocdef.rettype.def.needs_inittable) then
  2035. begin
  2036. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  2037. reset_reference(r);
  2038. r.offset:=procinfo^.return_offset;
  2039. r.base:=procinfo^.framepointer;
  2040. initialize(aktprocdef.rettype.def,r,ret_in_param(aktprocdef.rettype.def));
  2041. end;
  2042. { initialisize local data like ansistrings }
  2043. case aktprocdef.proctypeoption of
  2044. potype_unitinit:
  2045. begin
  2046. { using current_module.globalsymtable is hopefully }
  2047. { more robust than symtablestack and symtablestack.next }
  2048. tsymtable(current_module.globalsymtable).foreach_static({$ifndef TP}@{$endif}initialize_data);
  2049. tsymtable(current_module.localsymtable).foreach_static({$ifndef TP}@{$endif}initialize_data);
  2050. end;
  2051. { units have seperate code for initilization and finalization }
  2052. potype_unitfinalize: ;
  2053. else
  2054. aktprocdef.localst.foreach_static({$ifndef TP}@{$endif}initialize_data);
  2055. end;
  2056. { initialisizes temp. ansi/wide string data }
  2057. inittempvariables;
  2058. { generate copies of call by value parameters }
  2059. if not(po_assembler in aktprocdef.procoptions) and
  2060. not(aktprocdef.proccalloption in [pocall_cdecl,pocall_cppdecl,pocall_palmossyscall,pocall_system]) then
  2061. aktprocdef.parast.foreach_static({$ifndef TP}@{$endif}copyvalueparas);
  2062. if assigned( aktprocdef.parast) then
  2063. aktprocdef.parast.foreach_static({$ifndef TP}@{$endif}init_paras);
  2064. { do we need an exception frame because of ansi/widestrings/interfaces ? }
  2065. if not inlined and
  2066. ((procinfo^.flags and pi_needs_implicit_finally)<>0) and
  2067. { but it's useless in init/final code of units }
  2068. not(aktprocdef.proctypeoption in [potype_unitfinalize,potype_unitinit]) then
  2069. begin
  2070. usedinproc:=usedinproc or ($80 shr byte(R_EAX));
  2071. exprasmList.concat(Taicpu.op_const_reg(A_SUB,S_L,36,R_ESP));
  2072. exprasmList.concat(Taicpu.op_reg_reg(A_MOV,S_L,R_ESP,R_EDI));
  2073. reset_reference(tempaddr);
  2074. tempaddr.base:=R_EDI;
  2075. emitpushreferenceaddr(tempaddr);
  2076. reset_reference(tempbuf);
  2077. tempbuf.base:=R_EDI;
  2078. tempbuf.offset:=12;
  2079. emitpushreferenceaddr(tempbuf);
  2080. { Type of stack-frame must be pushed}
  2081. exprasmList.concat(Taicpu.op_const(A_PUSH,S_L,1));
  2082. emitcall('FPC_PUSHEXCEPTADDR');
  2083. exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
  2084. emitcall('FPC_SETJMP');
  2085. exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
  2086. exprasmList.concat(Taicpu.op_reg_reg(A_TEST,S_L,R_EAX,R_EAX));
  2087. emitjmp(C_NE,aktexitlabel);
  2088. { probably we've to reload self here }
  2089. maybe_loadself;
  2090. end;
  2091. if not inlined then
  2092. begin
  2093. if (cs_profile in aktmoduleswitches) or
  2094. (aktprocdef.owner.symtabletype=globalsymtable) or
  2095. (assigned(procinfo^._class) and (procinfo^._class.owner.symtabletype=globalsymtable)) then
  2096. make_global:=true;
  2097. hs:=aktprocdef.aliasnames.getfirst;
  2098. {$ifdef GDB}
  2099. if (cs_debuginfo in aktmoduleswitches) and target_info.use_function_relative_addresses then
  2100. stab_function_name := Tai_stab_function_name.Create(strpnew(hs));
  2101. {$EndIf GDB}
  2102. while hs<>'' do
  2103. begin
  2104. if make_global then
  2105. exprasmList.insert(Tai_symbol.Createname_global(hs,0))
  2106. else
  2107. exprasmList.insert(Tai_symbol.Createname(hs,0));
  2108. {$ifdef GDB}
  2109. if (cs_debuginfo in aktmoduleswitches) and
  2110. target_info.use_function_relative_addresses then
  2111. exprasmList.insert(Tai_stab_function_name.Create(strpnew(hs)));
  2112. {$endif GDB}
  2113. hs:=aktprocdef.aliasnames.getfirst;
  2114. end;
  2115. if make_global or ((procinfo^.flags and pi_is_global) <> 0) then
  2116. aktprocsym.is_global := True;
  2117. {$ifdef GDB}
  2118. if (cs_debuginfo in aktmoduleswitches) then
  2119. begin
  2120. if target_info.use_function_relative_addresses then
  2121. exprasmList.insert(stab_function_name);
  2122. exprasmList.insert(Tai_stabs.Create(aktprocdef.stabstring));
  2123. aktprocsym.isstabwritten:=true;
  2124. end;
  2125. {$endif GDB}
  2126. { Align, gprof uses 16 byte granularity }
  2127. if (cs_profile in aktmoduleswitches) then
  2128. exprasmList.insert(Tai_align.Create_op(16,$90))
  2129. else
  2130. exprasmList.insert(Tai_align.Create(aktalignment.procalign));
  2131. end;
  2132. if inlined then
  2133. load_regvars(exprasmlist,nil);
  2134. exprasmlist:=oldexprasmlist;
  2135. end;
  2136. procedure handle_return_value(inlined : boolean;var uses_eax,uses_edx : boolean);
  2137. var
  2138. hr : preference;
  2139. op : Tasmop;
  2140. s : Topsize;
  2141. begin
  2142. if not is_void(aktprocdef.rettype.def) then
  2143. begin
  2144. {if ((procinfo^.flags and pi_operator)<>0) and
  2145. assigned(otsym) then
  2146. procinfo^.funcret_is_valid:=
  2147. procinfo^.funcret_is_valid or (otsym.refs>0);}
  2148. if (tfuncretsym(aktprocdef.funcretsym).funcretstate<>vs_assigned) and not inlined { and
  2149. ((procinfo^.flags and pi_uses_asm)=0)} then
  2150. CGMessage(sym_w_function_result_not_set);
  2151. hr:=new_reference(procinfo^.framepointer,procinfo^.return_offset);
  2152. if (aktprocdef.rettype.def.deftype in [orddef,enumdef]) then
  2153. begin
  2154. uses_eax:=true;
  2155. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  2156. case aktprocdef.rettype.def.size of
  2157. 8:
  2158. begin
  2159. emit_ref_reg(A_MOV,S_L,hr,R_EAX);
  2160. hr:=new_reference(procinfo^.framepointer,procinfo^.return_offset+4);
  2161. exprasmList.concat(Tairegalloc.Alloc(R_EDX));
  2162. emit_ref_reg(A_MOV,S_L,hr,R_EDX);
  2163. uses_edx:=true;
  2164. end;
  2165. 4:
  2166. emit_ref_reg(A_MOV,S_L,hr,R_EAX);
  2167. 2:
  2168. emit_ref_reg(A_MOV,S_W,hr,R_AX);
  2169. 1:
  2170. emit_ref_reg(A_MOV,S_B,hr,R_AL);
  2171. end;
  2172. end
  2173. else
  2174. if ret_in_acc(aktprocdef.rettype.def) then
  2175. begin
  2176. uses_eax:=true;
  2177. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  2178. emit_ref_reg(A_MOV,S_L,hr,R_EAX);
  2179. end
  2180. else
  2181. if (aktprocdef.rettype.def.deftype=floatdef) then
  2182. begin
  2183. floatloadops(tfloatdef(aktprocdef.rettype.def).typ,op,s);
  2184. exprasmList.concat(Taicpu.Op_ref(op,s,hr));
  2185. end
  2186. else
  2187. dispose(hr);
  2188. end
  2189. end;
  2190. procedure handle_fast_exit_return_value;
  2191. var
  2192. hr : preference;
  2193. op : Tasmop;
  2194. s : Topsize;
  2195. begin
  2196. if not is_void(aktprocdef.rettype.def) then
  2197. begin
  2198. hr:=new_reference(procinfo^.framepointer,procinfo^.return_offset);
  2199. if (aktprocdef.rettype.def.deftype in [orddef,enumdef]) then
  2200. begin
  2201. case aktprocdef.rettype.def.size of
  2202. 8:
  2203. begin
  2204. emit_reg_ref(A_MOV,S_L,R_EAX,hr);
  2205. hr:=new_reference(procinfo^.framepointer,procinfo^.return_offset+4);
  2206. emit_reg_ref(A_MOV,S_L,R_EDX,hr);
  2207. end;
  2208. 4:
  2209. emit_reg_ref(A_MOV,S_L,R_EAX,hr);
  2210. 2:
  2211. emit_reg_ref(A_MOV,S_W,R_AX,hr);
  2212. 1:
  2213. emit_reg_ref(A_MOV,S_B,R_AL,hr);
  2214. end;
  2215. end
  2216. else
  2217. if ret_in_acc(aktprocdef.rettype.def) then
  2218. begin
  2219. emit_reg_ref(A_MOV,S_L,R_EAX,hr);
  2220. end
  2221. else
  2222. if (aktprocdef.rettype.def.deftype=floatdef) then
  2223. begin
  2224. floatstoreops(tfloatdef(aktprocdef.rettype.def).typ,op,s);
  2225. exprasmlist.concat(taicpu.op_ref(op,s,hr));
  2226. end
  2227. else
  2228. dispose(hr);
  2229. end
  2230. end;
  2231. procedure genexitcode(alist : TAAsmoutput;parasize:longint;nostackframe,inlined:boolean);
  2232. var
  2233. {$ifdef GDB}
  2234. mangled_length : longint;
  2235. p : pchar;
  2236. st : string[2];
  2237. {$endif GDB}
  2238. stabsendlabel,nofinal,okexitlabel,
  2239. noreraiselabel,nodestroycall : tasmlabel;
  2240. hr : treference;
  2241. uses_eax,uses_edx,uses_esi : boolean;
  2242. oldexprasmlist : TAAsmoutput;
  2243. ai : taicpu;
  2244. pd : tprocdef;
  2245. begin
  2246. oldexprasmlist:=exprasmlist;
  2247. exprasmlist:=alist;
  2248. if aktexit2label.is_used and
  2249. ((procinfo^.flags and (pi_needs_implicit_finally or pi_uses_exceptions)) <> 0) then
  2250. begin
  2251. exprasmlist.concat(taicpu.op_sym(A_JMP,S_NO,aktexitlabel));
  2252. exprasmlist.concat(tai_label.create(aktexit2label));
  2253. handle_fast_exit_return_value;
  2254. end;
  2255. if aktexitlabel.is_used then
  2256. exprasmList.concat(Tai_label.Create(aktexitlabel));
  2257. cleanup_regvars(alist);
  2258. { call the destructor help procedure }
  2259. if (aktprocdef.proctypeoption=potype_destructor) and
  2260. assigned(procinfo^._class) then
  2261. begin
  2262. if is_class(procinfo^._class) then
  2263. begin
  2264. emitinsertcall('FPC_DISPOSE_CLASS');
  2265. end
  2266. else if is_object(procinfo^._class) then
  2267. begin
  2268. emitinsertcall('FPC_HELP_DESTRUCTOR');
  2269. getexplicitregister32(R_EDI);
  2270. exprasmList.insert(Taicpu.Op_const_reg(A_MOV,S_L,procinfo^._class.vmt_offset,R_EDI));
  2271. { must the object be finalized ? }
  2272. if procinfo^._class.needs_inittable then
  2273. begin
  2274. getlabel(nofinal);
  2275. exprasmList.insert(Tai_label.Create(nofinal));
  2276. emitinsertcall('FPC_FINALIZE');
  2277. ungetregister32(R_EDI);
  2278. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_ESI));
  2279. exprasmList.insert(Taicpu.Op_sym(A_PUSH,S_L,procinfo^._class.get_rtti_label(initrtti)));
  2280. ai:=Taicpu.Op_sym(A_Jcc,S_NO,nofinal);
  2281. ai.SetCondition(C_Z);
  2282. exprasmList.insert(ai);
  2283. reset_reference(hr);
  2284. hr.base:=R_EBP;
  2285. hr.offset:=8;
  2286. exprasmList.insert(Taicpu.Op_const_ref(A_CMP,S_L,0,newreference(hr)));
  2287. end;
  2288. end
  2289. else
  2290. begin
  2291. Internalerror(200006161);
  2292. end;
  2293. end;
  2294. { finalize temporary data }
  2295. finalizetempvariables;
  2296. { finalize local data like ansistrings}
  2297. case aktprocdef.proctypeoption of
  2298. potype_unitfinalize:
  2299. begin
  2300. { using current_module.globalsymtable is hopefully }
  2301. { more robust than symtablestack and symtablestack.next }
  2302. tsymtable(current_module.globalsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
  2303. tsymtable(current_module.localsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
  2304. end;
  2305. { units have seperate code for initialization and finalization }
  2306. potype_unitinit: ;
  2307. else
  2308. aktprocdef.localst.foreach_static({$ifndef TP}@{$endif}finalize_data);
  2309. end;
  2310. { finalize paras data }
  2311. if assigned(aktprocdef.parast) then
  2312. aktprocdef.parast.foreach_static({$ifndef TP}@{$endif}final_paras);
  2313. { do we need to handle exceptions because of ansi/widestrings ? }
  2314. if not inlined and
  2315. ((procinfo^.flags and pi_needs_implicit_finally)<>0) and
  2316. { but it's useless in init/final code of units }
  2317. not(aktprocdef.proctypeoption in [potype_unitfinalize,potype_unitinit]) then
  2318. begin
  2319. { the exception helper routines modify all registers }
  2320. aktprocdef.usedregisters:=$ff;
  2321. getlabel(noreraiselabel);
  2322. emitcall('FPC_POPADDRSTACK');
  2323. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  2324. exprasmList.concat(Taicpu.op_reg(A_POP,S_L,R_EAX));
  2325. exprasmList.concat(Taicpu.op_reg_reg(A_TEST,S_L,R_EAX,R_EAX));
  2326. ungetregister32(R_EAX);
  2327. emitjmp(C_E,noreraiselabel);
  2328. if (aktprocdef.proctypeoption=potype_constructor) then
  2329. begin
  2330. if assigned(procinfo^._class) then
  2331. begin
  2332. pd:=procinfo^._class.searchdestructor;
  2333. if assigned(pd) then
  2334. begin
  2335. getlabel(nodestroycall);
  2336. emit_const_ref(A_CMP,S_L,0,new_reference(procinfo^.framepointer,
  2337. procinfo^.selfpointer_offset));
  2338. emitjmp(C_E,nodestroycall);
  2339. if is_class(procinfo^._class) then
  2340. begin
  2341. emit_const(A_PUSH,S_L,1);
  2342. emit_reg(A_PUSH,S_L,R_ESI);
  2343. end
  2344. else if is_object(procinfo^._class) then
  2345. begin
  2346. emit_reg(A_PUSH,S_L,R_ESI);
  2347. emit_sym(A_PUSH,S_L,newasmsymbol(procinfo^._class.vmt_mangledname));
  2348. end
  2349. else
  2350. begin
  2351. Internalerror(200006161);
  2352. end;
  2353. if (po_virtualmethod in pd.procoptions) then
  2354. begin
  2355. emit_ref_reg(A_MOV,S_L,new_reference(R_ESI,0),R_EDI);
  2356. emit_ref(A_CALL,S_NO,new_reference(R_EDI,procinfo^._class.vmtmethodoffset(pd.extnumber)));
  2357. end
  2358. else
  2359. emitcall(pd.mangledname);
  2360. { not necessary because the result is never assigned in the
  2361. case of an exception (FK)
  2362. emit_const_reg(A_MOV,S_L,0,R_ESI);
  2363. emit_const_ref(A_MOV,S_L,0,new_reference(procinfo^.framepointer,8));
  2364. }
  2365. emitlab(nodestroycall);
  2366. end;
  2367. end
  2368. end
  2369. else
  2370. { must be the return value finalized before reraising the exception? }
  2371. if (not is_void(aktprocdef.rettype.def)) and
  2372. (aktprocdef.rettype.def.needs_inittable) and
  2373. ((aktprocdef.rettype.def.deftype<>objectdef) or
  2374. not is_class(aktprocdef.rettype.def)) then
  2375. begin
  2376. reset_reference(hr);
  2377. hr.offset:=procinfo^.return_offset;
  2378. hr.base:=procinfo^.framepointer;
  2379. finalize(aktprocdef.rettype.def,hr,ret_in_param(aktprocdef.rettype.def));
  2380. end;
  2381. emitcall('FPC_RERAISE');
  2382. emitlab(noreraiselabel);
  2383. end;
  2384. { call __EXIT for main program }
  2385. if (not DLLsource) and (not inlined) and (aktprocdef.proctypeoption=potype_proginit) then
  2386. begin
  2387. emitcall('FPC_DO_EXIT');
  2388. end;
  2389. { handle return value, this is not done for assembler routines when
  2390. they didn't reference the result variable }
  2391. uses_eax:=false;
  2392. uses_edx:=false;
  2393. uses_esi:=false;
  2394. if not(po_assembler in aktprocdef.procoptions) or
  2395. (assigned(aktprocdef.funcretsym) and
  2396. (tfuncretsym(aktprocdef.funcretsym).refcount>1)) then
  2397. begin
  2398. if (aktprocdef.proctypeoption<>potype_constructor) then
  2399. handle_return_value(inlined,uses_eax,uses_edx)
  2400. else
  2401. begin
  2402. { successful constructor deletes the zero flag }
  2403. { and returns self in eax }
  2404. { eax must be set to zero if the allocation failed !!! }
  2405. getlabel(okexitlabel);
  2406. emitjmp(C_NONE,okexitlabel);
  2407. emitlab(faillabel);
  2408. if is_class(procinfo^._class) then
  2409. begin
  2410. emit_ref_reg(A_MOV,S_L,new_reference(procinfo^.framepointer,8),R_ESI);
  2411. emitcall('FPC_HELP_FAIL_CLASS');
  2412. end
  2413. else if is_object(procinfo^._class) then
  2414. begin
  2415. emit_ref_reg(A_MOV,S_L,new_reference(procinfo^.framepointer,12),R_ESI);
  2416. getexplicitregister32(R_EDI);
  2417. emit_const_reg(A_MOV,S_L,procinfo^._class.vmt_offset,R_EDI);
  2418. emitcall('FPC_HELP_FAIL');
  2419. ungetregister32(R_EDI);
  2420. end
  2421. else
  2422. Internalerror(200006161);
  2423. emitlab(okexitlabel);
  2424. { for classes this is done after the call to }
  2425. { AfterConstruction }
  2426. if is_object(procinfo^._class) then
  2427. begin
  2428. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  2429. emit_reg_reg(A_MOV,S_L,R_ESI,R_EAX);
  2430. uses_eax:=true;
  2431. end;
  2432. emit_reg_reg(A_TEST,S_L,R_ESI,R_ESI);
  2433. uses_esi:=true;
  2434. end;
  2435. end;
  2436. if aktexit2label.is_used and not aktexit2label.is_set then
  2437. emitlab(aktexit2label);
  2438. if ((cs_debuginfo in aktmoduleswitches) and not inlined) then
  2439. begin
  2440. getlabel(stabsendlabel);
  2441. emitlab(stabsendlabel);
  2442. end;
  2443. { gives problems for long mangled names }
  2444. {List.concat(Tai_symbol.Create(aktprocdef.mangledname+'_end'));}
  2445. { should we restore edi ? }
  2446. { for all i386 gcc implementations }
  2447. if (po_savestdregs in aktprocdef.procoptions) then
  2448. begin
  2449. if (aktprocdef.usedregisters and ($80 shr byte(R_EBX)))<>0 then
  2450. exprasmList.concat(Taicpu.Op_reg(A_POP,S_L,R_EBX));
  2451. exprasmList.concat(Taicpu.Op_reg(A_POP,S_L,R_ESI));
  2452. exprasmList.concat(Taicpu.Op_reg(A_POP,S_L,R_EDI));
  2453. { here we could reset R_EBX
  2454. but that is risky because it only works
  2455. if genexitcode is called after genentrycode
  2456. so lets skip this for the moment PM
  2457. aktprocdef.usedregisters:=
  2458. aktprocdef.usedregisters or not ($80 shr byte(R_EBX));
  2459. }
  2460. end;
  2461. { for the save all registers we can simply use a pusha,popa which
  2462. push edi,esi,ebp,esp(ignored),ebx,edx,ecx,eax }
  2463. if (po_saveregisters in aktprocdef.procoptions) then
  2464. begin
  2465. if uses_esi then
  2466. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_ESI,new_reference(R_ESP,4)));
  2467. if uses_edx then
  2468. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDX,new_reference(R_ESP,20)));
  2469. if uses_eax then
  2470. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EAX,new_reference(R_ESP,28)));
  2471. exprasmList.concat(Taicpu.Op_none(A_POPA,S_L));
  2472. { We add a NOP because of the 386DX CPU bugs with POPAD }
  2473. exprasmlist.concat(taicpu.op_none(A_NOP,S_L));
  2474. end;
  2475. if not(nostackframe) then
  2476. begin
  2477. if not inlined then
  2478. exprasmList.concat(Taicpu.Op_none(A_LEAVE,S_NO));
  2479. end
  2480. else
  2481. begin
  2482. if (gettempsize<>0) and not inlined then
  2483. exprasmList.insert(Taicpu.op_const_reg(A_ADD,S_L,gettempsize,R_ESP));
  2484. end;
  2485. { parameters are limited to 65535 bytes because }
  2486. { ret allows only imm16 }
  2487. if (parasize>65535) and not(po_clearstack in aktprocdef.procoptions) then
  2488. CGMessage(cg_e_parasize_too_big);
  2489. { at last, the return is generated }
  2490. if not inlined then
  2491. if (po_interrupt in aktprocdef.procoptions) then
  2492. begin
  2493. if uses_esi then
  2494. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_ESI,new_reference(R_ESP,16)));
  2495. if uses_edx then
  2496. begin
  2497. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  2498. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDX,new_reference(R_ESP,12)));
  2499. end;
  2500. if uses_eax then
  2501. begin
  2502. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  2503. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EAX,new_reference(R_ESP,0)));
  2504. end;
  2505. generate_interrupt_stackframe_exit;
  2506. end
  2507. else
  2508. begin
  2509. {Routines with the poclearstack flag set use only a ret.}
  2510. { also routines with parasize=0 }
  2511. if (po_clearstack in aktprocdef.procoptions) then
  2512. begin
  2513. {$ifndef OLD_C_STACK}
  2514. { complex return values are removed from stack in C code PM }
  2515. if ret_in_param(aktprocdef.rettype.def) then
  2516. exprasmList.concat(Taicpu.Op_const(A_RET,S_NO,4))
  2517. else
  2518. {$endif not OLD_C_STACK}
  2519. exprasmList.concat(Taicpu.Op_none(A_RET,S_NO));
  2520. end
  2521. else if (parasize=0) then
  2522. exprasmList.concat(Taicpu.Op_none(A_RET,S_NO))
  2523. else
  2524. exprasmList.concat(Taicpu.Op_const(A_RET,S_NO,parasize));
  2525. end;
  2526. if not inlined then
  2527. exprasmList.concat(Tai_symbol_end.Createname(aktprocdef.mangledname));
  2528. {$ifdef GDB}
  2529. if (cs_debuginfo in aktmoduleswitches) and not inlined then
  2530. begin
  2531. aktprocdef.concatstabto(exprasmlist);
  2532. if assigned(procinfo^._class) then
  2533. if (not assigned(procinfo^.parent) or
  2534. not assigned(procinfo^.parent^._class)) then
  2535. begin
  2536. if (po_classmethod in aktprocdef.procoptions) or
  2537. ((po_virtualmethod in aktprocdef.procoptions) and
  2538. (potype_constructor=aktprocdef.proctypeoption)) or
  2539. (po_staticmethod in aktprocdef.procoptions) then
  2540. begin
  2541. exprasmList.concat(Tai_stabs.Create(strpnew(
  2542. '"pvmt:p'+tstoreddef(pvmttype.def).numberstring+'",'+
  2543. tostr(N_tsym)+',0,0,'+tostr(procinfo^.selfpointer_offset))));
  2544. end
  2545. else
  2546. begin
  2547. if not(is_class(procinfo^._class)) then
  2548. st:='v'
  2549. else
  2550. st:='p';
  2551. exprasmList.concat(Tai_stabs.Create(strpnew(
  2552. '"$t:'+st+procinfo^._class.numberstring+'",'+
  2553. tostr(N_tsym)+',0,0,'+tostr(procinfo^.selfpointer_offset))));
  2554. end;
  2555. end
  2556. else
  2557. begin
  2558. if not is_class(procinfo^._class) then
  2559. st:='*'
  2560. else
  2561. st:='';
  2562. exprasmList.concat(Tai_stabs.Create(strpnew(
  2563. '"$t:r'+st+procinfo^._class.numberstring+'",'+
  2564. tostr(N_RSYM)+',0,0,'+tostr(GDB_i386index[R_ESI]))));
  2565. end;
  2566. { define calling EBP as pseudo local var PM }
  2567. { this enables test if the function is a local one !! }
  2568. if assigned(procinfo^.parent) and (lexlevel>normal_function_level) then
  2569. exprasmList.concat(Tai_stabs.Create(strpnew(
  2570. '"parent_ebp:'+tstoreddef(voidpointertype.def).numberstring+'",'+
  2571. tostr(N_LSYM)+',0,0,'+tostr(procinfo^.framepointer_offset))));
  2572. if (not is_void(aktprocdef.rettype.def)) then
  2573. begin
  2574. if ret_in_param(aktprocdef.rettype.def) then
  2575. exprasmList.concat(Tai_stabs.Create(strpnew(
  2576. '"'+aktprocsym.name+':X*'+tstoreddef(aktprocdef.rettype.def).numberstring+'",'+
  2577. tostr(N_tsym)+',0,0,'+tostr(procinfo^.return_offset))))
  2578. else
  2579. exprasmList.concat(Tai_stabs.Create(strpnew(
  2580. '"'+aktprocsym.name+':X'+tstoreddef(aktprocdef.rettype.def).numberstring+'",'+
  2581. tostr(N_tsym)+',0,0,'+tostr(procinfo^.return_offset))));
  2582. if (m_result in aktmodeswitches) then
  2583. if ret_in_param(aktprocdef.rettype.def) then
  2584. exprasmList.concat(Tai_stabs.Create(strpnew(
  2585. '"RESULT:X*'+tstoreddef(aktprocdef.rettype.def).numberstring+'",'+
  2586. tostr(N_tsym)+',0,0,'+tostr(procinfo^.return_offset))))
  2587. else
  2588. exprasmList.concat(Tai_stabs.Create(strpnew(
  2589. '"RESULT:X'+tstoreddef(aktprocdef.rettype.def).numberstring+'",'+
  2590. tostr(N_tsym)+',0,0,'+tostr(procinfo^.return_offset))));
  2591. end;
  2592. mangled_length:=length(aktprocdef.mangledname);
  2593. getmem(p,2*mangled_length+50);
  2594. strpcopy(p,'192,0,0,');
  2595. strpcopy(strend(p),aktprocdef.mangledname);
  2596. if (target_info.use_function_relative_addresses) then
  2597. begin
  2598. strpcopy(strend(p),'-');
  2599. strpcopy(strend(p),aktprocdef.mangledname);
  2600. end;
  2601. exprasmList.concat(Tai_stabn.Create(strnew(p)));
  2602. {List.concat(Tai_stabn.Create(strpnew('192,0,0,'
  2603. +aktprocdef.mangledname))));
  2604. p[0]:='2';p[1]:='2';p[2]:='4';
  2605. strpcopy(strend(p),'_end');}
  2606. strpcopy(p,'224,0,0,'+stabsendlabel.name);
  2607. if (target_info.use_function_relative_addresses) then
  2608. begin
  2609. strpcopy(strend(p),'-');
  2610. strpcopy(strend(p),aktprocdef.mangledname);
  2611. end;
  2612. exprasmList.concatlist(withdebuglist);
  2613. exprasmList.concat(Tai_stabn.Create(strnew(p)));
  2614. { strpnew('224,0,0,'
  2615. +aktprocdef.mangledname+'_end'))));}
  2616. freemem(p,2*mangled_length+50);
  2617. end;
  2618. {$endif GDB}
  2619. if inlined then
  2620. cleanup_regvars(exprasmlist);
  2621. exprasmlist:=oldexprasmlist;
  2622. end;
  2623. procedure genimplicitunitfinal(alist : TAAsmoutput);
  2624. begin
  2625. { using current_module.globalsymtable is hopefully }
  2626. { more robust than symtablestack and symtablestack.next }
  2627. tsymtable(current_module.globalsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
  2628. tsymtable(current_module.localsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
  2629. exprasmList.insert(Tai_symbol.Createname_global('FINALIZE$$'+current_module.modulename^,0));
  2630. exprasmList.insert(Tai_symbol.Createname_global(target_info.cprefix+current_module.modulename^+'_finalize',0));
  2631. {$ifdef GDB}
  2632. if (cs_debuginfo in aktmoduleswitches) and
  2633. target_info.use_function_relative_addresses then
  2634. exprasmList.insert(Tai_stab_function_name.Create(strpnew('FINALIZE$$'+current_module.modulename^)));
  2635. {$endif GDB}
  2636. exprasmList.concat(Taicpu.Op_none(A_RET,S_NO));
  2637. aList.concatlist(exprasmlist);
  2638. end;
  2639. procedure genimplicitunitinit(alist : TAAsmoutput);
  2640. begin
  2641. { using current_module.globalsymtable is hopefully }
  2642. { more robust than symtablestack and symtablestack.next }
  2643. tsymtable(current_module.globalsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
  2644. tsymtable(current_module.localsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
  2645. exprasmList.insert(Tai_symbol.Createname_global('INIT$$'+current_module.modulename^,0));
  2646. exprasmList.insert(Tai_symbol.Createname_global(target_info.cprefix+current_module.modulename^+'_init',0));
  2647. {$ifdef GDB}
  2648. if (cs_debuginfo in aktmoduleswitches) and
  2649. target_info.use_function_relative_addresses then
  2650. exprasmList.insert(Tai_stab_function_name.Create(strpnew('INIT$$'+current_module.modulename^)));
  2651. {$endif GDB}
  2652. exprasmList.concat(Taicpu.Op_none(A_RET,S_NO));
  2653. aList.concatlist(exprasmlist);
  2654. end;
  2655. {$ifdef test_dest_loc}
  2656. procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister);
  2657. begin
  2658. if (dest_loc.loc=LOC_CREGISTER) or (dest_loc.loc=LOC_REGISTER) then
  2659. begin
  2660. emit_reg_reg(A_MOV,s,reg,dest_loc.register);
  2661. set_location(p^.location,dest_loc);
  2662. in_dest_loc:=true;
  2663. end
  2664. else
  2665. if (dest_loc.loc=LOC_REFERENCE) or (dest_loc.loc=LOC_MEM) then
  2666. begin
  2667. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,s,reg,newreference(dest_loc.reference)));
  2668. set_location(p^.location,dest_loc);
  2669. in_dest_loc:=true;
  2670. end
  2671. else
  2672. internalerror(20080);
  2673. end;
  2674. {$endif test_dest_loc}
  2675. end.
  2676. {
  2677. $Log$
  2678. Revision 1.16 2002-03-04 19:10:12 peter
  2679. * removed compiler warnings
  2680. Revision 1.15 2002/01/24 18:25:53 peter
  2681. * implicit result variable generation for assembler routines
  2682. * removed m_tp modeswitch, use m_tp7 or not(m_fpc) instead
  2683. Revision 1.14 2002/01/19 14:21:17 peter
  2684. * fixed init/final for value parameters
  2685. Revision 1.13 2001/12/30 17:24:45 jonas
  2686. * range checking is now processor independent (part in cgobj,
  2687. part in cg64f32) and should work correctly again (it needed
  2688. some changes after the changes of the low and high of
  2689. tordef's to int64)
  2690. * maketojumpbool() is now processor independent (in ncgutil)
  2691. * getregister32 is now called getregisterint
  2692. Revision 1.12 2001/12/29 15:28:58 jonas
  2693. * powerpc/cgcpu.pas compiles :)
  2694. * several powerpc-related fixes
  2695. * cpuasm unit is now based on common tainst unit
  2696. + nppcmat unit for powerpc (almost complete)
  2697. Revision 1.11 2001/11/18 18:59:59 peter
  2698. * changed aktprocsym to aktprocdef for stabs generation
  2699. Revision 1.10 2001/11/06 16:39:02 jonas
  2700. * moved call to "cleanup_regvars" to cga.pas for i386 because it has
  2701. to insert "fstp %st0" instructions after the exit label
  2702. Revision 1.9 2001/11/02 22:58:09 peter
  2703. * procsym definition rewrite
  2704. Revision 1.8 2001/10/25 21:22:41 peter
  2705. * calling convention rewrite
  2706. Revision 1.7 2001/10/20 17:22:57 peter
  2707. * concatcopy could release a wrong reference because the offset was
  2708. increased without restoring the original before the release of
  2709. a temp
  2710. Revision 1.6 2001/10/14 11:49:51 jonas
  2711. * finetuned register allocation info for assignments
  2712. Revision 1.5 2001/09/30 21:28:34 peter
  2713. * int64->boolean fixed
  2714. Revision 1.4 2001/08/30 20:13:57 peter
  2715. * rtti/init table updates
  2716. * rttisym for reusable global rtti/init info
  2717. * support published for interfaces
  2718. Revision 1.3 2001/08/29 12:01:47 jonas
  2719. + support for int64 LOC_REGISTERS in remove_non_regvars_from_loc
  2720. Revision 1.2 2001/08/26 13:36:52 florian
  2721. * some cg reorganisation
  2722. * some PPC updates
  2723. Revision 1.29 2001/08/12 20:23:02 peter
  2724. * netbsd doesn't use stackchecking
  2725. Revision 1.28 2001/08/07 18:47:13 peter
  2726. * merged netbsd start
  2727. * profile for win32
  2728. Revision 1.27 2001/08/06 21:40:49 peter
  2729. * funcret moved from tprocinfo to tprocdef
  2730. Revision 1.26 2001/07/30 20:59:28 peter
  2731. * m68k updates from v10 merged
  2732. Revision 1.25 2001/07/01 20:16:18 peter
  2733. * alignmentinfo record added
  2734. * -Oa argument supports more alignment settings that can be specified
  2735. per type: PROC,LOOP,VARMIN,VARMAX,CONSTMIN,CONSTMAX,RECORDMIN
  2736. RECORDMAX,LOCALMIN,LOCALMAX. It is possible to set the mimimum
  2737. required alignment and the maximum usefull alignment. The final
  2738. alignment will be choosen per variable size dependent on these
  2739. settings
  2740. Revision 1.24 2001/05/27 14:30:55 florian
  2741. + some widestring stuff added
  2742. Revision 1.23 2001/04/21 13:33:16 peter
  2743. * move winstackpagesize const to cgai386 to remove uses t_win32
  2744. Revision 1.22 2001/04/21 12:05:32 peter
  2745. * add nop after popa (merged)
  2746. Revision 1.21 2001/04/18 22:02:00 peter
  2747. * registration of targets and assemblers
  2748. Revision 1.20 2001/04/13 01:22:17 peter
  2749. * symtable change to classes
  2750. * range check generation and errors fixed, make cycle DEBUG=1 works
  2751. * memory leaks fixed
  2752. Revision 1.19 2001/04/05 21:33:07 peter
  2753. * fast exit fix merged
  2754. Revision 1.18 2001/04/02 21:20:35 peter
  2755. * resulttype rewrite
  2756. Revision 1.17 2001/01/05 17:36:58 florian
  2757. * the info about exception frames is stored now on the stack
  2758. instead on the heap
  2759. Revision 1.16 2000/12/25 00:07:31 peter
  2760. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  2761. tlinkedlist objects)
  2762. Revision 1.15 2000/12/05 11:44:32 jonas
  2763. + new integer regvar handling, should be much more efficient
  2764. Revision 1.14 2000/11/29 00:30:43 florian
  2765. * unused units removed from uses clause
  2766. * some changes for widestrings
  2767. Revision 1.13 2000/11/28 00:28:07 pierre
  2768. * stabs fixing
  2769. Revision 1.12 2000/11/22 15:12:06 jonas
  2770. * fixed inline-related problems (partially "merges")
  2771. Revision 1.11 2000/11/17 10:30:24 florian
  2772. * passing interfaces as parameters fixed
  2773. Revision 1.10 2000/11/07 23:40:48 florian
  2774. + AfterConstruction and BeforeDestruction impemented
  2775. Revision 1.9 2000/11/06 23:49:20 florian
  2776. * fixed init_paras call
  2777. Revision 1.8 2000/11/06 23:15:01 peter
  2778. * added copyvaluepara call again
  2779. Revision 1.7 2000/11/04 14:25:23 florian
  2780. + merged Attila's changes for interfaces, not tested yet
  2781. Revision 1.6 2000/10/31 22:02:55 peter
  2782. * symtable splitted, no real code changes
  2783. Revision 1.5 2000/10/24 22:23:04 peter
  2784. * emitcall -> emitinsertcall for profiling (merged)
  2785. Revision 1.4 2000/10/24 12:47:45 jonas
  2786. * allocate registers which hold function result
  2787. Revision 1.3 2000/10/24 08:54:25 michael
  2788. + Extra patch from peter
  2789. Revision 1.2 2000/10/24 07:20:03 pierre
  2790. * fix for bug 1193 (merged)
  2791. Revision 1.1 2000/10/15 09:47:42 peter
  2792. * moved to i386/
  2793. Revision 1.19 2000/10/14 10:14:46 peter
  2794. * moehrendorf oct 2000 rewrite
  2795. Revision 1.18 2000/10/10 14:55:28 jonas
  2796. * added missing regallocs for edi in emit_mov_ref_reg64 (merged)
  2797. Revision 1.17 2000/10/01 19:48:23 peter
  2798. * lot of compile updates for cg11
  2799. Revision 1.16 2000/09/30 16:08:45 peter
  2800. * more cg11 updates
  2801. Revision 1.15 2000/09/24 15:06:12 peter
  2802. * use defines.inc
  2803. Revision 1.14 2000/09/16 12:22:52 peter
  2804. * freebsd support merged
  2805. Revision 1.13 2000/08/27 16:11:49 peter
  2806. * moved some util functions from globals,cobjects to cutils
  2807. * splitted files into finput,fmodule
  2808. Revision 1.12 2000/08/24 19:07:54 peter
  2809. * don't initialize if localvarsym is set because that varsym will
  2810. already be initialized
  2811. * first initialize local data before copy of value para's (merged)
  2812. Revision 1.11 2000/08/19 20:09:33 peter
  2813. * check size after checking openarray in push_value_para (merged)
  2814. Revision 1.10 2000/08/16 13:06:06 florian
  2815. + support of 64 bit integer constants
  2816. Revision 1.9 2000/08/10 18:42:03 peter
  2817. * fixed for constants in emit_push_mem_size for go32v2 (merged)
  2818. Revision 1.8 2000/08/07 11:29:40 jonas
  2819. + emit_push_mem_size() which pushes a value in memory of a certain size
  2820. * pushsetelement() and pushvaluepara() use this new procedure, because
  2821. otherwise they could sometimes try to push data past the end of the
  2822. heap, causing a crash
  2823. (merged from fixes branch)
  2824. Revision 1.7 2000/08/03 13:17:25 jonas
  2825. + allow regvars to be used inside inlined procs, which required the
  2826. following changes:
  2827. + load regvars in genentrycode/free them in genexitcode (cgai386)
  2828. * moved all regvar related code to new regvars unit
  2829. + added pregvarinfo type to hcodegen
  2830. + added regvarinfo field to tprocinfo (symdef/symdefh)
  2831. * deallocate the regvars of the caller in secondprocinline before
  2832. inlining the called procedure and reallocate them afterwards
  2833. Revision 1.6 2000/08/02 08:05:04 jonas
  2834. * fixed web bug1087
  2835. * allocate R_ECX explicitely if it's used
  2836. (merged from fixes branch)
  2837. Revision 1.5 2000/07/27 09:25:05 jonas
  2838. * moved locflags2reg() procedure from cg386add to cgai386
  2839. + added locjump2reg() procedure to cgai386
  2840. * fixed internalerror(2002) when the result of a case expression has
  2841. LOC_JUMP
  2842. (all merged from fixes branch)
  2843. Revision 1.4 2000/07/21 15:14:02 jonas
  2844. + added is_addr field for labels, if they are only used for getting the address
  2845. (e.g. for io checks) and corresponding getaddrlabel() procedure
  2846. Revision 1.3 2000/07/13 12:08:25 michael
  2847. + patched to 1.1.0 with former 1.09patch from peter
  2848. Revision 1.2 2000/07/13 11:32:37 michael
  2849. + removed logs
  2850. }