2
0

ncgutil.pas 129 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Helper routines for all code generators
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit ncgutil;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. node,cpuinfo,
  22. globtype,
  23. cpubase,cgbase,parabase,cgutils,
  24. aasmbase,aasmtai,aasmdata,aasmcpu,
  25. symconst,symbase,symdef,symsym,symtype,symtable
  26. {$ifndef cpu64bitalu}
  27. ,cg64f32
  28. {$endif not cpu64bitalu}
  29. ;
  30. type
  31. tloadregvars = (lr_dont_load_regvars, lr_load_regvars);
  32. pusedregvars = ^tusedregvars;
  33. tusedregvars = record
  34. intregvars, fpuregvars, mmregvars: Tsuperregisterworklist;
  35. end;
  36. {
  37. Not used currently, implemented because I thought we had to
  38. synchronise around if/then/else as well, but not needed. May
  39. still be useful for SSA once we get around to implementing
  40. that (JM)
  41. pusedregvarscommon = ^tusedregvarscommon;
  42. tusedregvarscommon = record
  43. allregvars, commonregvars, myregvars: tusedregvars;
  44. end;
  45. }
  46. procedure firstcomplex(p : tbinarynode);
  47. procedure maketojumpbool(list:TAsmList; p : tnode; loadregvars: tloadregvars);
  48. // procedure remove_non_regvars_from_loc(const t: tlocation; var regs:Tsuperregisterset);
  49. procedure location_force_reg(list:TAsmList;var l:tlocation;dst_size:TCGSize;maybeconst:boolean);
  50. procedure location_force_fpureg(list:TAsmList;var l: tlocation;maybeconst:boolean);
  51. procedure location_force_mem(list:TAsmList;var l:tlocation);
  52. procedure location_force_mmregscalar(list:TAsmList;var l: tlocation;maybeconst:boolean);
  53. procedure location_force_mmreg(list:TAsmList;var l: tlocation;maybeconst:boolean);
  54. procedure location_allocate_register(list:TAsmList;out l: tlocation;def: tdef;constant: boolean);
  55. { load a tlocation into a cgpara }
  56. procedure gen_load_loc_cgpara(list: TAsmList; vardef: tdef; const l: tlocation; const cgpara: tcgpara);
  57. { loads a cgpara into a tlocation; assumes that loc.loc is already
  58. initialised }
  59. procedure gen_load_cgpara_loc(list: TAsmList; vardef: tdef; const para: TCGPara; var destloc: tlocation; reusepara: boolean);
  60. { allocate registers for a tlocation; assumes that loc.loc is already
  61. set to LOC_CREGISTER/LOC_CFPUREGISTER/... }
  62. procedure gen_alloc_regloc(list:TAsmList;var loc: tlocation);
  63. procedure register_maybe_adjust_setbase(list: TAsmList; var l: tlocation; setbase: aint);
  64. { Retrieve the location of the data pointed to in location l, when the location is
  65. a register it is expected to contain the address of the data }
  66. procedure location_get_data_ref(list:TAsmList;const l:tlocation;var ref:treference;loadref:boolean; alignment: longint);
  67. function has_alias_name(pd:tprocdef;const s:string):boolean;
  68. procedure alloc_proc_symbol(pd: tprocdef);
  69. procedure gen_proc_symbol(list:TAsmList);
  70. procedure gen_proc_symbol_end(list:TAsmList);
  71. procedure gen_proc_entry_code(list:TAsmList);
  72. procedure gen_proc_exit_code(list:TAsmList);
  73. procedure gen_stack_check_size_para(list:TAsmList);
  74. procedure gen_stack_check_call(list:TAsmList);
  75. procedure gen_save_used_regs(list:TAsmList);
  76. procedure gen_restore_used_regs(list:TAsmList);
  77. procedure gen_initialize_code(list:TAsmList);
  78. procedure gen_finalize_code(list:TAsmList);
  79. procedure gen_entry_code(list:TAsmList);
  80. procedure gen_exit_code(list:TAsmList);
  81. procedure gen_load_para_value(list:TAsmList);
  82. procedure gen_load_return_value(list:TAsmList);
  83. procedure gen_external_stub(list:TAsmList;pd:tprocdef;const externalname:string);
  84. procedure gen_intf_wrappers(list:TAsmList;st:TSymtable;nested:boolean);
  85. procedure gen_load_vmt_register(list:TAsmList;objdef:tobjectdef;selfloc:tlocation;var vmtreg:tregister);
  86. procedure get_used_regvars(n: tnode; var rv: tusedregvars);
  87. { adds the regvars used in n and its children to rv.allregvars,
  88. those which were already in rv.allregvars to rv.commonregvars and
  89. uses rv.myregvars as scratch (so that two uses of the same regvar
  90. in a single tree to make it appear in commonregvars). Useful to
  91. find out which regvars are used in two different node trees
  92. (e.g. in the "else" and "then" path, or in various case blocks }
  93. // procedure get_used_regvars_common(n: tnode; var rv: tusedregvarscommon);
  94. procedure gen_sync_regvars(list:TAsmList; var rv: tusedregvars);
  95. { if the result of n is a LOC_C(..)REGISTER, try to find the corresponding }
  96. { loadn and change its location to a new register (= SSA). In case reload }
  97. { is true, transfer the old to the new register }
  98. procedure maybechangeloadnodereg(list: TAsmList; var n: tnode; reload: boolean);
  99. {#
  100. Allocate the buffers for exception management and setjmp environment.
  101. Return a pointer to these buffers, send them to the utility routine
  102. so they are registered, and then call setjmp.
  103. Then compare the result of setjmp with 0, and if not equal
  104. to zero, then jump to exceptlabel.
  105. Also store the result of setjmp to a temporary space by calling g_save_exception_reason
  106. It is to note that this routine may be called *after* the stackframe of a
  107. routine has been called, therefore on machines where the stack cannot
  108. be modified, all temps should be allocated on the heap instead of the
  109. stack.
  110. }
  111. const
  112. EXCEPT_BUF_SIZE = 3*sizeof(pint);
  113. type
  114. texceptiontemps=record
  115. jmpbuf,
  116. envbuf,
  117. reasonbuf : treference;
  118. end;
  119. procedure get_exception_temps(list:TAsmList;var t:texceptiontemps);
  120. procedure unget_exception_temps(list:TAsmList;const t:texceptiontemps);
  121. procedure new_exception(list:TAsmList;const t:texceptiontemps;exceptlabel:tasmlabel);
  122. procedure free_exception(list:TAsmList;const t:texceptiontemps;a:aint;endexceptlabel:tasmlabel;onlyfree:boolean);
  123. procedure insertbssdata(sym : tstaticvarsym);
  124. procedure gen_alloc_symtable(list:TAsmList;st:TSymtable);
  125. procedure gen_free_symtable(list:TAsmList;st:TSymtable);
  126. procedure location_free(list: TAsmList; const location : TLocation);
  127. function getprocalign : shortint;
  128. procedure gen_fpc_dummy(list : TAsmList);
  129. procedure InsertInterruptTable;
  130. implementation
  131. uses
  132. version,
  133. cutils,cclasses,
  134. globals,systems,verbose,export,
  135. ppu,defutil,
  136. procinfo,paramgr,fmodule,
  137. regvars,dbgbase,
  138. pass_1,pass_2,
  139. nbas,ncon,nld,nmem,nutils,
  140. tgobj,cgobj,cgcpu
  141. {$ifdef powerpc}
  142. , cpupi
  143. {$endif}
  144. {$ifdef powerpc64}
  145. , cpupi
  146. {$endif}
  147. {$ifdef SUPPORT_MMX}
  148. , cgx86
  149. {$endif SUPPORT_MMX}
  150. ;
  151. {*****************************************************************************
  152. Misc Helpers
  153. *****************************************************************************}
  154. {$if first_mm_imreg = 0}
  155. {$WARN 4044 OFF} { Comparison might be always false ... }
  156. {$endif}
  157. procedure location_free(list: TAsmList; const location : TLocation);
  158. begin
  159. case location.loc of
  160. LOC_VOID:
  161. ;
  162. LOC_REGISTER,
  163. LOC_CREGISTER:
  164. begin
  165. {$ifdef cpu64bitaddr}
  166. { x86-64 system v abi:
  167. structs with up to 16 bytes are returned in registers }
  168. if location.size in [OS_128,OS_S128] then
  169. begin
  170. if getsupreg(location.register)<first_int_imreg then
  171. cg.ungetcpuregister(list,location.register);
  172. if getsupreg(location.registerhi)<first_int_imreg then
  173. cg.ungetcpuregister(list,location.registerhi);
  174. end
  175. {$else cpu64bitaddr}
  176. if location.size in [OS_64,OS_S64] then
  177. begin
  178. if getsupreg(location.register64.reglo)<first_int_imreg then
  179. cg.ungetcpuregister(list,location.register64.reglo);
  180. if getsupreg(location.register64.reghi)<first_int_imreg then
  181. cg.ungetcpuregister(list,location.register64.reghi);
  182. end
  183. {$endif}
  184. else
  185. if getsupreg(location.register)<first_int_imreg then
  186. cg.ungetcpuregister(list,location.register);
  187. end;
  188. LOC_FPUREGISTER,
  189. LOC_CFPUREGISTER:
  190. begin
  191. if getsupreg(location.register)<first_fpu_imreg then
  192. cg.ungetcpuregister(list,location.register);
  193. end;
  194. LOC_MMREGISTER,
  195. LOC_CMMREGISTER :
  196. begin
  197. if getsupreg(location.register)<first_mm_imreg then
  198. cg.ungetcpuregister(list,location.register);
  199. end;
  200. LOC_REFERENCE,
  201. LOC_CREFERENCE :
  202. begin
  203. if paramanager.use_fixed_stack then
  204. location_freetemp(list,location);
  205. end;
  206. else
  207. internalerror(2004110211);
  208. end;
  209. end;
  210. procedure firstcomplex(p : tbinarynode);
  211. var
  212. fcl, fcr: longint;
  213. ncl, ncr: longint;
  214. begin
  215. { always calculate boolean AND and OR from left to right }
  216. if (p.nodetype in [orn,andn]) and
  217. is_boolean(p.left.resultdef) then
  218. begin
  219. if nf_swapped in p.flags then
  220. internalerror(200709253);
  221. end
  222. else
  223. begin
  224. fcl:=node_resources_fpu(p.left);
  225. fcr:=node_resources_fpu(p.right);
  226. ncl:=node_complexity(p.left);
  227. ncr:=node_complexity(p.right);
  228. { We swap left and right if
  229. a) right needs more floating point registers than left, and
  230. left needs more than 0 floating point registers (if it
  231. doesn't need any, swapping won't change the floating
  232. point register pressure)
  233. b) both left and right need an equal amount of floating
  234. point registers or right needs no floating point registers,
  235. and in addition right has a higher complexity than left
  236. (+- needs more integer registers, but not necessarily)
  237. }
  238. if ((fcr>fcl) and
  239. (fcl>0)) or
  240. (((fcr=fcl) or
  241. (fcr=0)) and
  242. (ncr>ncl)) then
  243. p.swapleftright
  244. end;
  245. end;
  246. procedure maketojumpbool(list:TAsmList; p : tnode; loadregvars: tloadregvars);
  247. {
  248. produces jumps to true respectively false labels using boolean expressions
  249. depending on whether the loading of regvars is currently being
  250. synchronized manually (such as in an if-node) or automatically (most of
  251. the other cases where this procedure is called), loadregvars can be
  252. "lr_load_regvars" or "lr_dont_load_regvars"
  253. }
  254. var
  255. opsize : tcgsize;
  256. storepos : tfileposinfo;
  257. tmpreg : tregister;
  258. begin
  259. if nf_error in p.flags then
  260. exit;
  261. storepos:=current_filepos;
  262. current_filepos:=p.fileinfo;
  263. if is_boolean(p.resultdef) then
  264. begin
  265. {$ifdef OLDREGVARS}
  266. if loadregvars = lr_load_regvars then
  267. load_all_regvars(list);
  268. {$endif OLDREGVARS}
  269. if is_constboolnode(p) then
  270. begin
  271. if Tordconstnode(p).value.uvalue<>0 then
  272. cg.a_jmp_always(list,current_procinfo.CurrTrueLabel)
  273. else
  274. cg.a_jmp_always(list,current_procinfo.CurrFalseLabel)
  275. end
  276. else
  277. begin
  278. opsize:=def_cgsize(p.resultdef);
  279. case p.location.loc of
  280. LOC_SUBSETREG,LOC_CSUBSETREG,
  281. LOC_SUBSETREF,LOC_CSUBSETREF:
  282. begin
  283. tmpreg := cg.getintregister(list,OS_INT);
  284. cg.a_load_loc_reg(list,OS_INT,p.location,tmpreg);
  285. cg.a_cmp_const_reg_label(list,OS_INT,OC_NE,0,tmpreg,current_procinfo.CurrTrueLabel);
  286. cg.a_jmp_always(list,current_procinfo.CurrFalseLabel);
  287. end;
  288. LOC_CREGISTER,LOC_REGISTER,LOC_CREFERENCE,LOC_REFERENCE :
  289. begin
  290. {$ifndef cpu64bitalu}
  291. if opsize in [OS_64,OS_S64] then
  292. begin
  293. location_force_reg(list,p.location,opsize,true);
  294. tmpreg:=cg.getintregister(list,OS_32);
  295. cg.a_op_reg_reg_reg(list,OP_OR,OS_32,p.location.register64.reglo,p.location.register64.reghi,tmpreg);
  296. location_reset(p.location,LOC_REGISTER,OS_32);
  297. p.location.register:=tmpreg;
  298. opsize:=OS_32;
  299. end;
  300. {$endif not cpu64bitalu}
  301. cg.a_cmp_const_loc_label(list,opsize,OC_NE,0,p.location,current_procinfo.CurrTrueLabel);
  302. cg.a_jmp_always(list,current_procinfo.CurrFalseLabel);
  303. end;
  304. LOC_JUMP:
  305. ;
  306. {$ifdef cpuflags}
  307. LOC_FLAGS :
  308. begin
  309. cg.a_jmp_flags(list,p.location.resflags,current_procinfo.CurrTrueLabel);
  310. cg.a_jmp_always(list,current_procinfo.CurrFalseLabel);
  311. end;
  312. {$endif cpuflags}
  313. else
  314. begin
  315. printnode(output,p);
  316. internalerror(200308241);
  317. end;
  318. end;
  319. end;
  320. end
  321. else
  322. internalerror(200112305);
  323. current_filepos:=storepos;
  324. end;
  325. (*
  326. This code needs fixing. It is not safe to use rgint; on the m68000 it
  327. would be rgaddr.
  328. procedure remove_non_regvars_from_loc(const t: tlocation; var regs:Tsuperregisterset);
  329. begin
  330. case t.loc of
  331. LOC_REGISTER:
  332. begin
  333. { can't be a regvar, since it would be LOC_CREGISTER then }
  334. exclude(regs,getsupreg(t.register));
  335. if t.register64.reghi<>NR_NO then
  336. exclude(regs,getsupreg(t.register64.reghi));
  337. end;
  338. LOC_CREFERENCE,LOC_REFERENCE:
  339. begin
  340. if not(cs_opt_regvar in current_settings.optimizerswitches) or
  341. (getsupreg(t.reference.base) in cg.rgint.usableregs) then
  342. exclude(regs,getsupreg(t.reference.base));
  343. if not(cs_opt_regvar in current_settings.optimizerswitches) or
  344. (getsupreg(t.reference.index) in cg.rgint.usableregs) then
  345. exclude(regs,getsupreg(t.reference.index));
  346. end;
  347. end;
  348. end;
  349. *)
  350. {*****************************************************************************
  351. EXCEPTION MANAGEMENT
  352. *****************************************************************************}
  353. procedure get_exception_temps(list:TAsmList;var t:texceptiontemps);
  354. var
  355. srsym : ttypesym;
  356. begin
  357. if jmp_buf_size=-1 then
  358. begin
  359. srsym:=search_system_type('JMP_BUF');
  360. jmp_buf_size:=srsym.typedef.size;
  361. jmp_buf_align:=srsym.typedef.alignment;
  362. end;
  363. tg.GetTemp(list,EXCEPT_BUF_SIZE,sizeof(pint),tt_persistent,t.envbuf);
  364. tg.GetTemp(list,jmp_buf_size,jmp_buf_align,tt_persistent,t.jmpbuf);
  365. tg.GetTemp(list,sizeof(pint),sizeof(pint),tt_persistent,t.reasonbuf);
  366. end;
  367. procedure unget_exception_temps(list:TAsmList;const t:texceptiontemps);
  368. begin
  369. tg.Ungettemp(list,t.jmpbuf);
  370. tg.ungettemp(list,t.envbuf);
  371. tg.ungettemp(list,t.reasonbuf);
  372. end;
  373. procedure new_exception(list:TAsmList;const t:texceptiontemps;exceptlabel:tasmlabel);
  374. var
  375. paraloc1,paraloc2,paraloc3 : tcgpara;
  376. begin
  377. paraloc1.init;
  378. paraloc2.init;
  379. paraloc3.init;
  380. paramanager.getintparaloc(pocall_default,1,paraloc1);
  381. paramanager.getintparaloc(pocall_default,2,paraloc2);
  382. paramanager.getintparaloc(pocall_default,3,paraloc3);
  383. cg.a_loadaddr_ref_cgpara(list,t.envbuf,paraloc3);
  384. cg.a_loadaddr_ref_cgpara(list,t.jmpbuf,paraloc2);
  385. { push type of exceptionframe }
  386. cg.a_load_const_cgpara(list,OS_S32,1,paraloc1);
  387. paramanager.freecgpara(list,paraloc3);
  388. paramanager.freecgpara(list,paraloc2);
  389. paramanager.freecgpara(list,paraloc1);
  390. cg.allocallcpuregisters(list);
  391. cg.a_call_name(list,'FPC_PUSHEXCEPTADDR',false);
  392. cg.deallocallcpuregisters(list);
  393. paramanager.getintparaloc(pocall_default,1,paraloc1);
  394. cg.a_load_reg_cgpara(list,OS_ADDR,NR_FUNCTION_RESULT_REG,paraloc1);
  395. paramanager.freecgpara(list,paraloc1);
  396. cg.allocallcpuregisters(list);
  397. cg.a_call_name(list,'FPC_SETJMP',false);
  398. cg.deallocallcpuregisters(list);
  399. cg.alloccpuregisters(list,R_INTREGISTER,[RS_FUNCTION_RESULT_REG]);
  400. cg.g_exception_reason_save(list, t.reasonbuf);
  401. cg.a_cmp_const_reg_label(list,OS_S32,OC_NE,0,cg.makeregsize(list,NR_FUNCTION_RESULT_REG,OS_S32),exceptlabel);
  402. cg.dealloccpuregisters(list,R_INTREGISTER,[RS_FUNCTION_RESULT_REG]);
  403. paraloc1.done;
  404. paraloc2.done;
  405. paraloc3.done;
  406. end;
  407. procedure free_exception(list:TAsmList;const t:texceptiontemps;a:aint;endexceptlabel:tasmlabel;onlyfree:boolean);
  408. begin
  409. cg.allocallcpuregisters(list);
  410. cg.a_call_name(list,'FPC_POPADDRSTACK',false);
  411. cg.deallocallcpuregisters(list);
  412. if not onlyfree then
  413. begin
  414. { g_exception_reason_load already allocates NR_FUNCTION_RESULT_REG }
  415. cg.g_exception_reason_load(list, t.reasonbuf);
  416. cg.a_cmp_const_reg_label(list,OS_INT,OC_EQ,a,NR_FUNCTION_RESULT_REG,endexceptlabel);
  417. cg.a_reg_dealloc(list,NR_FUNCTION_RESULT_REG);
  418. end;
  419. end;
  420. {*****************************************************************************
  421. TLocation
  422. *****************************************************************************}
  423. {$ifndef cpu64bitalu}
  424. { 32-bit version }
  425. procedure location_force_reg(list:TAsmList;var l:tlocation;dst_size:TCGSize;maybeconst:boolean);
  426. var
  427. hregister,
  428. hregisterhi : tregister;
  429. hreg64 : tregister64;
  430. hl : tasmlabel;
  431. oldloc : tlocation;
  432. const_location: boolean;
  433. begin
  434. oldloc:=l;
  435. if dst_size=OS_NO then
  436. internalerror(200309144);
  437. { handle transformations to 64bit separate }
  438. if dst_size in [OS_64,OS_S64] then
  439. begin
  440. if not (l.size in [OS_64,OS_S64]) then
  441. begin
  442. { load a smaller size to OS_64 }
  443. if l.loc=LOC_REGISTER then
  444. begin
  445. {$ifdef AVR}
  446. { on avr, we cannot change the size of a register
  447. due to the nature how register with size > OS8 are handled
  448. }
  449. hregister:=cg.getintregister(list,OS_32);
  450. {$else AVR}
  451. hregister:=cg.makeregsize(list,l.register64.reglo,OS_32);
  452. {$endif AVR}
  453. cg.a_load_reg_reg(list,l.size,OS_32,l.register64.reglo,hregister);
  454. end
  455. else
  456. hregister:=cg.getintregister(list,OS_32);
  457. { load value in low register }
  458. case l.loc of
  459. {$ifdef cpuflags}
  460. LOC_FLAGS :
  461. cg.g_flags2reg(list,OS_INT,l.resflags,hregister);
  462. {$endif cpuflags}
  463. LOC_JUMP :
  464. begin
  465. cg.a_label(list,current_procinfo.CurrTrueLabel);
  466. cg.a_load_const_reg(list,OS_INT,1,hregister);
  467. current_asmdata.getjumplabel(hl);
  468. cg.a_jmp_always(list,hl);
  469. cg.a_label(list,current_procinfo.CurrFalseLabel);
  470. cg.a_load_const_reg(list,OS_INT,0,hregister);
  471. cg.a_label(list,hl);
  472. end;
  473. else
  474. cg.a_load_loc_reg(list,OS_INT,l,hregister);
  475. end;
  476. { reset hi part, take care of the signed bit of the current value }
  477. hregisterhi:=cg.getintregister(list,OS_32);
  478. if (l.size in [OS_S8,OS_S16,OS_S32]) then
  479. begin
  480. if l.loc=LOC_CONSTANT then
  481. begin
  482. if (longint(l.value)<0) then
  483. cg.a_load_const_reg(list,OS_32,aint($ffffffff),hregisterhi)
  484. else
  485. cg.a_load_const_reg(list,OS_32,0,hregisterhi);
  486. end
  487. else
  488. begin
  489. cg.a_op_const_reg_reg(list,OP_SAR,OS_32,31,hregister,
  490. hregisterhi);
  491. end;
  492. end
  493. else
  494. cg.a_load_const_reg(list,OS_32,0,hregisterhi);
  495. location_reset(l,LOC_REGISTER,dst_size);
  496. l.register64.reglo:=hregister;
  497. l.register64.reghi:=hregisterhi;
  498. end
  499. else
  500. begin
  501. { 64bit to 64bit }
  502. if ((l.loc=LOC_CREGISTER) and maybeconst) then
  503. begin
  504. hregister:=l.register64.reglo;
  505. hregisterhi:=l.register64.reghi;
  506. const_location := true;
  507. end
  508. else
  509. begin
  510. hregister:=cg.getintregister(list,OS_32);
  511. hregisterhi:=cg.getintregister(list,OS_32);
  512. const_location := false;
  513. end;
  514. hreg64.reglo:=hregister;
  515. hreg64.reghi:=hregisterhi;
  516. { load value in new register }
  517. cg64.a_load64_loc_reg(list,l,hreg64);
  518. if not const_location then
  519. location_reset(l,LOC_REGISTER,dst_size)
  520. else
  521. location_reset(l,LOC_CREGISTER,dst_size);
  522. l.register64.reglo:=hregister;
  523. l.register64.reghi:=hregisterhi;
  524. end;
  525. end
  526. else
  527. begin
  528. {Do not bother to recycle the existing register. The register
  529. allocator eliminates unnecessary moves, so it's not needed
  530. and trying to recycle registers can cause problems because
  531. the registers changes size and may need aditional constraints.
  532. Not if it's about LOC_CREGISTER's (JM)
  533. }
  534. const_location :=
  535. (maybeconst) and
  536. (l.loc = LOC_CREGISTER) and
  537. (TCGSize2Size[l.size] = TCGSize2Size[dst_size]) and
  538. ((l.size = dst_size) or
  539. (TCGSize2Size[l.size] = sizeof(aint)));
  540. if not const_location then
  541. hregister:=cg.getintregister(list,dst_size)
  542. else
  543. hregister := l.register;
  544. { load value in new register }
  545. case l.loc of
  546. {$ifdef cpuflags}
  547. LOC_FLAGS :
  548. cg.g_flags2reg(list,dst_size,l.resflags,hregister);
  549. {$endif cpuflags}
  550. LOC_JUMP :
  551. begin
  552. cg.a_label(list,current_procinfo.CurrTrueLabel);
  553. cg.a_load_const_reg(list,dst_size,1,hregister);
  554. current_asmdata.getjumplabel(hl);
  555. cg.a_jmp_always(list,hl);
  556. cg.a_label(list,current_procinfo.CurrFalseLabel);
  557. cg.a_load_const_reg(list,dst_size,0,hregister);
  558. cg.a_label(list,hl);
  559. end;
  560. else
  561. begin
  562. { load_loc_reg can only handle size >= l.size, when the
  563. new size is smaller then we need to adjust the size
  564. of the orignal and maybe recalculate l.register for i386 }
  565. if (TCGSize2Size[dst_size]<TCGSize2Size[l.size]) then
  566. begin
  567. if (l.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  568. l.register:=cg.makeregsize(list,l.register,dst_size);
  569. { for big endian systems, the reference's offset must }
  570. { be increased in this case, since they have the }
  571. { MSB first in memory and e.g. byte(word_var) should }
  572. { return the second byte in this case (JM) }
  573. if (target_info.endian = ENDIAN_BIG) and
  574. (l.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  575. begin
  576. inc(l.reference.offset,TCGSize2Size[l.size]-TCGSize2Size[dst_size]);
  577. l.reference.alignment:=newalignment(l.reference.alignment,TCGSize2Size[l.size]-TCGSize2Size[dst_size]);
  578. end;
  579. {$ifdef x86}
  580. if not (l.loc in [LOC_SUBSETREG,LOC_CSUBSETREG]) then
  581. l.size:=dst_size;
  582. {$endif x86}
  583. end;
  584. cg.a_load_loc_reg(list,dst_size,l,hregister);
  585. if (TCGSize2Size[dst_size]<TCGSize2Size[l.size])
  586. {$ifdef x86}
  587. and (l.loc in [LOC_SUBSETREG,LOC_CSUBSETREG])
  588. {$endif x86}
  589. then
  590. l.size:=dst_size;
  591. end;
  592. end;
  593. if not const_location then
  594. location_reset(l,LOC_REGISTER,dst_size)
  595. else
  596. location_reset(l,LOC_CREGISTER,dst_size);
  597. l.register:=hregister;
  598. end;
  599. { Release temp when it was a reference }
  600. if oldloc.loc=LOC_REFERENCE then
  601. location_freetemp(list,oldloc);
  602. end;
  603. {$else not cpu64bitalu}
  604. { 64-bit version }
  605. procedure location_force_reg(list:TAsmList;var l:tlocation;dst_size:TCGSize;maybeconst:boolean);
  606. var
  607. hregister : tregister;
  608. hl : tasmlabel;
  609. oldloc : tlocation;
  610. begin
  611. oldloc:=l;
  612. hregister:=cg.getintregister(list,dst_size);
  613. { load value in new register }
  614. case l.loc of
  615. LOC_FLAGS :
  616. cg.g_flags2reg(list,dst_size,l.resflags,hregister);
  617. LOC_JUMP :
  618. begin
  619. cg.a_label(list,current_procinfo.CurrTrueLabel);
  620. cg.a_load_const_reg(list,dst_size,1,hregister);
  621. current_asmdata.getjumplabel(hl);
  622. cg.a_jmp_always(list,hl);
  623. cg.a_label(list,current_procinfo.CurrFalseLabel);
  624. cg.a_load_const_reg(list,dst_size,0,hregister);
  625. cg.a_label(list,hl);
  626. end;
  627. else
  628. begin
  629. { load_loc_reg can only handle size >= l.size, when the
  630. new size is smaller then we need to adjust the size
  631. of the orignal and maybe recalculate l.register for i386 }
  632. if (TCGSize2Size[dst_size]<TCGSize2Size[l.size]) then
  633. begin
  634. if (l.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  635. l.register:=cg.makeregsize(list,l.register,dst_size);
  636. { for big endian systems, the reference's offset must }
  637. { be increased in this case, since they have the }
  638. { MSB first in memory and e.g. byte(word_var) should }
  639. { return the second byte in this case (JM) }
  640. if (target_info.endian = ENDIAN_BIG) and
  641. (l.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  642. begin
  643. inc(l.reference.offset,TCGSize2Size[l.size]-TCGSize2Size[dst_size]);
  644. l.reference.alignment:=newalignment(l.reference.alignment,TCGSize2Size[l.size]-TCGSize2Size[dst_size]);
  645. end;
  646. {$ifdef x86}
  647. l.size:=dst_size;
  648. {$endif x86}
  649. end;
  650. cg.a_load_loc_reg(list,dst_size,l,hregister);
  651. {$ifndef x86}
  652. if (TCGSize2Size[dst_size]<TCGSize2Size[l.size]) then
  653. l.size:=dst_size;
  654. {$endif not x86}
  655. end;
  656. end;
  657. if (l.loc <> LOC_CREGISTER) or
  658. not maybeconst then
  659. location_reset(l,LOC_REGISTER,dst_size)
  660. else
  661. location_reset(l,LOC_CREGISTER,dst_size);
  662. l.register:=hregister;
  663. { Release temp when it was a reference }
  664. if oldloc.loc=LOC_REFERENCE then
  665. location_freetemp(list,oldloc);
  666. end;
  667. {$endif not cpu64bitalu}
  668. procedure location_force_fpureg(list:TAsmList;var l: tlocation;maybeconst:boolean);
  669. var
  670. reg : tregister;
  671. href : treference;
  672. begin
  673. if (l.loc<>LOC_FPUREGISTER) and
  674. ((l.loc<>LOC_CFPUREGISTER) or (not maybeconst)) then
  675. begin
  676. { if it's in an mm register, store to memory first }
  677. if (l.loc in [LOC_MMREGISTER,LOC_CMMREGISTER]) then
  678. begin
  679. tg.GetTemp(list,tcgsize2size[l.size],tcgsize2size[l.size],tt_normal,href);
  680. cg.a_loadmm_reg_ref(list,l.size,l.size,l.register,href,mms_movescalar);
  681. location_reset_ref(l,LOC_REFERENCE,l.size,0);
  682. l.reference:=href;
  683. end;
  684. reg:=cg.getfpuregister(list,l.size);
  685. cg.a_loadfpu_loc_reg(list,l.size,l,reg);
  686. location_freetemp(list,l);
  687. location_reset(l,LOC_FPUREGISTER,l.size);
  688. l.register:=reg;
  689. end;
  690. end;
  691. procedure location_force_mmregscalar(list:TAsmList;var l: tlocation;maybeconst:boolean);
  692. var
  693. reg : tregister;
  694. href : treference;
  695. newsize : tcgsize;
  696. begin
  697. if (l.loc<>LOC_MMREGISTER) and
  698. ((l.loc<>LOC_CMMREGISTER) or (not maybeconst)) then
  699. begin
  700. { if it's in an fpu register, store to memory first }
  701. if (l.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER]) then
  702. begin
  703. tg.GetTemp(list,tcgsize2size[l.size],tcgsize2size[l.size],tt_normal,href);
  704. cg.a_loadfpu_reg_ref(list,l.size,l.size,l.register,href);
  705. location_reset_ref(l,LOC_REFERENCE,l.size,0);
  706. l.reference:=href;
  707. end;
  708. {$ifndef cpu64bitalu}
  709. if (l.loc in [LOC_REGISTER,LOC_CREGISTER]) and
  710. (l.size in [OS_64,OS_S64]) then
  711. begin
  712. reg:=cg.getmmregister(list,OS_F64);
  713. cg64.a_loadmm_intreg64_reg(list,OS_F64,l.register64,reg);
  714. l.size:=OS_F64
  715. end
  716. else
  717. {$endif not cpu64bitalu}
  718. begin
  719. { on ARM, CFP values may be located in integer registers,
  720. and its second_int_to_real() also uses this routine to
  721. force integer (memory) values in an mmregister }
  722. if (l.size in [OS_32,OS_S32]) then
  723. newsize:=OS_F32
  724. else if (l.size in [OS_64,OS_S64]) then
  725. newsize:=OS_F64
  726. else
  727. newsize:=l.size;
  728. reg:=cg.getmmregister(list,newsize);
  729. cg.a_loadmm_loc_reg(list,newsize,l,reg,mms_movescalar);
  730. l.size:=newsize;
  731. end;
  732. location_freetemp(list,l);
  733. location_reset(l,LOC_MMREGISTER,l.size);
  734. l.register:=reg;
  735. end;
  736. end;
  737. procedure gen_loadfpu_loc_cgpara(list: TAsmList; const l: tlocation;const cgpara: tcgpara;locintsize: longint);
  738. var
  739. {$ifdef i386}
  740. href : treference;
  741. size : longint;
  742. {$endif i386}
  743. locsize : tcgsize;
  744. tmploc : tlocation;
  745. begin
  746. if not(l.size in [OS_32,OS_S32,OS_64,OS_S64,OS_128,OS_S128]) then
  747. locsize:=l.size
  748. else
  749. locsize:=int_float_cgsize(tcgsize2size[l.size]);
  750. {$ifdef i386}
  751. case l.loc of
  752. LOC_FPUREGISTER,
  753. LOC_CFPUREGISTER:
  754. begin
  755. case cgpara.location^.loc of
  756. LOC_REFERENCE:
  757. begin
  758. size:=align(locintsize,cgpara.alignment);
  759. if (not paramanager.use_fixed_stack) and
  760. (cgpara.location^.reference.index=NR_STACK_POINTER_REG) then
  761. begin
  762. cg.g_stackpointer_alloc(list,size);
  763. reference_reset_base(href,NR_STACK_POINTER_REG,0,sizeof(pint));
  764. end
  765. else
  766. reference_reset_base(href,cgpara.location^.reference.index,cgpara.location^.reference.offset,cgpara.alignment);
  767. cg.a_loadfpu_reg_ref(list,locsize,locsize,l.register,href);
  768. end;
  769. LOC_FPUREGISTER:
  770. begin
  771. cg.a_loadfpu_reg_reg(list,locsize,cgpara.location^.size,l.register,cgpara.location^.register);
  772. end;
  773. { can happen if a record with only 1 "single field" is
  774. returned in a floating point register and then is directly
  775. passed to a regcall parameter }
  776. LOC_REGISTER:
  777. begin
  778. tmploc:=l;
  779. location_force_mem(list,tmploc);
  780. case locsize of
  781. OS_F32:
  782. tmploc.size:=OS_32;
  783. OS_F64:
  784. tmploc.size:=OS_64;
  785. else
  786. internalerror(2010053116);
  787. end;
  788. cg.a_load_loc_cgpara(list,tmploc,cgpara);
  789. location_freetemp(list,tmploc);
  790. end
  791. else
  792. internalerror(2010053003);
  793. end;
  794. end;
  795. LOC_MMREGISTER,
  796. LOC_CMMREGISTER:
  797. begin
  798. case cgpara.location^.loc of
  799. LOC_REFERENCE:
  800. begin
  801. { can't use TCGSize2Size[l.size], because the size of an
  802. 80 bit extended parameter can be either 10 or 12 bytes }
  803. size:=align(locintsize,cgpara.alignment);
  804. if (not paramanager.use_fixed_stack) and
  805. (cgpara.location^.reference.index=NR_STACK_POINTER_REG) then
  806. begin
  807. cg.g_stackpointer_alloc(list,size);
  808. reference_reset_base(href,NR_STACK_POINTER_REG,0,sizeof(pint));
  809. end
  810. else
  811. reference_reset_base(href,cgpara.location^.reference.index,cgpara.location^.reference.offset,cgpara.alignment);
  812. cg.a_loadmm_reg_ref(list,locsize,locsize,l.register,href,mms_movescalar);
  813. end;
  814. LOC_FPUREGISTER:
  815. begin
  816. tmploc:=l;
  817. location_force_mem(list,tmploc);
  818. cg.a_loadfpu_ref_cgpara(list,tmploc.size,tmploc.reference,cgpara);
  819. location_freetemp(list,tmploc);
  820. end;
  821. else
  822. internalerror(2010053004);
  823. end;
  824. end;
  825. LOC_REFERENCE,
  826. LOC_CREFERENCE :
  827. begin
  828. case cgpara.location^.loc of
  829. LOC_REFERENCE:
  830. begin
  831. size:=align(locintsize,cgpara.alignment);
  832. if (not paramanager.use_fixed_stack) and
  833. (cgpara.location^.reference.index=NR_STACK_POINTER_REG) then
  834. cg.a_load_ref_cgpara(list,locsize,l.reference,cgpara)
  835. else
  836. begin
  837. reference_reset_base(href,cgpara.location^.reference.index,cgpara.location^.reference.offset,cgpara.alignment);
  838. cg.g_concatcopy(list,l.reference,href,size);
  839. end;
  840. end;
  841. LOC_FPUREGISTER:
  842. begin
  843. cg.a_loadfpu_ref_cgpara(list,locsize,l.reference,cgpara);
  844. end;
  845. else
  846. internalerror(2010053005);
  847. end;
  848. end;
  849. else
  850. internalerror(2002042430);
  851. end;
  852. {$else i386}
  853. case l.loc of
  854. LOC_MMREGISTER,
  855. LOC_CMMREGISTER:
  856. case cgpara.location^.loc of
  857. LOC_REFERENCE,
  858. LOC_CREFERENCE,
  859. LOC_MMREGISTER,
  860. LOC_CMMREGISTER,
  861. LOC_REGISTER,
  862. LOC_CREGISTER :
  863. cg.a_loadmm_reg_cgpara(list,locsize,l.register,cgpara,mms_movescalar);
  864. LOC_FPUREGISTER,
  865. LOC_CFPUREGISTER:
  866. begin
  867. tmploc:=l;
  868. location_force_fpureg(list,tmploc,false);
  869. cg.a_loadfpu_reg_cgpara(list,tmploc.size,tmploc.register,cgpara);
  870. end;
  871. else
  872. internalerror(200204249);
  873. end;
  874. LOC_FPUREGISTER,
  875. LOC_CFPUREGISTER:
  876. case cgpara.location^.loc of
  877. LOC_MMREGISTER,
  878. LOC_CMMREGISTER:
  879. begin
  880. tmploc:=l;
  881. location_force_mmregscalar(list,tmploc,false);
  882. cg.a_loadmm_reg_cgpara(list,tmploc.size,tmploc.register,cgpara,mms_movescalar);
  883. end;
  884. { Some targets pass floats in normal registers }
  885. LOC_REGISTER,
  886. LOC_CREGISTER,
  887. LOC_REFERENCE,
  888. LOC_CREFERENCE,
  889. LOC_FPUREGISTER,
  890. LOC_CFPUREGISTER:
  891. cg.a_loadfpu_reg_cgpara(list,locsize,l.register,cgpara);
  892. else
  893. internalerror(2002042433);
  894. end;
  895. LOC_REFERENCE,
  896. LOC_CREFERENCE:
  897. case cgpara.location^.loc of
  898. LOC_MMREGISTER,
  899. LOC_CMMREGISTER:
  900. cg.a_loadmm_ref_cgpara(list,locsize,l.reference,cgpara,mms_movescalar);
  901. { Some targets pass floats in normal registers }
  902. LOC_REGISTER,
  903. LOC_CREGISTER,
  904. LOC_REFERENCE,
  905. LOC_CREFERENCE,
  906. LOC_FPUREGISTER,
  907. LOC_CFPUREGISTER:
  908. cg.a_loadfpu_ref_cgpara(list,locsize,l.reference,cgpara);
  909. else
  910. internalerror(2002042431);
  911. end;
  912. LOC_REGISTER,
  913. LOC_CREGISTER :
  914. begin
  915. {$ifndef cpu64bitalu}
  916. { Only a_load_ref_cgpara supports multiple locations, when the
  917. value is still a const or in a register then write it
  918. to a reference first. This situation can be triggered
  919. by typecasting an int64 constant to a record of 8 bytes }
  920. if locsize = OS_F64 then
  921. begin
  922. tmploc:=l;
  923. location_force_mem(list,tmploc);
  924. cg.a_load_loc_cgpara(list,tmploc,cgpara);
  925. location_freetemp(list,tmploc);
  926. end
  927. else
  928. {$endif not cpu64bitalu}
  929. cg.a_load_loc_cgpara(list,l,cgpara);
  930. end;
  931. else
  932. internalerror(2002042432);
  933. end;
  934. {$endif i386}
  935. end;
  936. procedure gen_load_loc_cgpara(list: TAsmList; vardef: tdef; const l: tlocation; const cgpara: tcgpara);
  937. {$ifndef cpu64bitalu}
  938. var
  939. tmploc: tlocation;
  940. {$endif not cpu64bitalu}
  941. begin
  942. { Handle Floating point types differently
  943. This doesn't depend on emulator settings, emulator settings should
  944. be handled by cpupara }
  945. if (vardef.typ=floatdef) or
  946. { some ABIs return certain records in an fpu register }
  947. (l.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER]) or
  948. (assigned(cgpara.location) and
  949. (cgpara.Location^.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER])) then
  950. begin
  951. gen_loadfpu_loc_cgpara(list,l,cgpara,vardef.size);
  952. exit;
  953. end;
  954. case l.loc of
  955. LOC_CONSTANT,
  956. LOC_REGISTER,
  957. LOC_CREGISTER,
  958. LOC_REFERENCE,
  959. LOC_CREFERENCE :
  960. begin
  961. {$ifndef cpu64bitalu}
  962. { use cg64 only for int64, not for 8 byte records }
  963. if is_64bit(vardef) then
  964. cg64.a_load64_loc_cgpara(list,l,cgpara)
  965. else
  966. {$endif not cpu64bitalu}
  967. begin
  968. {$ifndef cpu64bitalu}
  969. { Only a_load_ref_cgpara supports multiple locations, when the
  970. value is still a const or in a register then write it
  971. to a reference first. This situation can be triggered
  972. by typecasting an int64 constant to a record of 8 bytes }
  973. if l.size in [OS_64,OS_S64] then
  974. begin
  975. tmploc:=l;
  976. location_force_mem(list,tmploc);
  977. cg.a_load_loc_cgpara(list,tmploc,cgpara);
  978. { do not free the tmploc in case the original value was
  979. already in memory, because the caller (ncgcal) will then
  980. free it again later }
  981. if not(l.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  982. location_freetemp(list,tmploc);
  983. end
  984. else
  985. {$endif not cpu64bitalu}
  986. cg.a_load_loc_cgpara(list,l,cgpara);
  987. end;
  988. end;
  989. LOC_MMREGISTER,
  990. LOC_CMMREGISTER:
  991. begin
  992. case l.size of
  993. OS_F32,
  994. OS_F64:
  995. cg.a_loadmm_loc_cgpara(list,l,cgpara,mms_movescalar);
  996. else
  997. cg.a_loadmm_loc_cgpara(list,l,cgpara,nil);
  998. end;
  999. end;
  1000. {$ifdef SUPPORT_MMX}
  1001. LOC_MMXREGISTER,
  1002. LOC_CMMXREGISTER:
  1003. cg.a_loadmm_reg_cgpara(list,OS_M64,l.register,cgpara,nil);
  1004. {$endif SUPPORT_MMX}
  1005. else
  1006. internalerror(200204241);
  1007. end;
  1008. end;
  1009. procedure register_maybe_adjust_setbase(list: TAsmList; var l: tlocation; setbase: aint);
  1010. var
  1011. tmpreg: tregister;
  1012. begin
  1013. if (setbase<>0) then
  1014. begin
  1015. if not(l.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  1016. internalerror(2007091502);
  1017. { subtract the setbase }
  1018. case l.loc of
  1019. LOC_CREGISTER:
  1020. begin
  1021. tmpreg := cg.getintregister(list,l.size);
  1022. cg.a_op_const_reg_reg(list,OP_SUB,l.size,setbase,l.register,tmpreg);
  1023. l.loc:=LOC_REGISTER;
  1024. l.register:=tmpreg;
  1025. end;
  1026. LOC_REGISTER:
  1027. begin
  1028. cg.a_op_const_reg(list,OP_SUB,l.size,setbase,l.register);
  1029. end;
  1030. end;
  1031. end;
  1032. end;
  1033. procedure location_force_mmreg(list:TAsmList;var l: tlocation;maybeconst:boolean);
  1034. var
  1035. reg : tregister;
  1036. begin
  1037. if (l.loc<>LOC_MMREGISTER) and
  1038. ((l.loc<>LOC_CMMREGISTER) or (not maybeconst)) then
  1039. begin
  1040. reg:=cg.getmmregister(list,OS_VECTOR);
  1041. cg.a_loadmm_loc_reg(list,OS_VECTOR,l,reg,nil);
  1042. location_freetemp(list,l);
  1043. location_reset(l,LOC_MMREGISTER,OS_VECTOR);
  1044. l.register:=reg;
  1045. end;
  1046. end;
  1047. procedure location_allocate_register(list: TAsmList;out l: tlocation;def: tdef;constant: boolean);
  1048. begin
  1049. l.size:=def_cgsize(def);
  1050. if (def.typ=floatdef) and
  1051. not(cs_fp_emulation in current_settings.moduleswitches) then
  1052. begin
  1053. if use_vectorfpu(def) then
  1054. begin
  1055. if constant then
  1056. location_reset(l,LOC_CMMREGISTER,l.size)
  1057. else
  1058. location_reset(l,LOC_MMREGISTER,l.size);
  1059. l.register:=cg.getmmregister(list,l.size);
  1060. end
  1061. else
  1062. begin
  1063. if constant then
  1064. location_reset(l,LOC_CFPUREGISTER,l.size)
  1065. else
  1066. location_reset(l,LOC_FPUREGISTER,l.size);
  1067. l.register:=cg.getfpuregister(list,l.size);
  1068. end;
  1069. end
  1070. else
  1071. begin
  1072. if constant then
  1073. location_reset(l,LOC_CREGISTER,l.size)
  1074. else
  1075. location_reset(l,LOC_REGISTER,l.size);
  1076. {$ifndef cpu64bitalu}
  1077. if l.size in [OS_64,OS_S64,OS_F64] then
  1078. begin
  1079. l.register64.reglo:=cg.getintregister(list,OS_32);
  1080. l.register64.reghi:=cg.getintregister(list,OS_32);
  1081. end
  1082. else
  1083. {$endif not cpu64bitalu}
  1084. l.register:=cg.getintregister(list,l.size);
  1085. end;
  1086. end;
  1087. procedure location_force_mem(list:TAsmList;var l:tlocation);
  1088. var
  1089. r : treference;
  1090. begin
  1091. case l.loc of
  1092. LOC_FPUREGISTER,
  1093. LOC_CFPUREGISTER :
  1094. begin
  1095. tg.GetTemp(list,TCGSize2Size[l.size],TCGSize2Size[l.size],tt_normal,r);
  1096. cg.a_loadfpu_reg_ref(list,l.size,l.size,l.register,r);
  1097. location_reset_ref(l,LOC_REFERENCE,l.size,0);
  1098. l.reference:=r;
  1099. end;
  1100. LOC_MMREGISTER,
  1101. LOC_CMMREGISTER:
  1102. begin
  1103. tg.GetTemp(list,TCGSize2Size[l.size],TCGSize2Size[l.size],tt_normal,r);
  1104. cg.a_loadmm_reg_ref(list,l.size,l.size,l.register,r,mms_movescalar);
  1105. location_reset_ref(l,LOC_REFERENCE,l.size,0);
  1106. l.reference:=r;
  1107. end;
  1108. LOC_CONSTANT,
  1109. LOC_REGISTER,
  1110. LOC_CREGISTER :
  1111. begin
  1112. tg.GetTemp(list,TCGSize2Size[l.size],TCGSize2Size[l.size],tt_normal,r);
  1113. {$ifndef cpu64bitalu}
  1114. if l.size in [OS_64,OS_S64] then
  1115. cg64.a_load64_loc_ref(list,l,r)
  1116. else
  1117. {$endif not cpu64bitalu}
  1118. cg.a_load_loc_ref(list,l.size,l,r);
  1119. location_reset_ref(l,LOC_REFERENCE,l.size,0);
  1120. l.reference:=r;
  1121. end;
  1122. LOC_SUBSETREG,
  1123. LOC_CSUBSETREG,
  1124. LOC_SUBSETREF,
  1125. LOC_CSUBSETREF:
  1126. begin
  1127. tg.GetTemp(list,TCGSize2Size[l.size],TCGSize2Size[l.size],tt_normal,r);
  1128. cg.a_load_loc_ref(list,l.size,l,r);
  1129. location_reset_ref(l,LOC_REFERENCE,l.size,0);
  1130. l.reference:=r;
  1131. end;
  1132. LOC_CREFERENCE,
  1133. LOC_REFERENCE : ;
  1134. else
  1135. internalerror(200203219);
  1136. end;
  1137. end;
  1138. procedure location_get_data_ref(list:TAsmList;const l:tlocation;var ref:treference;loadref:boolean; alignment: longint);
  1139. begin
  1140. case l.loc of
  1141. LOC_REGISTER,
  1142. LOC_CREGISTER :
  1143. begin
  1144. if not loadref then
  1145. internalerror(200410231);
  1146. reference_reset_base(ref,l.register,0,alignment);
  1147. end;
  1148. LOC_REFERENCE,
  1149. LOC_CREFERENCE :
  1150. begin
  1151. if loadref then
  1152. begin
  1153. reference_reset_base(ref,cg.getaddressregister(list),0,alignment);
  1154. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,l.reference,ref.base);
  1155. end
  1156. else
  1157. ref:=l.reference;
  1158. end;
  1159. else
  1160. internalerror(200309181);
  1161. end;
  1162. end;
  1163. {****************************************************************************
  1164. Init/Finalize Code
  1165. ****************************************************************************}
  1166. procedure copyvalueparas(p:TObject;arg:pointer);
  1167. var
  1168. href : treference;
  1169. hreg : tregister;
  1170. list : TAsmList;
  1171. hsym : tparavarsym;
  1172. l : longint;
  1173. localcopyloc : tlocation;
  1174. begin
  1175. list:=TAsmList(arg);
  1176. if (tsym(p).typ=paravarsym) and
  1177. (tparavarsym(p).varspez=vs_value) and
  1178. (paramanager.push_addr_param(tparavarsym(p).varspez,tparavarsym(p).vardef,current_procinfo.procdef.proccalloption)) then
  1179. begin
  1180. { we have no idea about the alignment at the caller side }
  1181. location_get_data_ref(list,tparavarsym(p).initialloc,href,true,1);
  1182. if is_open_array(tparavarsym(p).vardef) or
  1183. is_array_of_const(tparavarsym(p).vardef) then
  1184. begin
  1185. { cdecl functions don't have a high pointer so it is not possible to generate
  1186. a local copy }
  1187. if not(current_procinfo.procdef.proccalloption in cdecl_pocalls) then
  1188. begin
  1189. hsym:=tparavarsym(get_high_value_sym(tparavarsym(p)));
  1190. if not assigned(hsym) then
  1191. internalerror(200306061);
  1192. hreg:=cg.getaddressregister(list);
  1193. if not is_packed_array(tparavarsym(p).vardef) then
  1194. cg.g_copyvaluepara_openarray(list,href,hsym.initialloc,tarraydef(tparavarsym(p).vardef).elesize,hreg)
  1195. else
  1196. internalerror(2006080401);
  1197. // cg.g_copyvaluepara_packedopenarray(list,href,hsym.intialloc,tarraydef(tparavarsym(p).vardef).elepackedbitsize,hreg);
  1198. cg.a_load_reg_loc(list,OS_ADDR,hreg,tparavarsym(p).initialloc);
  1199. end;
  1200. end
  1201. else
  1202. begin
  1203. { Allocate space for the local copy }
  1204. l:=tparavarsym(p).getsize;
  1205. localcopyloc.loc:=LOC_REFERENCE;
  1206. localcopyloc.size:=int_cgsize(l);
  1207. tg.GetLocal(list,l,tparavarsym(p).vardef,localcopyloc.reference);
  1208. { Copy data }
  1209. if is_shortstring(tparavarsym(p).vardef) then
  1210. begin
  1211. { this code is only executed before the code for the body and the entry/exit code is generated
  1212. so we're allowed to include pi_do_call here; after pass1 is run, this isn't allowed anymore
  1213. }
  1214. include(current_procinfo.flags,pi_do_call);
  1215. cg.g_copyshortstring(list,href,localcopyloc.reference,tstringdef(tparavarsym(p).vardef).len)
  1216. end
  1217. else if tparavarsym(p).vardef.typ = variantdef then
  1218. begin
  1219. { this code is only executed before the code for the body and the entry/exit code is generated
  1220. so we're allowed to include pi_do_call here; after pass1 is run, this isn't allowed anymore
  1221. }
  1222. include(current_procinfo.flags,pi_do_call);
  1223. cg.g_copyvariant(list,href,localcopyloc.reference)
  1224. end
  1225. else
  1226. begin
  1227. { pass proper alignment info }
  1228. localcopyloc.reference.alignment:=tparavarsym(p).vardef.alignment;
  1229. cg.g_concatcopy(list,href,localcopyloc.reference,tparavarsym(p).vardef.size);
  1230. end;
  1231. { update localloc of varsym }
  1232. tg.Ungetlocal(list,tparavarsym(p).localloc.reference);
  1233. tparavarsym(p).localloc:=localcopyloc;
  1234. tparavarsym(p).initialloc:=localcopyloc;
  1235. end;
  1236. end;
  1237. end;
  1238. const
  1239. {$ifdef cpu64bitalu}
  1240. trashintvalues: array[0..nroftrashvalues-1] of aint = ($5555555555555555,aint($AAAAAAAAAAAAAAAA),aint($EFEFEFEFEFEFEFEF),0);
  1241. {$endif cpu64bitalu}
  1242. {$ifdef cpu32bitalu}
  1243. trashintvalues: array[0..nroftrashvalues-1] of aint = ($55555555,aint($AAAAAAAA),aint($EFEFEFEF),0);
  1244. {$endif cpu32bitalu}
  1245. {$ifdef cpu8bitalu}
  1246. trashintvalues: array[0..nroftrashvalues-1] of aint = ($55,aint($AA),aint($EF),0);
  1247. {$endif cpu8bitalu}
  1248. procedure trash_reference(list: TAsmList; const ref: treference; size: aint);
  1249. var
  1250. countreg, valuereg: tregister;
  1251. hl: tasmlabel;
  1252. trashintval: aint;
  1253. tmpref: treference;
  1254. begin
  1255. trashintval := trashintvalues[localvartrashing];
  1256. case size of
  1257. 0: ; { empty record }
  1258. 1: cg.a_load_const_ref(list,OS_8,byte(trashintval),ref);
  1259. 2: cg.a_load_const_ref(list,OS_16,word(trashintval),ref);
  1260. 4: cg.a_load_const_ref(list,OS_32,longint(trashintval),ref);
  1261. {$ifdef cpu64bitalu}
  1262. 8: cg.a_load_const_ref(list,OS_64,int64(trashintval),ref);
  1263. {$endif cpu64bitalu}
  1264. else
  1265. begin
  1266. countreg := cg.getintregister(list,OS_ADDR);
  1267. valuereg := cg.getintregister(list,OS_8);
  1268. cg.a_load_const_reg(list,OS_INT,size,countreg);
  1269. cg.a_load_const_reg(list,OS_8,byte(trashintval),valuereg);
  1270. current_asmdata.getjumplabel(hl);
  1271. tmpref := ref;
  1272. if (tmpref.index <> NR_NO) then
  1273. internalerror(200607201);
  1274. tmpref.index := countreg;
  1275. dec(tmpref.offset);
  1276. cg.a_label(list,hl);
  1277. cg.a_load_reg_ref(list,OS_8,OS_8,valuereg,tmpref);
  1278. cg.a_op_const_reg(list,OP_SUB,OS_INT,1,countreg);
  1279. cg.a_cmp_const_reg_label(list,OS_INT,OC_NE,0,countreg,hl);
  1280. cg.a_reg_sync(list,tmpref.base);
  1281. cg.a_reg_sync(list,valuereg);
  1282. end;
  1283. end;
  1284. end;
  1285. { trash contents of local variables or parameters (function result) }
  1286. procedure trash_variable(p:TObject;arg:pointer);
  1287. var
  1288. trashintval: aint;
  1289. list: TAsmList absolute arg;
  1290. begin
  1291. if ((tsym(p).typ=localvarsym) or
  1292. ((tsym(p).typ=paravarsym) and
  1293. (vo_is_funcret in tparavarsym(p).varoptions))) and
  1294. not(is_managed_type(tabstractnormalvarsym(p).vardef)) and
  1295. not(assigned(tabstractnormalvarsym(p).defaultconstsym)) then
  1296. begin
  1297. trashintval := trashintvalues[localvartrashing];
  1298. case tabstractnormalvarsym(p).initialloc.loc of
  1299. LOC_CREGISTER :
  1300. {$push}
  1301. {$q-}
  1302. begin
  1303. { avoid problems with broken x86 shifts }
  1304. case tcgsize2size[tabstractnormalvarsym(p).initialloc.size] of
  1305. 1: cg.a_load_const_reg(list,OS_8,byte(trashintval),tabstractnormalvarsym(p).initialloc.register);
  1306. 2: cg.a_load_const_reg(list,OS_16,word(trashintval),tabstractnormalvarsym(p).initialloc.register);
  1307. 4: cg.a_load_const_reg(list,OS_32,longint(trashintval),tabstractnormalvarsym(p).initialloc.register);
  1308. 8:
  1309. begin
  1310. {$ifdef cpu64bitalu}
  1311. cg.a_load_const_reg(list,OS_64,aint(trashintval),tabstractnormalvarsym(p).initialloc.register);
  1312. {$else}
  1313. cg64.a_load64_const_reg(list,int64(trashintval) shl 32 or int64(trashintval),tabstractnormalvarsym(p).initialloc.register64);
  1314. {$endif}
  1315. end;
  1316. else
  1317. internalerror(2010060801);
  1318. end;
  1319. end;
  1320. {$pop}
  1321. LOC_REFERENCE :
  1322. begin
  1323. if ((tsym(p).typ=localvarsym) and
  1324. not(vo_is_funcret in tabstractvarsym(p).varoptions)) or
  1325. not is_shortstring(tabstractnormalvarsym(p).vardef) then
  1326. trash_reference(list,tabstractnormalvarsym(p).initialloc.reference,
  1327. tlocalvarsym(p).getsize)
  1328. else
  1329. { may be an open string, even if is_open_string() returns }
  1330. { false (for some helpers in the system unit) }
  1331. { an open string has at least size 2 }
  1332. trash_reference(list,tabstractnormalvarsym(p).initialloc.reference,
  1333. 2);
  1334. end;
  1335. LOC_CMMREGISTER :
  1336. ;
  1337. LOC_CFPUREGISTER :
  1338. ;
  1339. else
  1340. internalerror(200410124);
  1341. end;
  1342. end;
  1343. end;
  1344. { initializes the regvars from staticsymtable with 0 }
  1345. procedure initialize_regvars(p:TObject;arg:pointer);
  1346. var
  1347. href : treference;
  1348. begin
  1349. if (tsym(p).typ=staticvarsym) then
  1350. begin
  1351. { Static variables can have the initialloc only set to LOC_CxREGISTER
  1352. or LOC_INVALID, for explaination see gen_alloc_symtable (PFV) }
  1353. case tstaticvarsym(p).initialloc.loc of
  1354. LOC_CREGISTER :
  1355. begin
  1356. {$ifndef cpu64bitalu}
  1357. if (tstaticvarsym(p).initialloc.size in [OS_64,OS_S64]) then
  1358. cg64.a_load64_const_reg(TAsmList(arg),0,tstaticvarsym(p).initialloc.register64)
  1359. else
  1360. {$endif not cpu64bitalu}
  1361. cg.a_load_const_reg(TAsmList(arg),reg_cgsize(tstaticvarsym(p).initialloc.register),0,
  1362. tstaticvarsym(p).initialloc.register);
  1363. end;
  1364. LOC_CMMREGISTER :
  1365. { clear the whole register }
  1366. cg.a_opmm_reg_reg(TAsmList(arg),OP_XOR,reg_cgsize(tstaticvarsym(p).initialloc.register),
  1367. tstaticvarsym(p).initialloc.register,
  1368. tstaticvarsym(p).initialloc.register,
  1369. nil);
  1370. LOC_CFPUREGISTER :
  1371. begin
  1372. { initialize fpu regvar by loading from memory }
  1373. reference_reset_symbol(href,
  1374. current_asmdata.RefAsmSymbol(tstaticvarsym(p).mangledname), 0,
  1375. var_align(tstaticvarsym(p).vardef.alignment));
  1376. cg.a_loadfpu_ref_reg(TAsmList(arg), tstaticvarsym(p).initialloc.size,
  1377. tstaticvarsym(p).initialloc.size, href, tstaticvarsym(p).initialloc.register);
  1378. end;
  1379. LOC_INVALID :
  1380. ;
  1381. else
  1382. internalerror(200410124);
  1383. end;
  1384. end;
  1385. end;
  1386. { generates the code for initialisation of local data }
  1387. procedure initialize_data(p:TObject;arg:pointer);
  1388. var
  1389. OldAsmList : TAsmList;
  1390. hp : tnode;
  1391. begin
  1392. if (tsym(p).typ = localvarsym) and
  1393. { local (procedure or unit) variables only need initialization if
  1394. they are used }
  1395. ((tabstractvarsym(p).refs>0) or
  1396. { managed return symbols must be inited }
  1397. ((tsym(p).typ=localvarsym) and (vo_is_funcret in tlocalvarsym(p).varoptions))
  1398. ) and
  1399. not(vo_is_typed_const in tabstractvarsym(p).varoptions) and
  1400. not(vo_is_external in tabstractvarsym(p).varoptions) and
  1401. not(vo_is_default_var in tabstractvarsym(p).varoptions) and
  1402. (is_managed_type(tabstractvarsym(p).vardef) or
  1403. ((m_iso in current_settings.modeswitches) and (tabstractvarsym(p).vardef.typ=filedef))
  1404. ) then
  1405. begin
  1406. OldAsmList:=current_asmdata.CurrAsmList;
  1407. current_asmdata.CurrAsmList:=TAsmList(arg);
  1408. hp:=initialize_data_node(cloadnode.create(tsym(p),tsym(p).owner));
  1409. firstpass(hp);
  1410. secondpass(hp);
  1411. hp.free;
  1412. current_asmdata.CurrAsmList:=OldAsmList;
  1413. end;
  1414. end;
  1415. procedure finalize_sym(asmlist:TAsmList;sym:tsym);
  1416. var
  1417. hp : tnode;
  1418. OldAsmList : TAsmList;
  1419. begin
  1420. include(current_procinfo.flags,pi_needs_implicit_finally);
  1421. OldAsmList:=current_asmdata.CurrAsmList;
  1422. current_asmdata.CurrAsmList:=asmlist;
  1423. hp:=cloadnode.create(sym,sym.owner);
  1424. if (sym.typ=staticvarsym) and (vo_force_finalize in tstaticvarsym(sym).varoptions) then
  1425. include(tloadnode(hp).loadnodeflags,loadnf_isinternal_ignoreconst);
  1426. hp:=finalize_data_node(hp);
  1427. firstpass(hp);
  1428. secondpass(hp);
  1429. hp.free;
  1430. current_asmdata.CurrAsmList:=OldAsmList;
  1431. end;
  1432. { generates the code for finalisation of local variables }
  1433. procedure finalize_local_vars(p:TObject;arg:pointer);
  1434. begin
  1435. if (tsym(p).typ=localvarsym) and
  1436. (tlocalvarsym(p).refs>0) and
  1437. not(vo_is_external in tlocalvarsym(p).varoptions) and
  1438. not(vo_is_funcret in tlocalvarsym(p).varoptions) and
  1439. not(vo_is_default_var in tlocalvarsym(p).varoptions) and
  1440. is_managed_type(tlocalvarsym(p).vardef) then
  1441. finalize_sym(TAsmList(arg),tsym(p));
  1442. end;
  1443. { generates the code for finalization of static symtable and
  1444. all local (static) typed consts }
  1445. procedure finalize_static_data(p:TObject;arg:pointer);
  1446. var
  1447. i : longint;
  1448. pd : tprocdef;
  1449. begin
  1450. case tsym(p).typ of
  1451. staticvarsym :
  1452. begin
  1453. { local (procedure or unit) variables only need finalization
  1454. if they are used
  1455. }
  1456. if ((tstaticvarsym(p).refs>0) or
  1457. { global (unit) variables always need finalization, since
  1458. they may also be used in another unit
  1459. }
  1460. (tstaticvarsym(p).owner.symtabletype=globalsymtable)) and
  1461. (
  1462. (tstaticvarsym(p).varspez<>vs_const) or
  1463. (vo_force_finalize in tstaticvarsym(p).varoptions)
  1464. ) and
  1465. not(vo_is_funcret in tstaticvarsym(p).varoptions) and
  1466. not(vo_is_external in tstaticvarsym(p).varoptions) and
  1467. is_managed_type(tstaticvarsym(p).vardef) then
  1468. finalize_sym(TAsmList(arg),tsym(p));
  1469. end;
  1470. procsym :
  1471. begin
  1472. for i:=0 to tprocsym(p).ProcdefList.Count-1 do
  1473. begin
  1474. pd:=tprocdef(tprocsym(p).ProcdefList[i]);
  1475. if assigned(pd.localst) and
  1476. (pd.procsym=tprocsym(p)) and
  1477. (pd.localst.symtabletype<>staticsymtable) then
  1478. pd.localst.SymList.ForEachCall(@finalize_static_data,arg);
  1479. end;
  1480. end;
  1481. end;
  1482. end;
  1483. { generates the code for incrementing the reference count of parameters and
  1484. initialize out parameters }
  1485. procedure init_paras(p:TObject;arg:pointer);
  1486. var
  1487. href : treference;
  1488. hsym : tparavarsym;
  1489. eldef : tdef;
  1490. tmpreg : tregister;
  1491. list : TAsmList;
  1492. needs_inittable,
  1493. do_trashing : boolean;
  1494. begin
  1495. list:=TAsmList(arg);
  1496. if (tsym(p).typ=paravarsym) then
  1497. begin
  1498. needs_inittable:=is_managed_type(tparavarsym(p).vardef);
  1499. do_trashing:=
  1500. (localvartrashing <> -1) and
  1501. (not assigned(tparavarsym(p).defaultconstsym)) and
  1502. not needs_inittable;
  1503. case tparavarsym(p).varspez of
  1504. vs_value :
  1505. if needs_inittable then
  1506. begin
  1507. { variants are already handled by the call to fpc_variant_copy_overwrite if
  1508. they are passed by reference }
  1509. if not((tparavarsym(p).vardef.typ=variantdef) and
  1510. paramanager.push_addr_param(tparavarsym(p).varspez,tparavarsym(p).vardef,current_procinfo.procdef.proccalloption)) then
  1511. begin
  1512. location_get_data_ref(list,tparavarsym(p).initialloc,href,is_open_array(tparavarsym(p).vardef),sizeof(pint));
  1513. if is_open_array(tparavarsym(p).vardef) then
  1514. begin
  1515. { open arrays do not contain correct element count in their rtti,
  1516. the actual count must be passed separately. }
  1517. hsym:=tparavarsym(get_high_value_sym(tparavarsym(p)));
  1518. eldef:=tarraydef(tparavarsym(p).vardef).elementdef;
  1519. if not assigned(hsym) then
  1520. internalerror(201003031);
  1521. cg.g_array_rtti_helper(list,eldef,href,hsym.initialloc,'FPC_ADDREF_ARRAY');
  1522. end
  1523. else
  1524. cg.g_incrrefcount(list,tparavarsym(p).vardef,href);
  1525. end;
  1526. end;
  1527. vs_out :
  1528. begin
  1529. if needs_inittable or
  1530. do_trashing then
  1531. begin
  1532. tmpreg:=cg.getaddressregister(list);
  1533. cg.a_load_loc_reg(list,OS_ADDR,tparavarsym(p).initialloc,tmpreg);
  1534. { we have no idea about the alignment at the callee side,
  1535. and the user also cannot specify "unaligned" here, so
  1536. assume worst case }
  1537. reference_reset_base(href,tmpreg,0,1);
  1538. if do_trashing and
  1539. { needs separate implementation to trash open arrays }
  1540. { since their size is only known at run time }
  1541. not is_special_array(tparavarsym(p).vardef) then
  1542. { may be an open string, even if is_open_string() returns }
  1543. { false (for some helpers in the system unit) }
  1544. if not is_shortstring(tparavarsym(p).vardef) then
  1545. trash_reference(list,href,tparavarsym(p).vardef.size)
  1546. else
  1547. trash_reference(list,href,2);
  1548. if needs_inittable then
  1549. begin
  1550. if is_open_array(tparavarsym(p).vardef) then
  1551. begin
  1552. hsym:=tparavarsym(get_high_value_sym(tparavarsym(p)));
  1553. eldef:=tarraydef(tparavarsym(p).vardef).elementdef;
  1554. if not assigned(hsym) then
  1555. internalerror(201103033);
  1556. cg.g_array_rtti_helper(list,eldef,href,hsym.initialloc,'FPC_INITIALIZE_ARRAY');
  1557. end
  1558. else
  1559. cg.g_initialize(list,tparavarsym(p).vardef,href);
  1560. end;
  1561. end;
  1562. end;
  1563. else if do_trashing and
  1564. ([vo_is_funcret,vo_is_hidden_para] * tparavarsym(p).varoptions = [vo_is_funcret,vo_is_hidden_para]) then
  1565. begin
  1566. tmpreg:=cg.getaddressregister(list);
  1567. cg.a_load_loc_reg(list,OS_ADDR,tparavarsym(p).initialloc,tmpreg);
  1568. { should always have standard alignment. If a function is assigned
  1569. to a non-aligned variable, the optimisation to pass this variable
  1570. directly as hidden function result must/cannot be performed
  1571. (see tcallnode.funcret_can_be_reused)
  1572. }
  1573. reference_reset_base(href,tmpreg,0,
  1574. used_align(tparavarsym(p).vardef.alignment,current_settings.alignment.localalignmin,current_settings.alignment.localalignmax));
  1575. { may be an open string, even if is_open_string() returns }
  1576. { false (for some helpers in the system unit) }
  1577. if not is_shortstring(tparavarsym(p).vardef) then
  1578. trash_reference(list,href,tparavarsym(p).vardef.size)
  1579. else
  1580. { an open string has at least size 2 }
  1581. trash_reference(list,href,2);
  1582. end
  1583. end;
  1584. end;
  1585. end;
  1586. { generates the code for decrementing the reference count of parameters }
  1587. procedure final_paras(p:TObject;arg:pointer);
  1588. var
  1589. list : TAsmList;
  1590. href : treference;
  1591. hsym : tparavarsym;
  1592. eldef : tdef;
  1593. begin
  1594. if not(tsym(p).typ=paravarsym) then
  1595. exit;
  1596. list:=TAsmList(arg);
  1597. if is_managed_type(tparavarsym(p).vardef) then
  1598. begin
  1599. if (tparavarsym(p).varspez=vs_value) then
  1600. begin
  1601. include(current_procinfo.flags,pi_needs_implicit_finally);
  1602. location_get_data_ref(list,tparavarsym(p).localloc,href,is_open_array(tparavarsym(p).vardef),sizeof(pint));
  1603. if is_open_array(tparavarsym(p).vardef) then
  1604. begin
  1605. hsym:=tparavarsym(get_high_value_sym(tparavarsym(p)));
  1606. eldef:=tarraydef(tparavarsym(p).vardef).elementdef;
  1607. if not assigned(hsym) then
  1608. internalerror(201003032);
  1609. cg.g_array_rtti_helper(list,eldef,href,hsym.initialloc,'FPC_FINALIZE_ARRAY');
  1610. end
  1611. else
  1612. cg.g_finalize(list,tparavarsym(p).vardef,href);
  1613. end;
  1614. end;
  1615. { open arrays can contain elements requiring init/final code, so the else has been removed here }
  1616. if (tparavarsym(p).varspez=vs_value) and
  1617. (is_open_array(tparavarsym(p).vardef) or
  1618. is_array_of_const(tparavarsym(p).vardef)) then
  1619. begin
  1620. { cdecl functions don't have a high pointer so it is not possible to generate
  1621. a local copy }
  1622. if not(current_procinfo.procdef.proccalloption in cdecl_pocalls) then
  1623. cg.g_releasevaluepara_openarray(list,tparavarsym(p).localloc);
  1624. end;
  1625. end;
  1626. { Initialize temp ansi/widestrings,interfaces }
  1627. procedure inittempvariables(list:TAsmList);
  1628. var
  1629. hp : ptemprecord;
  1630. href : treference;
  1631. begin
  1632. hp:=tg.templist;
  1633. while assigned(hp) do
  1634. begin
  1635. if assigned(hp^.def) and
  1636. is_managed_type(hp^.def) then
  1637. begin
  1638. reference_reset_base(href,current_procinfo.framepointer,hp^.pos,sizeof(pint));
  1639. cg.g_initialize(list,hp^.def,href);
  1640. end;
  1641. hp:=hp^.next;
  1642. end;
  1643. end;
  1644. procedure finalizetempvariables(list:TAsmList);
  1645. var
  1646. hp : ptemprecord;
  1647. href : treference;
  1648. begin
  1649. hp:=tg.templist;
  1650. while assigned(hp) do
  1651. begin
  1652. if assigned(hp^.def) and
  1653. is_managed_type(hp^.def) then
  1654. begin
  1655. include(current_procinfo.flags,pi_needs_implicit_finally);
  1656. reference_reset_base(href,current_procinfo.framepointer,hp^.pos,sizeof(pint));
  1657. cg.g_finalize(list,hp^.def,href);
  1658. end;
  1659. hp:=hp^.next;
  1660. end;
  1661. end;
  1662. procedure gen_load_return_value(list:TAsmList);
  1663. var
  1664. ressym : tabstractnormalvarsym;
  1665. funcretloc : TCGPara;
  1666. begin
  1667. { Is the loading needed? }
  1668. if is_void(current_procinfo.procdef.returndef) or
  1669. (
  1670. (po_assembler in current_procinfo.procdef.procoptions) and
  1671. (not(assigned(current_procinfo.procdef.funcretsym)) or
  1672. (tabstractvarsym(current_procinfo.procdef.funcretsym).refs=0))
  1673. ) then
  1674. exit;
  1675. funcretloc:=current_procinfo.procdef.funcretloc[calleeside];
  1676. { constructors return self }
  1677. if (current_procinfo.procdef.proctypeoption=potype_constructor) then
  1678. ressym:=tabstractnormalvarsym(current_procinfo.procdef.parast.Find('self'))
  1679. else
  1680. ressym:=tabstractnormalvarsym(current_procinfo.procdef.funcretsym);
  1681. if (ressym.refs>0) or
  1682. is_managed_type(ressym.vardef) then
  1683. begin
  1684. { was: don't do anything if funcretloc.loc in [LOC_INVALID,LOC_REFERENCE] }
  1685. if not paramanager.ret_in_param(current_procinfo.procdef.returndef,current_procinfo.procdef.proccalloption) then
  1686. gen_load_loc_cgpara(list,ressym.vardef,ressym.localloc,funcretloc);
  1687. end
  1688. {$ifdef x86}
  1689. else
  1690. begin
  1691. { the caller will pop a value from the fpu stack }
  1692. if assigned(funcretloc.location) and
  1693. (funcretloc.location^.loc = LOC_FPUREGISTER) then
  1694. list.concat(taicpu.op_none(A_FLDZ));
  1695. end;
  1696. {$endif x86}
  1697. end;
  1698. procedure gen_alloc_regloc(list:TAsmList;var loc: tlocation);
  1699. begin
  1700. case loc.loc of
  1701. LOC_CREGISTER:
  1702. begin
  1703. {$ifndef cpu64bitalu}
  1704. if loc.size in [OS_64,OS_S64] then
  1705. begin
  1706. loc.register64.reglo:=cg.getintregister(list,OS_32);
  1707. loc.register64.reghi:=cg.getintregister(list,OS_32);
  1708. end
  1709. else
  1710. {$endif cpu64bitalu}
  1711. loc.register:=cg.getintregister(list,loc.size);
  1712. end;
  1713. LOC_CFPUREGISTER:
  1714. begin
  1715. loc.register:=cg.getfpuregister(list,loc.size);
  1716. end;
  1717. LOC_CMMREGISTER:
  1718. begin
  1719. loc.register:=cg.getmmregister(list,loc.size);
  1720. end;
  1721. end;
  1722. end;
  1723. procedure gen_alloc_regvar(list:TAsmList;sym: tabstractnormalvarsym; allocreg: boolean);
  1724. begin
  1725. if allocreg then
  1726. gen_alloc_regloc(list,sym.initialloc);
  1727. if (pi_has_label in current_procinfo.flags) then
  1728. begin
  1729. { Allocate register already, to prevent first allocation to be
  1730. inside a loop }
  1731. {$ifndef cpu64bitalu}
  1732. if sym.initialloc.size in [OS_64,OS_S64] then
  1733. begin
  1734. cg.a_reg_sync(list,sym.initialloc.register64.reglo);
  1735. cg.a_reg_sync(list,sym.initialloc.register64.reghi);
  1736. end
  1737. else
  1738. {$endif not cpu64bitalu}
  1739. cg.a_reg_sync(list,sym.initialloc.register);
  1740. end;
  1741. sym.localloc:=sym.initialloc;
  1742. end;
  1743. procedure gen_load_cgpara_loc(list: TAsmList; vardef: tdef; const para: TCGPara; var destloc: tlocation; reusepara: boolean);
  1744. procedure unget_para(const paraloc:TCGParaLocation);
  1745. begin
  1746. case paraloc.loc of
  1747. LOC_REGISTER :
  1748. begin
  1749. if getsupreg(paraloc.register)<first_int_imreg then
  1750. cg.ungetcpuregister(list,paraloc.register);
  1751. end;
  1752. LOC_MMREGISTER :
  1753. begin
  1754. if getsupreg(paraloc.register)<first_mm_imreg then
  1755. cg.ungetcpuregister(list,paraloc.register);
  1756. end;
  1757. LOC_FPUREGISTER :
  1758. begin
  1759. if getsupreg(paraloc.register)<first_fpu_imreg then
  1760. cg.ungetcpuregister(list,paraloc.register);
  1761. end;
  1762. end;
  1763. end;
  1764. var
  1765. paraloc : pcgparalocation;
  1766. href : treference;
  1767. sizeleft : aint;
  1768. {$if defined(sparc) or defined(arm)}
  1769. tempref : treference;
  1770. {$endif sparc}
  1771. {$ifndef cpu64bitalu}
  1772. reg64: tregister64;
  1773. {$endif not cpu64bitalu}
  1774. begin
  1775. paraloc:=para.location;
  1776. if not assigned(paraloc) then
  1777. internalerror(200408203);
  1778. { skip e.g. empty records }
  1779. if (paraloc^.loc = LOC_VOID) then
  1780. exit;
  1781. case destloc.loc of
  1782. LOC_REFERENCE :
  1783. begin
  1784. { If the parameter location is reused we don't need to copy
  1785. anything }
  1786. if not reusepara then
  1787. begin
  1788. href:=destloc.reference;
  1789. sizeleft:=para.intsize;
  1790. while assigned(paraloc) do
  1791. begin
  1792. if (paraloc^.size=OS_NO) then
  1793. begin
  1794. { Can only be a reference that contains the rest
  1795. of the parameter }
  1796. if (paraloc^.loc<>LOC_REFERENCE) or
  1797. assigned(paraloc^.next) then
  1798. internalerror(2005013010);
  1799. cg.a_load_cgparaloc_ref(list,paraloc^,href,sizeleft,destloc.reference.alignment);
  1800. inc(href.offset,sizeleft);
  1801. sizeleft:=0;
  1802. end
  1803. else
  1804. begin
  1805. cg.a_load_cgparaloc_ref(list,paraloc^,href,tcgsize2size[paraloc^.size],destloc.reference.alignment);
  1806. inc(href.offset,TCGSize2Size[paraloc^.size]);
  1807. dec(sizeleft,TCGSize2Size[paraloc^.size]);
  1808. end;
  1809. unget_para(paraloc^);
  1810. paraloc:=paraloc^.next;
  1811. end;
  1812. end;
  1813. end;
  1814. LOC_REGISTER,
  1815. LOC_CREGISTER :
  1816. begin
  1817. {$ifndef cpu64bitalu}
  1818. if (para.size in [OS_64,OS_S64,OS_F64]) and
  1819. (is_64bit(vardef) or
  1820. { in case of fpu emulation, or abi's that pass fpu values
  1821. via integer registers }
  1822. (vardef.typ=floatdef)) then
  1823. begin
  1824. case paraloc^.loc of
  1825. LOC_REGISTER:
  1826. begin
  1827. if not assigned(paraloc^.next) then
  1828. internalerror(200410104);
  1829. if (target_info.endian=ENDIAN_BIG) then
  1830. begin
  1831. { paraloc^ -> high
  1832. paraloc^.next -> low }
  1833. unget_para(paraloc^);
  1834. gen_alloc_regloc(list,destloc);
  1835. { reg->reg, alignment is irrelevant }
  1836. cg.a_load_cgparaloc_anyreg(list,OS_32,paraloc^,destloc.register64.reghi,4);
  1837. unget_para(paraloc^.next^);
  1838. cg.a_load_cgparaloc_anyreg(list,OS_32,paraloc^.next^,destloc.register64.reglo,4);
  1839. end
  1840. else
  1841. begin
  1842. { paraloc^ -> low
  1843. paraloc^.next -> high }
  1844. unget_para(paraloc^);
  1845. gen_alloc_regloc(list,destloc);
  1846. cg.a_load_cgparaloc_anyreg(list,OS_32,paraloc^,destloc.register64.reglo,4);
  1847. unget_para(paraloc^.next^);
  1848. cg.a_load_cgparaloc_anyreg(list,OS_32,paraloc^.next^,destloc.register64.reghi,4);
  1849. end;
  1850. end;
  1851. LOC_REFERENCE:
  1852. begin
  1853. gen_alloc_regloc(list,destloc);
  1854. reference_reset_base(href,paraloc^.reference.index,paraloc^.reference.offset,para.alignment);
  1855. cg64.a_load64_ref_reg(list,href,destloc.register64);
  1856. unget_para(paraloc^);
  1857. end;
  1858. else
  1859. internalerror(2005101501);
  1860. end
  1861. end
  1862. else
  1863. {$endif not cpu64bitalu}
  1864. begin
  1865. if assigned(paraloc^.next) then
  1866. internalerror(200410105);
  1867. unget_para(paraloc^);
  1868. gen_alloc_regloc(list,destloc);
  1869. cg.a_load_cgparaloc_anyreg(list,destloc.size,paraloc^,destloc.register,sizeof(aint));
  1870. end;
  1871. end;
  1872. LOC_FPUREGISTER,
  1873. LOC_CFPUREGISTER :
  1874. begin
  1875. {$if defined(sparc) or defined(arm)}
  1876. { Arm and Sparc passes floats in int registers, when loading to fpu register
  1877. we need a temp }
  1878. sizeleft := TCGSize2Size[destloc.size];
  1879. tg.GetTemp(list,sizeleft,sizeleft,tt_normal,tempref);
  1880. href:=tempref;
  1881. while assigned(paraloc) do
  1882. begin
  1883. unget_para(paraloc^);
  1884. cg.a_load_cgparaloc_ref(list,paraloc^,href,sizeleft,destloc.reference.alignment);
  1885. inc(href.offset,TCGSize2Size[paraloc^.size]);
  1886. dec(sizeleft,TCGSize2Size[paraloc^.size]);
  1887. paraloc:=paraloc^.next;
  1888. end;
  1889. gen_alloc_regloc(list,destloc);
  1890. cg.a_loadfpu_ref_reg(list,destloc.size,destloc.size,tempref,destloc.register);
  1891. tg.UnGetTemp(list,tempref);
  1892. {$else sparc}
  1893. unget_para(paraloc^);
  1894. gen_alloc_regloc(list,destloc);
  1895. { from register to register -> alignment is irrelevant }
  1896. cg.a_load_cgparaloc_anyreg(list,destloc.size,paraloc^,destloc.register,0);
  1897. if assigned(paraloc^.next) then
  1898. internalerror(200410109);
  1899. {$endif sparc}
  1900. end;
  1901. LOC_MMREGISTER,
  1902. LOC_CMMREGISTER :
  1903. begin
  1904. {$ifndef cpu64bitalu}
  1905. { ARM vfp floats are passed in integer registers }
  1906. if (para.size=OS_F64) and
  1907. (paraloc^.size in [OS_32,OS_S32]) and
  1908. use_vectorfpu(vardef) then
  1909. begin
  1910. { we need 2x32bit reg }
  1911. if not assigned(paraloc^.next) or
  1912. assigned(paraloc^.next^.next) then
  1913. internalerror(2009112421);
  1914. unget_para(paraloc^);
  1915. unget_para(paraloc^.next^);
  1916. gen_alloc_regloc(list,destloc);
  1917. if (target_info.endian=endian_big) then
  1918. { paraloc^ -> high
  1919. paraloc^.next -> low }
  1920. reg64:=joinreg64(paraloc^.next^.register,paraloc^.register)
  1921. else
  1922. reg64:=joinreg64(paraloc^.register,paraloc^.next^.register);
  1923. cg64.a_loadmm_intreg64_reg(list,OS_F64,reg64,destloc.register);
  1924. end
  1925. else
  1926. {$endif not cpu64bitalu}
  1927. begin
  1928. unget_para(paraloc^);
  1929. gen_alloc_regloc(list,destloc);
  1930. { from register to register -> alignment is irrelevant }
  1931. cg.a_load_cgparaloc_anyreg(list,destloc.size,paraloc^,destloc.register,0);
  1932. { data could come in two memory locations, for now
  1933. we simply ignore the sanity check (FK)
  1934. if assigned(paraloc^.next) then
  1935. internalerror(200410108);
  1936. }
  1937. end;
  1938. end;
  1939. else
  1940. internalerror(2010052903);
  1941. end;
  1942. end;
  1943. procedure gen_load_para_value(list:TAsmList);
  1944. procedure get_para(const paraloc:TCGParaLocation);
  1945. begin
  1946. case paraloc.loc of
  1947. LOC_REGISTER :
  1948. begin
  1949. if getsupreg(paraloc.register)<first_int_imreg then
  1950. cg.getcpuregister(list,paraloc.register);
  1951. end;
  1952. LOC_MMREGISTER :
  1953. begin
  1954. if getsupreg(paraloc.register)<first_mm_imreg then
  1955. cg.getcpuregister(list,paraloc.register);
  1956. end;
  1957. LOC_FPUREGISTER :
  1958. begin
  1959. if getsupreg(paraloc.register)<first_fpu_imreg then
  1960. cg.getcpuregister(list,paraloc.register);
  1961. end;
  1962. end;
  1963. end;
  1964. var
  1965. i : longint;
  1966. currpara : tparavarsym;
  1967. paraloc : pcgparalocation;
  1968. begin
  1969. if (po_assembler in current_procinfo.procdef.procoptions) or
  1970. { exceptfilters have a single hidden 'parentfp' parameter, which
  1971. is handled by tcg.g_proc_entry. }
  1972. (current_procinfo.procdef.proctypeoption=potype_exceptfilter) then
  1973. exit;
  1974. { Allocate registers used by parameters }
  1975. for i:=0 to current_procinfo.procdef.paras.count-1 do
  1976. begin
  1977. currpara:=tparavarsym(current_procinfo.procdef.paras[i]);
  1978. paraloc:=currpara.paraloc[calleeside].location;
  1979. while assigned(paraloc) do
  1980. begin
  1981. if paraloc^.loc in [LOC_REGISTER,LOC_FPUREGISTER,LOC_MMREGISTER] then
  1982. get_para(paraloc^);
  1983. paraloc:=paraloc^.next;
  1984. end;
  1985. end;
  1986. { Copy parameters to local references/registers }
  1987. for i:=0 to current_procinfo.procdef.paras.count-1 do
  1988. begin
  1989. currpara:=tparavarsym(current_procinfo.procdef.paras[i]);
  1990. gen_load_cgpara_loc(list,currpara.vardef,currpara.paraloc[calleeside],currpara.initialloc,paramanager.param_use_paraloc(currpara.paraloc[calleeside]));
  1991. { gen_load_cgpara_loc() already allocated the initialloc
  1992. -> don't allocate again }
  1993. if currpara.initialloc.loc in [LOC_CREGISTER,LOC_CFPUREGISTER,LOC_CMMREGISTER] then
  1994. gen_alloc_regvar(list,currpara,false);
  1995. end;
  1996. { generate copies of call by value parameters, must be done before
  1997. the initialization and body is parsed because the refcounts are
  1998. incremented using the local copies }
  1999. current_procinfo.procdef.parast.SymList.ForEachCall(@copyvalueparas,list);
  2000. {$ifdef powerpc}
  2001. { unget the register that contains the stack pointer before the procedure entry, }
  2002. { which is used to access the parameters in their original callee-side location }
  2003. if (tppcprocinfo(current_procinfo).needs_frame_pointer) then
  2004. cg.a_reg_dealloc(list,NR_R12);
  2005. {$endif powerpc}
  2006. {$ifdef powerpc64}
  2007. { unget the register that contains the stack pointer before the procedure entry, }
  2008. { which is used to access the parameters in their original callee-side location }
  2009. if (tppcprocinfo(current_procinfo).needs_frame_pointer) then
  2010. cg.a_reg_dealloc(list, NR_OLD_STACK_POINTER_REG);
  2011. {$endif powerpc64}
  2012. if not(po_assembler in current_procinfo.procdef.procoptions) then
  2013. begin
  2014. { has to be done here rather than in gen_initialize_code, because
  2015. the initialisation code is generated a) later and b) with
  2016. rad_backwards, so the register allocator would generate
  2017. information as if this code comes before loading the parameters
  2018. from their original registers to their local location }
  2019. if (localvartrashing <> -1) then
  2020. current_procinfo.procdef.localst.SymList.ForEachCall(@trash_variable,list);
  2021. { initialize refcounted paras, and trash others. Needed here
  2022. instead of in gen_initialize_code, because when a reference is
  2023. intialised or trashed while the pointer to that reference is kept
  2024. in a regvar, we add a register move and that one again has to
  2025. come after the parameter loading code as far as the register
  2026. allocator is concerned }
  2027. current_procinfo.procdef.parast.SymList.ForEachCall(@init_paras,list);
  2028. end;
  2029. end;
  2030. procedure gen_initialize_code(list:TAsmList);
  2031. begin
  2032. { initialize local data like ansistrings }
  2033. case current_procinfo.procdef.proctypeoption of
  2034. potype_unitinit:
  2035. begin
  2036. { this is also used for initialization of variables in a
  2037. program which does not have a globalsymtable }
  2038. if assigned(current_module.globalsymtable) then
  2039. TSymtable(current_module.globalsymtable).SymList.ForEachCall(@initialize_data,list);
  2040. TSymtable(current_module.localsymtable).SymList.ForEachCall(@initialize_data,list);
  2041. TSymtable(current_module.localsymtable).SymList.ForEachCall(@initialize_regvars,list);
  2042. end;
  2043. { units have seperate code for initilization and finalization }
  2044. potype_unitfinalize: ;
  2045. { program init/final is generated in separate procedure }
  2046. potype_proginit:
  2047. begin
  2048. TSymtable(current_module.localsymtable).SymList.ForEachCall(@initialize_regvars,list);
  2049. end;
  2050. else
  2051. current_procinfo.procdef.localst.SymList.ForEachCall(@initialize_data,list);
  2052. end;
  2053. { initialisizes temp. ansi/wide string data }
  2054. if (current_procinfo.procdef.proctypeoption<>potype_exceptfilter) then
  2055. inittempvariables(list);
  2056. {$ifdef OLDREGVARS}
  2057. load_regvars(list,nil);
  2058. {$endif OLDREGVARS}
  2059. end;
  2060. procedure gen_finalize_code(list:TAsmList);
  2061. var
  2062. old_current_procinfo: tprocinfo;
  2063. begin
  2064. old_current_procinfo:=current_procinfo;
  2065. if (current_procinfo.procdef.proctypeoption=potype_exceptfilter) then
  2066. begin
  2067. if (current_procinfo.parent.finalize_procinfo<>current_procinfo) then
  2068. exit;
  2069. current_procinfo:=current_procinfo.parent;
  2070. end;
  2071. {$ifdef OLDREGVARS}
  2072. cleanup_regvars(list);
  2073. {$endif OLDREGVARS}
  2074. { finalize temporary data }
  2075. finalizetempvariables(list);
  2076. { finalize local data like ansistrings}
  2077. case current_procinfo.procdef.proctypeoption of
  2078. potype_unitfinalize:
  2079. begin
  2080. { this is also used for initialization of variables in a
  2081. program which does not have a globalsymtable }
  2082. if assigned(current_module.globalsymtable) then
  2083. TSymtable(current_module.globalsymtable).SymList.ForEachCall(@finalize_static_data,list);
  2084. TSymtable(current_module.localsymtable).SymList.ForEachCall(@finalize_static_data,list);
  2085. end;
  2086. { units/progs have separate code for initialization and finalization }
  2087. potype_unitinit: ;
  2088. { program init/final is generated in separate procedure }
  2089. potype_proginit: ;
  2090. else
  2091. current_procinfo.procdef.localst.SymList.ForEachCall(@finalize_local_vars,list);
  2092. end;
  2093. { finalize paras data }
  2094. if assigned(current_procinfo.procdef.parast) and
  2095. not(po_assembler in current_procinfo.procdef.procoptions) then
  2096. current_procinfo.procdef.parast.SymList.ForEachCall(@final_paras,list);
  2097. current_procinfo:=old_current_procinfo;
  2098. end;
  2099. procedure gen_entry_code(list:TAsmList);
  2100. begin
  2101. { the actual profile code can clobber some registers,
  2102. therefore if the context must be saved, do it before
  2103. the actual call to the profile code
  2104. }
  2105. if (cs_profile in current_settings.moduleswitches) and
  2106. not(po_assembler in current_procinfo.procdef.procoptions) then
  2107. begin
  2108. { non-win32 can call mcout even in main }
  2109. if not (target_info.system in [system_i386_win32,system_i386_wdosx]) or
  2110. not (current_procinfo.procdef.proctypeoption=potype_proginit) then
  2111. begin
  2112. cg.g_profilecode(list);
  2113. end;
  2114. end;
  2115. { call startup helpers from main program }
  2116. if (current_procinfo.procdef.proctypeoption=potype_proginit) then
  2117. begin
  2118. { initialize units }
  2119. cg.allocallcpuregisters(list);
  2120. if not(current_module.islibrary) then
  2121. cg.a_call_name(list,'FPC_INITIALIZEUNITS',false)
  2122. else
  2123. cg.a_call_name(list,'FPC_LIBINITIALIZEUNITS',false);
  2124. cg.deallocallcpuregisters(list);
  2125. end;
  2126. list.concat(Tai_force_line.Create);
  2127. {$ifdef OLDREGVARS}
  2128. load_regvars(list,nil);
  2129. {$endif OLDREGVARS}
  2130. end;
  2131. procedure gen_exit_code(list:TAsmList);
  2132. begin
  2133. { call __EXIT for main program }
  2134. if (not DLLsource) and
  2135. (current_procinfo.procdef.proctypeoption=potype_proginit) then
  2136. cg.a_call_name(list,'FPC_DO_EXIT',false);
  2137. end;
  2138. {****************************************************************************
  2139. Entry/Exit
  2140. ****************************************************************************}
  2141. function has_alias_name(pd:tprocdef;const s:string):boolean;
  2142. var
  2143. item : TCmdStrListItem;
  2144. begin
  2145. result:=true;
  2146. if pd.mangledname=s then
  2147. exit;
  2148. item := TCmdStrListItem(pd.aliasnames.first);
  2149. while assigned(item) do
  2150. begin
  2151. if item.str=s then
  2152. exit;
  2153. item := TCmdStrListItem(item.next);
  2154. end;
  2155. result:=false;
  2156. end;
  2157. procedure alloc_proc_symbol(pd: tprocdef);
  2158. var
  2159. item : TCmdStrListItem;
  2160. begin
  2161. item := TCmdStrListItem(pd.aliasnames.first);
  2162. while assigned(item) do
  2163. begin
  2164. current_asmdata.DefineAsmSymbol(item.str,AB_GLOBAL,AT_FUNCTION);
  2165. item := TCmdStrListItem(item.next);
  2166. end;
  2167. end;
  2168. procedure gen_proc_symbol(list:TAsmList);
  2169. var
  2170. item,
  2171. previtem : TCmdStrListItem;
  2172. begin
  2173. previtem:=nil;
  2174. item := TCmdStrListItem(current_procinfo.procdef.aliasnames.first);
  2175. while assigned(item) do
  2176. begin
  2177. {$ifdef arm}
  2178. if current_settings.cputype in cpu_thumb2 then
  2179. list.concat(tai_thumb_func.create);
  2180. {$endif arm}
  2181. { "double link" all procedure entry symbols via .reference }
  2182. { directives on darwin, because otherwise the linker }
  2183. { sometimes strips the procedure if only on of the symbols }
  2184. { is referenced }
  2185. if assigned(previtem) and
  2186. (target_info.system in systems_darwin) then
  2187. list.concat(tai_directive.create(asd_reference,item.str));
  2188. if (cs_profile in current_settings.moduleswitches) or
  2189. (po_global in current_procinfo.procdef.procoptions) then
  2190. list.concat(Tai_symbol.createname_global(item.str,AT_FUNCTION,0))
  2191. else
  2192. list.concat(Tai_symbol.createname(item.str,AT_FUNCTION,0));
  2193. if assigned(previtem) and
  2194. (target_info.system in systems_darwin) then
  2195. list.concat(tai_directive.create(asd_reference,previtem.str));
  2196. if not(af_stabs_use_function_absolute_addresses in target_asm.flags) then
  2197. list.concat(Tai_function_name.create(item.str));
  2198. previtem:=item;
  2199. item := TCmdStrListItem(item.next);
  2200. end;
  2201. current_procinfo.procdef.procstarttai:=tai(list.last);
  2202. end;
  2203. procedure gen_proc_symbol_end(list:TAsmList);
  2204. begin
  2205. list.concat(Tai_symbol_end.Createname(current_procinfo.procdef.mangledname));
  2206. current_procinfo.procdef.procendtai:=tai(list.last);
  2207. if (current_module.islibrary) then
  2208. if (current_procinfo.procdef.proctypeoption = potype_proginit) then
  2209. { setinitname may generate a new section -> don't add to the
  2210. current list, because we assume this remains a text section }
  2211. exportlib.setinitname(current_asmdata.AsmLists[al_exports],current_procinfo.procdef.mangledname);
  2212. if (current_procinfo.procdef.proctypeoption=potype_proginit) then
  2213. begin
  2214. if (target_info.system in (systems_darwin+[system_powerpc_macos]+systems_aix)) and
  2215. not(current_module.islibrary) then
  2216. begin
  2217. new_section(list,sec_code,'',4);
  2218. list.concat(tai_symbol.createname_global(
  2219. target_info.cprefix+mainaliasname,AT_FUNCTION,0));
  2220. { keep argc, argv and envp properly on the stack }
  2221. if not(target_info.system in systems_aix) then
  2222. cg.a_jmp_name(list,target_info.cprefix+'FPC_SYSTEMMAIN')
  2223. else
  2224. cg.a_call_name(list,target_info.cprefix+'FPC_SYSTEMMAIN',false)
  2225. end;
  2226. end;
  2227. end;
  2228. procedure gen_proc_entry_code(list:TAsmList);
  2229. var
  2230. hitemp,
  2231. lotemp : longint;
  2232. begin
  2233. { generate call frame marker for dwarf call frame info }
  2234. current_asmdata.asmcfi.start_frame(list);
  2235. { All temps are know, write offsets used for information }
  2236. if (cs_asm_source in current_settings.globalswitches) then
  2237. begin
  2238. if tg.direction>0 then
  2239. begin
  2240. lotemp:=current_procinfo.tempstart;
  2241. hitemp:=tg.lasttemp;
  2242. end
  2243. else
  2244. begin
  2245. lotemp:=tg.lasttemp;
  2246. hitemp:=current_procinfo.tempstart;
  2247. end;
  2248. list.concat(Tai_comment.Create(strpnew('Temps allocated between '+std_regname(current_procinfo.framepointer)+
  2249. tostr_with_plus(lotemp)+' and '+std_regname(current_procinfo.framepointer)+tostr_with_plus(hitemp))));
  2250. end;
  2251. { generate target specific proc entry code }
  2252. cg.g_proc_entry(list,current_procinfo.calc_stackframe_size,(po_nostackframe in current_procinfo.procdef.procoptions));
  2253. end;
  2254. procedure gen_proc_exit_code(list:TAsmList);
  2255. var
  2256. parasize : longint;
  2257. begin
  2258. { c style clearstack does not need to remove parameters from the stack, only the
  2259. return value when it was pushed by arguments }
  2260. if current_procinfo.procdef.proccalloption in clearstack_pocalls then
  2261. begin
  2262. parasize:=0;
  2263. if paramanager.ret_in_param(current_procinfo.procdef.returndef,current_procinfo.procdef.proccalloption) then
  2264. inc(parasize,sizeof(pint));
  2265. end
  2266. else
  2267. begin
  2268. parasize:=current_procinfo.para_stack_size;
  2269. { the parent frame pointer para has to be removed by the caller in
  2270. case of Delphi-style parent frame pointer passing }
  2271. if not paramanager.use_fixed_stack and
  2272. (po_delphi_nested_cc in current_procinfo.procdef.procoptions) then
  2273. dec(parasize,sizeof(pint));
  2274. end;
  2275. { generate target specific proc exit code }
  2276. cg.g_proc_exit(list,parasize,(po_nostackframe in current_procinfo.procdef.procoptions));
  2277. { release return registers, needed for optimizer }
  2278. if not is_void(current_procinfo.procdef.returndef) then
  2279. paramanager.freecgpara(list,current_procinfo.procdef.funcretloc[calleeside]);
  2280. { end of frame marker for call frame info }
  2281. current_asmdata.asmcfi.end_frame(list);
  2282. end;
  2283. procedure gen_stack_check_size_para(list:TAsmList);
  2284. var
  2285. paraloc1 : tcgpara;
  2286. begin
  2287. paraloc1.init;
  2288. paramanager.getintparaloc(pocall_default,1,paraloc1);
  2289. cg.a_load_const_cgpara(list,OS_INT,current_procinfo.calc_stackframe_size,paraloc1);
  2290. paramanager.freecgpara(list,paraloc1);
  2291. paraloc1.done;
  2292. end;
  2293. procedure gen_stack_check_call(list:TAsmList);
  2294. var
  2295. paraloc1 : tcgpara;
  2296. begin
  2297. paraloc1.init;
  2298. { Also alloc the register needed for the parameter }
  2299. paramanager.getintparaloc(pocall_default,1,paraloc1);
  2300. paramanager.freecgpara(list,paraloc1);
  2301. { Call the helper }
  2302. cg.allocallcpuregisters(list);
  2303. cg.a_call_name(list,'FPC_STACKCHECK',false);
  2304. cg.deallocallcpuregisters(list);
  2305. paraloc1.done;
  2306. end;
  2307. procedure gen_save_used_regs(list:TAsmList);
  2308. begin
  2309. { Pure assembler routines need to save the registers themselves }
  2310. if (po_assembler in current_procinfo.procdef.procoptions) then
  2311. exit;
  2312. { oldfpccall expects all registers to be destroyed }
  2313. if current_procinfo.procdef.proccalloption<>pocall_oldfpccall then
  2314. cg.g_save_registers(list);
  2315. end;
  2316. procedure gen_restore_used_regs(list:TAsmList);
  2317. begin
  2318. { Pure assembler routines need to save the registers themselves }
  2319. if (po_assembler in current_procinfo.procdef.procoptions) then
  2320. exit;
  2321. { oldfpccall expects all registers to be destroyed }
  2322. if current_procinfo.procdef.proccalloption<>pocall_oldfpccall then
  2323. cg.g_restore_registers(list);
  2324. end;
  2325. {****************************************************************************
  2326. External handling
  2327. ****************************************************************************}
  2328. procedure gen_external_stub(list:TAsmList;pd:tprocdef;const externalname:string);
  2329. begin
  2330. create_codegen;
  2331. { add the procedure to the al_procedures }
  2332. maybe_new_object_file(list);
  2333. new_section(list,sec_code,lower(pd.mangledname),current_settings.alignment.procalign);
  2334. list.concat(Tai_align.create(current_settings.alignment.procalign));
  2335. if (po_global in pd.procoptions) then
  2336. list.concat(Tai_symbol.createname_global(pd.mangledname,AT_FUNCTION,0))
  2337. else
  2338. list.concat(Tai_symbol.createname(pd.mangledname,AT_FUNCTION,0));
  2339. cg.g_external_wrapper(list,pd,externalname);
  2340. destroy_codegen;
  2341. end;
  2342. {****************************************************************************
  2343. Const Data
  2344. ****************************************************************************}
  2345. procedure insertbssdata(sym : tstaticvarsym);
  2346. var
  2347. l : asizeint;
  2348. varalign : shortint;
  2349. storefilepos : tfileposinfo;
  2350. list : TAsmList;
  2351. sectype : TAsmSectiontype;
  2352. begin
  2353. storefilepos:=current_filepos;
  2354. current_filepos:=sym.fileinfo;
  2355. l:=sym.getsize;
  2356. varalign:=sym.vardef.alignment;
  2357. if (varalign=0) then
  2358. varalign:=var_align_size(l)
  2359. else
  2360. varalign:=var_align(varalign);
  2361. if tf_section_threadvars in target_info.flags then
  2362. begin
  2363. if (vo_is_thread_var in sym.varoptions) then
  2364. begin
  2365. list:=current_asmdata.asmlists[al_threadvars];
  2366. sectype:=sec_threadvar;
  2367. end
  2368. else
  2369. begin
  2370. list:=current_asmdata.asmlists[al_globals];
  2371. sectype:=sec_bss;
  2372. end;
  2373. end
  2374. else
  2375. begin
  2376. if (vo_is_thread_var in sym.varoptions) then
  2377. begin
  2378. inc(l,sizeof(pint));
  2379. { it doesn't help to set a higher alignment, as }
  2380. { the first sizeof(pint) bytes field will offset }
  2381. { everything anyway }
  2382. varalign:=sizeof(pint);
  2383. end;
  2384. list:=current_asmdata.asmlists[al_globals];
  2385. sectype:=sec_bss;
  2386. end;
  2387. maybe_new_object_file(list);
  2388. if vo_has_section in sym.varoptions then
  2389. new_section(list,sec_user,sym.section,varalign)
  2390. else
  2391. new_section(list,sectype,lower(sym.mangledname),varalign);
  2392. if (sym.owner.symtabletype=globalsymtable) or
  2393. create_smartlink or
  2394. DLLSource or
  2395. (assigned(current_procinfo) and
  2396. (po_inline in current_procinfo.procdef.procoptions)) or
  2397. (vo_is_public in sym.varoptions) then
  2398. list.concat(Tai_datablock.create_global(sym.mangledname,l))
  2399. else
  2400. list.concat(Tai_datablock.create(sym.mangledname,l));
  2401. current_filepos:=storefilepos;
  2402. end;
  2403. procedure gen_alloc_symtable(list:TAsmList;st:TSymtable);
  2404. procedure setlocalloc(vs:tabstractnormalvarsym);
  2405. begin
  2406. if cs_asm_source in current_settings.globalswitches then
  2407. begin
  2408. case vs.initialloc.loc of
  2409. LOC_REFERENCE :
  2410. begin
  2411. if not assigned(vs.initialloc.reference.symbol) then
  2412. list.concat(Tai_comment.Create(strpnew('Var '+vs.realname+' located at '+
  2413. std_regname(vs.initialloc.reference.base)+tostr_with_plus(vs.initialloc.reference.offset))));
  2414. end;
  2415. end;
  2416. end;
  2417. vs.localloc:=vs.initialloc;
  2418. end;
  2419. var
  2420. i : longint;
  2421. sym : tsym;
  2422. vs : tabstractnormalvarsym;
  2423. isaddr : boolean;
  2424. begin
  2425. for i:=0 to st.SymList.Count-1 do
  2426. begin
  2427. sym:=tsym(st.SymList[i]);
  2428. case sym.typ of
  2429. staticvarsym :
  2430. begin
  2431. vs:=tabstractnormalvarsym(sym);
  2432. { The code in loadnode.pass_generatecode will create the
  2433. LOC_REFERENCE instead for all none register variables. This is
  2434. required because we can't store an asmsymbol in the localloc because
  2435. the asmsymbol is invalid after an unit is compiled. This gives
  2436. problems when this procedure is inlined in another unit (PFV) }
  2437. if vs.is_regvar(false) then
  2438. begin
  2439. vs.initialloc.loc:=tvarregable2tcgloc[vs.varregable];
  2440. vs.initialloc.size:=def_cgsize(vs.vardef);
  2441. gen_alloc_regvar(list,vs,true);
  2442. setlocalloc(vs);
  2443. end;
  2444. end;
  2445. paravarsym :
  2446. begin
  2447. vs:=tabstractnormalvarsym(sym);
  2448. { Parameters passed to assembler procedures need to be kept
  2449. in the original location }
  2450. if (po_assembler in current_procinfo.procdef.procoptions) then
  2451. tparavarsym(vs).paraloc[calleeside].get_location(vs.initialloc)
  2452. { exception filters receive their frame pointer as a parameter }
  2453. else if (current_procinfo.procdef.proctypeoption=potype_exceptfilter) and
  2454. (vo_is_parentfp in vs.varoptions) then
  2455. begin
  2456. location_reset(vs.initialloc,LOC_REGISTER,OS_ADDR);
  2457. vs.initialloc.register:=NR_FRAME_POINTER_REG;
  2458. end
  2459. else
  2460. begin
  2461. isaddr:=paramanager.push_addr_param(vs.varspez,vs.vardef,current_procinfo.procdef.proccalloption);
  2462. if isaddr then
  2463. vs.initialloc.size:=OS_ADDR
  2464. else
  2465. vs.initialloc.size:=def_cgsize(vs.vardef);
  2466. if vs.is_regvar(isaddr) then
  2467. vs.initialloc.loc:=tvarregable2tcgloc[vs.varregable]
  2468. else
  2469. begin
  2470. vs.initialloc.loc:=LOC_REFERENCE;
  2471. { Reuse the parameter location for values to are at a single location on the stack }
  2472. if paramanager.param_use_paraloc(tparavarsym(sym).paraloc[calleeside]) then
  2473. begin
  2474. reference_reset_base(vs.initialloc.reference,tparavarsym(sym).paraloc[calleeside].location^.reference.index,
  2475. tparavarsym(sym).paraloc[calleeside].location^.reference.offset,tparavarsym(sym).paraloc[calleeside].alignment);
  2476. end
  2477. else
  2478. begin
  2479. if isaddr then
  2480. tg.GetLocal(list,sizeof(pint),voidpointertype,vs.initialloc.reference)
  2481. else
  2482. tg.GetLocal(list,vs.getsize,tparavarsym(sym).paraloc[calleeside].alignment,vs.vardef,vs.initialloc.reference);
  2483. end;
  2484. end;
  2485. end;
  2486. setlocalloc(vs);
  2487. end;
  2488. localvarsym :
  2489. begin
  2490. vs:=tabstractnormalvarsym(sym);
  2491. vs.initialloc.size:=def_cgsize(vs.vardef);
  2492. if (m_delphi in current_settings.modeswitches) and
  2493. (po_assembler in current_procinfo.procdef.procoptions) and
  2494. (vo_is_funcret in vs.varoptions) and
  2495. (vs.refs=0) then
  2496. begin
  2497. { not referenced, so don't allocate. Use dummy to }
  2498. { avoid ie's later on because of LOC_INVALID }
  2499. vs.initialloc.loc:=LOC_REGISTER;
  2500. vs.initialloc.size:=OS_INT;
  2501. vs.initialloc.register:=NR_FUNCTION_RESULT_REG;
  2502. end
  2503. else if vs.is_regvar(false) then
  2504. begin
  2505. vs.initialloc.loc:=tvarregable2tcgloc[vs.varregable];
  2506. gen_alloc_regvar(list,vs,true);
  2507. end
  2508. else
  2509. begin
  2510. vs.initialloc.loc:=LOC_REFERENCE;
  2511. tg.GetLocal(list,vs.getsize,vs.vardef,vs.initialloc.reference);
  2512. end;
  2513. setlocalloc(vs);
  2514. end;
  2515. end;
  2516. end;
  2517. end;
  2518. procedure add_regvars(var rv: tusedregvars; const location: tlocation);
  2519. begin
  2520. case location.loc of
  2521. LOC_CREGISTER:
  2522. {$ifndef cpu64bitalu}
  2523. if location.size in [OS_64,OS_S64] then
  2524. begin
  2525. rv.intregvars.addnodup(getsupreg(location.register64.reglo));
  2526. rv.intregvars.addnodup(getsupreg(location.register64.reghi));
  2527. end
  2528. else
  2529. {$endif not cpu64bitalu}
  2530. rv.intregvars.addnodup(getsupreg(location.register));
  2531. LOC_CFPUREGISTER:
  2532. rv.fpuregvars.addnodup(getsupreg(location.register));
  2533. LOC_CMMREGISTER:
  2534. rv.mmregvars.addnodup(getsupreg(location.register));
  2535. end;
  2536. end;
  2537. function do_get_used_regvars(var n: tnode; arg: pointer): foreachnoderesult;
  2538. var
  2539. rv: pusedregvars absolute arg;
  2540. begin
  2541. case (n.nodetype) of
  2542. temprefn:
  2543. { We only have to synchronise a tempnode before a loop if it is }
  2544. { not created inside the loop, and only synchronise after the }
  2545. { loop if it's not destroyed inside the loop. If it's created }
  2546. { before the loop and not yet destroyed, then before the loop }
  2547. { is secondpassed tempinfo^.valid will be true, and we get the }
  2548. { correct registers. If it's not destroyed inside the loop, }
  2549. { then after the loop has been secondpassed tempinfo^.valid }
  2550. { be true and we also get the right registers. In other cases, }
  2551. { tempinfo^.valid will be false and so we do not add }
  2552. { unnecessary registers. This way, we don't have to look at }
  2553. { tempcreate and tempdestroy nodes to get this info (JM) }
  2554. if (ti_valid in ttemprefnode(n).tempinfo^.flags) then
  2555. add_regvars(rv^,ttemprefnode(n).tempinfo^.location);
  2556. loadn:
  2557. if (tloadnode(n).symtableentry.typ in [staticvarsym,localvarsym,paravarsym]) then
  2558. add_regvars(rv^,tabstractnormalvarsym(tloadnode(n).symtableentry).localloc);
  2559. vecn:
  2560. { range checks sometimes need the high parameter }
  2561. if (cs_check_range in current_settings.localswitches) and
  2562. (is_open_array(tvecnode(n).left.resultdef) or
  2563. is_array_of_const(tvecnode(n).left.resultdef)) and
  2564. not(current_procinfo.procdef.proccalloption in cdecl_pocalls) then
  2565. add_regvars(rv^,tabstractnormalvarsym(get_high_value_sym(tparavarsym(tloadnode(tvecnode(n).left).symtableentry))).localloc)
  2566. end;
  2567. result := fen_true;
  2568. end;
  2569. procedure get_used_regvars(n: tnode; var rv: tusedregvars);
  2570. begin
  2571. foreachnodestatic(n,@do_get_used_regvars,@rv);
  2572. end;
  2573. (*
  2574. See comments at declaration of pusedregvarscommon
  2575. function do_get_used_regvars_common(var n: tnode; arg: pointer): foreachnoderesult;
  2576. var
  2577. rv: pusedregvarscommon absolute arg;
  2578. begin
  2579. if (n.nodetype = loadn) and
  2580. (tloadnode(n).symtableentry.typ in [staticvarsym,localvarsym,paravarsym]) then
  2581. with tabstractnormalvarsym(tloadnode(n).symtableentry).localloc do
  2582. case loc of
  2583. LOC_CREGISTER:
  2584. { if not yet encountered in this node tree }
  2585. if (rv^.myregvars.intregvars.addnodup(getsupreg(register))) and
  2586. { but nevertheless already encountered somewhere }
  2587. not(rv^.allregvars.intregvars.addnodup(getsupreg(register))) then
  2588. { then it's a regvar used in two or more node trees }
  2589. rv^.commonregvars.intregvars.addnodup(getsupreg(register));
  2590. LOC_CFPUREGISTER:
  2591. if (rv^.myregvars.intregvars.addnodup(getsupreg(register))) and
  2592. not(rv^.allregvars.intregvars.addnodup(getsupreg(register))) then
  2593. rv^.commonregvars.intregvars.addnodup(getsupreg(register));
  2594. LOC_CMMREGISTER:
  2595. if (rv^.myregvars.intregvars.addnodup(getsupreg(register))) and
  2596. not(rv^.allregvars.intregvars.addnodup(getsupreg(register))) then
  2597. rv^.commonregvars.intregvars.addnodup(getsupreg(register));
  2598. end;
  2599. result := fen_true;
  2600. end;
  2601. procedure get_used_regvars_common(n: tnode; var rv: tusedregvarscommon);
  2602. begin
  2603. rv.myregvars.intregvars.clear;
  2604. rv.myregvars.fpuregvars.clear;
  2605. rv.myregvars.mmregvars.clear;
  2606. foreachnodestatic(n,@do_get_used_regvars_common,@rv);
  2607. end;
  2608. *)
  2609. procedure gen_sync_regvars(list:TAsmList; var rv: tusedregvars);
  2610. var
  2611. count: longint;
  2612. begin
  2613. for count := 1 to rv.intregvars.length do
  2614. cg.a_reg_sync(list,newreg(R_INTREGISTER,rv.intregvars.readidx(count-1),R_SUBWHOLE));
  2615. for count := 1 to rv.fpuregvars.length do
  2616. cg.a_reg_sync(list,newreg(R_FPUREGISTER,rv.fpuregvars.readidx(count-1),R_SUBWHOLE));
  2617. for count := 1 to rv.mmregvars.length do
  2618. cg.a_reg_sync(list,newreg(R_MMREGISTER,rv.mmregvars.readidx(count-1),R_SUBWHOLE));
  2619. end;
  2620. {*****************************************************************************
  2621. SSA support
  2622. *****************************************************************************}
  2623. type
  2624. preplaceregrec = ^treplaceregrec;
  2625. treplaceregrec = record
  2626. old, new: tregister;
  2627. {$ifndef cpu64bitalu}
  2628. oldhi, newhi: tregister;
  2629. {$endif not cpu64bitalu}
  2630. ressym: tsym;
  2631. { moved sym }
  2632. sym : tsym;
  2633. end;
  2634. function doreplace(var n: tnode; para: pointer): foreachnoderesult;
  2635. var
  2636. rr: preplaceregrec absolute para;
  2637. begin
  2638. result := fen_false;
  2639. if (nf_is_funcret in n.flags) and (fc_exit in flowcontrol) then
  2640. exit;
  2641. case n.nodetype of
  2642. loadn:
  2643. begin
  2644. if (tabstractvarsym(tloadnode(n).symtableentry).varoptions * [vo_is_dll_var, vo_is_thread_var] = []) and
  2645. not assigned(tloadnode(n).left) and
  2646. ((tloadnode(n).symtableentry <> rr^.ressym) or
  2647. not(fc_exit in flowcontrol)
  2648. ) and
  2649. (tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.loc in [LOC_CREGISTER,LOC_CFPUREGISTER,LOC_CMMXREGISTER,LOC_CMMREGISTER]) and
  2650. (tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.register = rr^.old) then
  2651. begin
  2652. {$ifndef cpu64bitalu}
  2653. { it's possible a 64 bit location was shifted and/xor typecasted }
  2654. { in a 32 bit value, so only 1 register was left in the location }
  2655. if (tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.size in [OS_64,OS_S64]) then
  2656. if (tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.register64.reghi = rr^.oldhi) then
  2657. tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.register64.reghi := rr^.newhi
  2658. else
  2659. exit;
  2660. {$endif not cpu64bitalu}
  2661. tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.register := rr^.new;
  2662. rr^.sym := tabstractnormalvarsym(tloadnode(n).symtableentry);
  2663. result := fen_norecurse_true;
  2664. end;
  2665. end;
  2666. temprefn:
  2667. begin
  2668. if (ti_valid in ttemprefnode(n).tempinfo^.flags) and
  2669. (ttemprefnode(n).tempinfo^.location.loc in [LOC_CREGISTER,LOC_CFPUREGISTER,LOC_CMMXREGISTER,LOC_CMMREGISTER]) and
  2670. (ttemprefnode(n).tempinfo^.location.register = rr^.old) then
  2671. begin
  2672. {$ifndef cpu64bitalu}
  2673. { it's possible a 64 bit location was shifted and/xor typecasted }
  2674. { in a 32 bit value, so only 1 register was left in the location }
  2675. if (ttemprefnode(n).tempinfo^.location.size in [OS_64,OS_S64]) then
  2676. if (ttemprefnode(n).tempinfo^.location.register64.reghi = rr^.oldhi) then
  2677. ttemprefnode(n).tempinfo^.location.register64.reghi := rr^.newhi
  2678. else
  2679. exit;
  2680. {$endif not cpu64bitalu}
  2681. ttemprefnode(n).tempinfo^.location.register := rr^.new;
  2682. result := fen_norecurse_true;
  2683. end;
  2684. end;
  2685. { optimize the searching a bit }
  2686. derefn,addrn,
  2687. calln,inlinen,casen,
  2688. addn,subn,muln,
  2689. andn,orn,xorn,
  2690. ltn,lten,gtn,gten,equaln,unequaln,
  2691. slashn,divn,shrn,shln,notn,
  2692. inn,
  2693. asn,isn:
  2694. result := fen_norecurse_false;
  2695. end;
  2696. end;
  2697. procedure maybechangeloadnodereg(list: TAsmList; var n: tnode; reload: boolean);
  2698. var
  2699. rr: treplaceregrec;
  2700. begin
  2701. if not (n.location.loc in [LOC_CREGISTER,LOC_CFPUREGISTER,LOC_CMMXREGISTER,LOC_CMMREGISTER]) or
  2702. ([fc_inflowcontrol,fc_gotolabel,fc_lefthandled] * flowcontrol <> []) then
  2703. exit;
  2704. rr.old := n.location.register;
  2705. rr.ressym := nil;
  2706. rr.sym := nil;
  2707. {$ifndef cpu64bitalu}
  2708. rr.oldhi := NR_NO;
  2709. {$endif not cpu64bitalu}
  2710. case n.location.loc of
  2711. LOC_CREGISTER:
  2712. begin
  2713. {$ifndef cpu64bitalu}
  2714. if (n.location.size in [OS_64,OS_S64]) then
  2715. begin
  2716. rr.oldhi := n.location.register64.reghi;
  2717. rr.new := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  2718. rr.newhi := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  2719. end
  2720. else
  2721. {$endif not cpu64bitalu}
  2722. rr.new := cg.getintregister(current_asmdata.CurrAsmList,n.location.size);
  2723. end;
  2724. LOC_CFPUREGISTER:
  2725. rr.new := cg.getfpuregister(current_asmdata.CurrAsmList,n.location.size);
  2726. {$ifdef SUPPORT_MMX}
  2727. LOC_CMMXREGISTER:
  2728. rr.new := tcgx86(cg).getmmxregister(current_asmdata.CurrAsmList);
  2729. {$endif SUPPORT_MMX}
  2730. LOC_CMMREGISTER:
  2731. rr.new := cg.getmmregister(current_asmdata.CurrAsmList,n.location.size);
  2732. else
  2733. exit;
  2734. end;
  2735. if not is_void(current_procinfo.procdef.returndef) and
  2736. assigned(current_procinfo.procdef.funcretsym) and
  2737. (tabstractvarsym(current_procinfo.procdef.funcretsym).refs <> 0) then
  2738. if (current_procinfo.procdef.proctypeoption=potype_constructor) then
  2739. rr.ressym:=tsym(current_procinfo.procdef.parast.Find('self'))
  2740. else
  2741. rr.ressym:=current_procinfo.procdef.funcretsym;
  2742. if not foreachnodestatic(n,@doreplace,@rr) then
  2743. exit;
  2744. if reload then
  2745. case n.location.loc of
  2746. LOC_CREGISTER:
  2747. begin
  2748. {$ifndef cpu64bitalu}
  2749. if (n.location.size in [OS_64,OS_S64]) then
  2750. cg64.a_load64_reg_reg(list,n.location.register64,joinreg64(rr.new,rr.newhi))
  2751. else
  2752. {$endif not cpu64bitalu}
  2753. cg.a_load_reg_reg(list,n.location.size,n.location.size,n.location.register,rr.new);
  2754. end;
  2755. LOC_CFPUREGISTER:
  2756. cg.a_loadfpu_reg_reg(list,n.location.size,n.location.size,n.location.register,rr.new);
  2757. {$ifdef SUPPORT_MMX}
  2758. LOC_CMMXREGISTER:
  2759. cg.a_loadmm_reg_reg(list,OS_M64,OS_M64,n.location.register,rr.new,nil);
  2760. {$endif SUPPORT_MMX}
  2761. LOC_CMMREGISTER:
  2762. cg.a_loadmm_reg_reg(list,n.location.size,n.location.size,n.location.register,rr.new,nil);
  2763. else
  2764. internalerror(2006090920);
  2765. end;
  2766. { now that we've change the loadn/temp, also change the node result location }
  2767. {$ifndef cpu64bitalu}
  2768. if (n.location.size in [OS_64,OS_S64]) then
  2769. begin
  2770. n.location.register64.reglo := rr.new;
  2771. n.location.register64.reghi := rr.newhi;
  2772. if assigned(rr.sym) then
  2773. list.concat(tai_varloc.create64(rr.sym,rr.new,rr.newhi));
  2774. end
  2775. else
  2776. {$endif not cpu64bitalu}
  2777. begin
  2778. n.location.register := rr.new;
  2779. if assigned(rr.sym) then
  2780. list.concat(tai_varloc.create(rr.sym,rr.new));
  2781. end;
  2782. end;
  2783. procedure gen_free_symtable(list:TAsmList;st:TSymtable);
  2784. var
  2785. i : longint;
  2786. sym : tsym;
  2787. begin
  2788. for i:=0 to st.SymList.Count-1 do
  2789. begin
  2790. sym:=tsym(st.SymList[i]);
  2791. if (sym.typ in [staticvarsym,localvarsym,paravarsym]) then
  2792. begin
  2793. with tabstractnormalvarsym(sym) do
  2794. begin
  2795. { Note: We need to keep the data available in memory
  2796. for the sub procedures that can access local data
  2797. in the parent procedures }
  2798. case localloc.loc of
  2799. LOC_CREGISTER :
  2800. if (pi_has_label in current_procinfo.flags) then
  2801. {$ifndef cpu64bitalu}
  2802. if def_cgsize(vardef) in [OS_64,OS_S64] then
  2803. begin
  2804. cg.a_reg_sync(list,localloc.register64.reglo);
  2805. cg.a_reg_sync(list,localloc.register64.reghi);
  2806. end
  2807. else
  2808. {$endif not cpu64bitalu}
  2809. cg.a_reg_sync(list,localloc.register);
  2810. LOC_CFPUREGISTER,
  2811. LOC_CMMREGISTER:
  2812. if (pi_has_label in current_procinfo.flags) then
  2813. cg.a_reg_sync(list,localloc.register);
  2814. LOC_REFERENCE :
  2815. begin
  2816. if typ in [localvarsym,paravarsym] then
  2817. tg.Ungetlocal(list,localloc.reference);
  2818. end;
  2819. end;
  2820. end;
  2821. end;
  2822. end;
  2823. end;
  2824. procedure gen_intf_wrapper(list:TAsmList;_class:tobjectdef);
  2825. var
  2826. i,j : longint;
  2827. tmps : string;
  2828. pd : TProcdef;
  2829. ImplIntf : TImplementedInterface;
  2830. begin
  2831. for i:=0 to _class.ImplementedInterfaces.count-1 do
  2832. begin
  2833. ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]);
  2834. if (ImplIntf=ImplIntf.VtblImplIntf) and
  2835. assigned(ImplIntf.ProcDefs) then
  2836. begin
  2837. maybe_new_object_file(list);
  2838. for j:=0 to ImplIntf.ProcDefs.Count-1 do
  2839. begin
  2840. pd:=TProcdef(ImplIntf.ProcDefs[j]);
  2841. tmps:=make_mangledname('WRPR',_class.owner,_class.objname^+'_$_'+
  2842. ImplIntf.IntfDef.objname^+'_$_'+tostr(j)+'_$_'+pd.mangledname);
  2843. { create wrapper code }
  2844. new_section(list,sec_code,tmps,0);
  2845. cg.init_register_allocators;
  2846. cg.g_intf_wrapper(list,pd,tmps,ImplIntf.ioffset);
  2847. cg.done_register_allocators;
  2848. end;
  2849. end;
  2850. end;
  2851. end;
  2852. procedure gen_intf_wrappers(list:TAsmList;st:TSymtable;nested:boolean);
  2853. var
  2854. i : longint;
  2855. def : tdef;
  2856. begin
  2857. if not nested then
  2858. create_codegen;
  2859. for i:=0 to st.DefList.Count-1 do
  2860. begin
  2861. def:=tdef(st.DefList[i]);
  2862. { if def can contain nested types then handle it symtable }
  2863. if def.typ in [objectdef,recorddef] then
  2864. gen_intf_wrappers(list,tabstractrecorddef(def).symtable,true);
  2865. if is_class(def) then
  2866. gen_intf_wrapper(list,tobjectdef(def));
  2867. end;
  2868. if not nested then
  2869. destroy_codegen;
  2870. end;
  2871. procedure gen_load_vmt_register(list:TAsmList;objdef:tobjectdef;selfloc:tlocation;var vmtreg:tregister);
  2872. var
  2873. href : treference;
  2874. begin
  2875. if is_object(objdef) then
  2876. begin
  2877. case selfloc.loc of
  2878. LOC_CREFERENCE,
  2879. LOC_REFERENCE:
  2880. begin
  2881. reference_reset_base(href,cg.getaddressregister(list),objdef.vmt_offset,sizeof(pint));
  2882. cg.a_loadaddr_ref_reg(list,selfloc.reference,href.base);
  2883. end;
  2884. else
  2885. internalerror(200305056);
  2886. end;
  2887. end
  2888. else
  2889. { This is also valid for Objective-C classes: vmt_offset is 0 there,
  2890. and the first "field" of an Objective-C class instance is a pointer
  2891. to its "meta-class". }
  2892. begin
  2893. case selfloc.loc of
  2894. LOC_REGISTER:
  2895. begin
  2896. {$ifdef cpu_uses_separate_address_registers}
  2897. if getregtype(left.location.register)<>R_ADDRESSREGISTER then
  2898. begin
  2899. reference_reset_base(href,cg.getaddressregister(list),objdef.vmt_offset,sizeof(pint));
  2900. cg.a_load_reg_reg(list,OS_ADDR,OS_ADDR,selfloc.register,href.base);
  2901. end
  2902. else
  2903. {$endif cpu_uses_separate_address_registers}
  2904. reference_reset_base(href,selfloc.register,objdef.vmt_offset,sizeof(pint));
  2905. end;
  2906. LOC_CREGISTER,
  2907. LOC_CREFERENCE,
  2908. LOC_REFERENCE:
  2909. begin
  2910. reference_reset_base(href,cg.getaddressregister(list),objdef.vmt_offset,sizeof(pint));
  2911. cg.a_load_loc_reg(list,OS_ADDR,selfloc,href.base);
  2912. end;
  2913. else
  2914. internalerror(200305057);
  2915. end;
  2916. end;
  2917. vmtreg:=cg.getaddressregister(list);
  2918. cg.g_maybe_testself(list,href.base);
  2919. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,vmtreg);
  2920. { test validity of VMT }
  2921. if not(is_interface(objdef)) and
  2922. not(is_cppclass(objdef)) and
  2923. not(is_objc_class_or_protocol(objdef)) then
  2924. cg.g_maybe_testvmt(list,vmtreg,objdef);
  2925. end;
  2926. function getprocalign : shortint;
  2927. begin
  2928. { gprof uses 16 byte granularity }
  2929. if (cs_profile in current_settings.moduleswitches) then
  2930. result:=16
  2931. else
  2932. result:=current_settings.alignment.procalign;
  2933. end;
  2934. procedure gen_fpc_dummy(list : TAsmList);
  2935. begin
  2936. {$ifdef i386}
  2937. { fix me! }
  2938. list.concat(Taicpu.Op_const_reg(A_MOV,S_L,1,NR_EAX));
  2939. list.concat(Taicpu.Op_const(A_RET,S_W,12));
  2940. {$endif i386}
  2941. end;
  2942. procedure InsertInterruptTable;
  2943. procedure WriteVector(const name: string);
  2944. {$IFDEF arm}
  2945. var
  2946. ai: taicpu;
  2947. {$ENDIF arm}
  2948. begin
  2949. {$IFDEF arm}
  2950. if current_settings.cputype in [cpu_armv7m] then
  2951. current_asmdata.asmlists[al_globals].concat(tai_const.Createname(name,0))
  2952. else
  2953. begin
  2954. ai:=taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(name));
  2955. ai.is_jmp:=true;
  2956. current_asmdata.asmlists[al_globals].concat(ai);
  2957. end;
  2958. {$ENDIF arm}
  2959. end;
  2960. function GetInterruptTableLength: longint;
  2961. begin
  2962. {$if defined(ARM)}
  2963. result:=embedded_controllers[current_settings.controllertype].interruptvectors;
  2964. {$else}
  2965. result:=0;
  2966. {$endif}
  2967. end;
  2968. var
  2969. hp: tused_unit;
  2970. sym: tsym;
  2971. i, i2: longint;
  2972. interruptTable: array of tprocdef;
  2973. pd: tprocdef;
  2974. begin
  2975. SetLength(interruptTable, GetInterruptTableLength);
  2976. FillChar(interruptTable[0], length(interruptTable)*sizeof(pointer), 0);
  2977. hp:=tused_unit(usedunits.first);
  2978. while assigned(hp) do
  2979. begin
  2980. for i := 0 to hp.u.symlist.Count-1 do
  2981. begin
  2982. sym:=tsym(hp.u.symlist[i]);
  2983. if not assigned(sym) then
  2984. continue;
  2985. if sym.typ = procsym then
  2986. begin
  2987. for i2 := 0 to tprocsym(sym).ProcdefList.Count-1 do
  2988. begin
  2989. pd:=tprocdef(tprocsym(sym).ProcdefList[i2]);
  2990. if pd.interruptvector >= 0 then
  2991. begin
  2992. if pd.interruptvector > high(interruptTable) then
  2993. Internalerror(2011030602);
  2994. if interruptTable[pd.interruptvector] <> nil then
  2995. internalerror(2011030601);
  2996. interruptTable[pd.interruptvector]:=pd;
  2997. break;
  2998. end;
  2999. end;
  3000. end;
  3001. end;
  3002. hp:=tused_unit(hp.next);
  3003. end;
  3004. new_section(current_asmdata.asmlists[al_globals],sec_init,'VECTORS',sizeof(pint));
  3005. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('VECTORS',AT_DATA,0));
  3006. {$IFDEF arm}
  3007. if current_settings.cputype in [cpu_armv7m] then
  3008. current_asmdata.asmlists[al_globals].concat(tai_const.Createname('_stack_top',0)); { ARMv7-M processors have the initial stack value at address 0 }
  3009. {$ENDIF arm}
  3010. for i:=0 to high(interruptTable) do
  3011. begin
  3012. if interruptTable[i]<>nil then
  3013. writeVector(interruptTable[i].mangledname)
  3014. else
  3015. writeVector('DefaultHandler'); { Default handler name }
  3016. end;
  3017. end;
  3018. end.