ncgld.pas 67 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Generate assembler for nodes that handle loads and assignments which
  4. are the same for all (most) processors
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit ncgld;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. globtype,
  23. symtype,symsym,
  24. aasmdata,
  25. node,nld,cgutils;
  26. type
  27. tcgloadnode = class(tloadnode)
  28. protected
  29. procedure generate_nested_access(vs: tsym);virtual;
  30. procedure generate_absaddr_access(vs: tabsolutevarsym); virtual;
  31. procedure generate_threadvar_access(gvs: tstaticvarsym); virtual;
  32. public
  33. procedure pass_generate_code;override;
  34. procedure changereflocation(const ref: treference);
  35. end;
  36. tcgassignmentnode = class(tassignmentnode)
  37. protected
  38. function maybechangetemp(list: TAsmList; var n: tnode; const newref: treference): boolean;virtual;
  39. public
  40. procedure pass_generate_code;override;
  41. end;
  42. tcgarrayconstructornode = class(tarrayconstructornode)
  43. protected
  44. procedure makearrayref(var ref: treference; eledef: tdef);virtual;
  45. procedure advancearrayoffset(var ref: treference; elesize: asizeint);virtual;
  46. public
  47. procedure pass_generate_code;override;
  48. end;
  49. tcgrttinode = class(trttinode)
  50. procedure pass_generate_code;override;
  51. end;
  52. implementation
  53. uses
  54. cutils,
  55. systems,
  56. verbose,globals,constexp,
  57. nutils,
  58. symtable,symconst,symdef,defutil,paramgr,ncon,nbas,ncgrtti,
  59. aasmbase,
  60. cgbase,pass_2,
  61. procinfo,
  62. cpubase,parabase,cpuinfo,
  63. tgobj,ncgutil,
  64. cgobj,hlcgobj,
  65. ncgbas,ncgflw,
  66. wpobase;
  67. {*****************************************************************************
  68. SSA (for memory temps) support
  69. *****************************************************************************}
  70. type
  71. preplacerefrec = ^treplacerefrec;
  72. treplacerefrec = record
  73. old, new: preference;
  74. ressym: tsym;
  75. end;
  76. function doreplaceref(var n: tnode; para: pointer): foreachnoderesult;
  77. var
  78. rr: preplacerefrec absolute para;
  79. begin
  80. result := fen_false;
  81. case n.nodetype of
  82. loadn:
  83. begin
  84. { regular variable }
  85. if (tabstractvarsym(tloadnode(n).symtableentry).varoptions * [vo_is_dll_var, vo_is_thread_var] = []) and
  86. not assigned(tloadnode(n).left) and
  87. { not function result, or no exit in function }
  88. (((tloadnode(n).symtableentry <> rr^.ressym) and
  89. not(vo_is_funcret in tabstractvarsym(tloadnode(n).symtableentry).varoptions)) or
  90. not(fc_exit in flowcontrol)) and
  91. { stored in memory... }
  92. (tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.loc in [LOC_REFERENCE]) and
  93. { ... at the place we are looking for }
  94. references_equal(tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.reference,rr^.old^) and
  95. { its address cannot have escaped the current routine }
  96. not(tabstractvarsym(tloadnode(n).symtableentry).addr_taken) then
  97. begin
  98. { relocate variable }
  99. tcgloadnode(n).changereflocation(rr^.new^);
  100. result := fen_norecurse_true;
  101. end;
  102. end;
  103. temprefn:
  104. begin
  105. if (ti_valid in ttemprefnode(n).tempinfo^.flags) and
  106. { memory temp... }
  107. (ttemprefnode(n).tempinfo^.location.loc in [LOC_REFERENCE]) and
  108. { ... at the place we are looking for }
  109. references_equal(ttemprefnode(n).tempinfo^.location.reference,rr^.old^) and
  110. { its address cannot have escaped the current routine }
  111. not(ti_addr_taken in ttemprefnode(n).tempinfo^.flags) then
  112. begin
  113. { relocate the temp }
  114. tcgtemprefnode(n).changelocation(rr^.new^);
  115. result := fen_norecurse_true;
  116. end;
  117. end;
  118. { Subscriptn must be rejected, otherwise we may replace an
  119. an entire record with a temp for its first field, mantis #13948)
  120. Exception: the field's size is the same as the entire record
  121. The same goes for array indexing
  122. }
  123. subscriptn,
  124. vecn:
  125. if not(tunarynode(n).left.resultdef.typ in [recorddef,objectdef,arraydef,stringdef]) or
  126. { make sure we don't try to call resultdef.size for types that
  127. don't have a compile-time size such as open arrays }
  128. is_special_array(tunarynode(n).left.resultdef) or
  129. (tunarynode(n).left.resultdef.size<>tunarynode(n).resultdef.size) then
  130. result := fen_norecurse_false;
  131. { optimize the searching a bit }
  132. derefn,addrn,
  133. calln,inlinen,casen,
  134. addn,subn,muln,
  135. andn,orn,xorn,
  136. ltn,lten,gtn,gten,equaln,unequaln,
  137. slashn,divn,shrn,shln,notn,
  138. inn,
  139. asn,isn:
  140. result := fen_norecurse_false;
  141. end;
  142. end;
  143. function tcgassignmentnode.maybechangetemp(list: TAsmList; var n: tnode; const newref: treference): boolean;
  144. var
  145. rr: treplacerefrec;
  146. begin
  147. result := false;
  148. { only do for -O2 or higher (breaks debugging since }
  149. { variables move to different memory locations) }
  150. if not(cs_opt_level2 in current_settings.optimizerswitches) or
  151. { must be a copy to a memory location ... }
  152. (n.location.loc <> LOC_REFERENCE) or
  153. { not inside a control flow statement and no goto's in sight }
  154. ([fc_inflowcontrol,fc_gotolabel] * flowcontrol <> []) or
  155. { not for refcounted types, because those locations are }
  156. { still used later on in initialisation/finalisation code }
  157. is_managed_type(n.resultdef) or
  158. { source and destination are temps (= not global variables) }
  159. not tg.istemp(n.location.reference) or
  160. not tg.istemp(newref) or
  161. { and both point to the start of a temp, and the source is a }
  162. { non-persistent temp (otherwise we need some kind of copy- }
  163. { on-write support in case later on both are still used) }
  164. (tg.gettypeoftemp(newref) <> tt_normal) or
  165. not (tg.gettypeoftemp(n.location.reference) in [tt_normal,tt_persistent]) or
  166. { and both have the same size }
  167. (tg.sizeoftemp(current_asmdata.CurrAsmList,newref) <> tg.sizeoftemp(current_asmdata.CurrAsmList,n.location.reference)) then
  168. exit;
  169. { find the source of the old reference (loadnode or tempnode) }
  170. { and replace it with the new reference }
  171. rr.old := @n.location.reference;
  172. rr.new := @newref;
  173. rr.ressym := nil;
  174. if assigned(current_procinfo.procdef.funcretsym) and
  175. (tabstractvarsym(current_procinfo.procdef.funcretsym).refs <> 0) then
  176. if (current_procinfo.procdef.proctypeoption=potype_constructor) then
  177. rr.ressym:=tsym(current_procinfo.procdef.parast.Find('self'))
  178. else
  179. rr.ressym:=current_procinfo.procdef.funcretsym;
  180. { if source not found, don't do anything }
  181. if not foreachnodestatic(n,@doreplaceref,@rr) then
  182. exit;
  183. n.location.reference := newref;
  184. result:=true;
  185. end;
  186. {*****************************************************************************
  187. SecondLoad
  188. *****************************************************************************}
  189. procedure tcgloadnode.changereflocation(const ref: treference);
  190. var
  191. oldtemptype: ttemptype;
  192. begin
  193. if (location.loc<>LOC_REFERENCE) then
  194. internalerror(2007020812);
  195. if not tg.istemp(location.reference) then
  196. internalerror(2007020813);
  197. oldtemptype:=tg.gettypeoftemp(location.reference);
  198. if (oldtemptype = tt_persistent) then
  199. tg.ChangeTempType(current_asmdata.CurrAsmList,location.reference,tt_normal);
  200. tg.ungettemp(current_asmdata.CurrAsmList,location.reference);
  201. location.reference:=ref;
  202. tg.ChangeTempType(current_asmdata.CurrAsmList,location.reference,oldtemptype);
  203. tabstractnormalvarsym(symtableentry).localloc:=location;
  204. end;
  205. procedure tcgloadnode.generate_nested_access(vs: tsym);
  206. var
  207. { paramter declared as tsym to reduce interface unit dependencies }
  208. lvs: tabstractnormalvarsym absolute vs;
  209. begin
  210. secondpass(left);
  211. if not(left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  212. internalerror(200309286);
  213. if lvs.localloc.loc<>LOC_REFERENCE then
  214. internalerror(200409241);
  215. hlcg.reference_reset_base(location.reference,left.resultdef,left.location.register,lvs.localloc.reference.offset,lvs.localloc.reference.alignment);
  216. end;
  217. procedure tcgloadnode.generate_absaddr_access(vs: tabsolutevarsym);
  218. begin
  219. location.reference.offset:=aint(vs.addroffset);
  220. end;
  221. procedure tcgloadnode.generate_threadvar_access(gvs: tstaticvarsym);
  222. var
  223. respara,
  224. paraloc1 : tcgpara;
  225. fieldptrdef,
  226. pvd : tdef;
  227. endrelocatelab,
  228. norelocatelab : tasmlabel;
  229. tvref,
  230. href : treference;
  231. hregister : tregister;
  232. tv_rec : trecorddef;
  233. tv_index_field,
  234. tv_non_mt_data_field: tsym;
  235. tmpresloc: tlocation;
  236. begin
  237. if (tf_section_threadvars in target_info.flags) then
  238. begin
  239. if gvs.localloc.loc=LOC_INVALID then
  240. if not(vo_is_weak_external in gvs.varoptions) then
  241. reference_reset_symbol(location.reference,current_asmdata.RefAsmSymbol(gvs.mangledname),0,location.reference.alignment)
  242. else
  243. reference_reset_symbol(location.reference,current_asmdata.WeakRefAsmSymbol(gvs.mangledname),0,location.reference.alignment)
  244. else
  245. location:=gvs.localloc;
  246. end
  247. else
  248. begin
  249. {
  250. Thread var loading is optimized to first check if
  251. a relocate function is available. When the function
  252. is available it is called to retrieve the address.
  253. Otherwise the address is loaded with the symbol
  254. }
  255. tv_rec:=get_threadvar_record(resultdef,tv_index_field,tv_non_mt_data_field);
  256. fieldptrdef:=cpointerdef.getreusable(resultdef);
  257. current_asmdata.getjumplabel(norelocatelab);
  258. current_asmdata.getjumplabel(endrelocatelab);
  259. { make sure hregister can't allocate the register necessary for the parameter }
  260. pvd:=search_system_type('TRELOCATETHREADVARHANDLER').typedef;
  261. if pvd.typ<>procvardef then
  262. internalerror(2012120901);
  263. { FPC_THREADVAR_RELOCATE is nil? }
  264. paraloc1.init;
  265. paramanager.getintparaloc(current_asmdata.CurrAsmList,tprocvardef(pvd),1,paraloc1);
  266. hregister:=hlcg.getaddressregister(current_asmdata.CurrAsmList,pvd);
  267. reference_reset_symbol(href,current_asmdata.RefAsmSymbol('FPC_THREADVAR_RELOCATE'),0,pvd.size);
  268. hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,pvd,pvd,href,hregister);
  269. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,pvd,OC_EQ,0,hregister,norelocatelab);
  270. { no, call it with the index of the threadvar as parameter }
  271. if not(vo_is_weak_external in gvs.varoptions) then
  272. reference_reset_symbol(tvref,current_asmdata.RefAsmSymbol(gvs.mangledname),0,sizeof(pint))
  273. else
  274. reference_reset_symbol(tvref,current_asmdata.WeakRefAsmSymbol(gvs.mangledname),0,sizeof(pint));
  275. href:=tvref;
  276. hlcg.g_set_addr_nonbitpacked_record_field_ref(current_asmdata.CurrAsmList,
  277. tv_rec,
  278. tfieldvarsym(tv_index_field),href);
  279. hlcg.a_load_ref_cgpara(current_asmdata.CurrAsmList,tfieldvarsym(tv_index_field).vardef,href,paraloc1);
  280. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  281. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  282. { result is the address of the threadvar }
  283. respara:=hlcg.a_call_reg(current_asmdata.CurrAsmList,tprocvardef(pvd),hregister,[@paraloc1]);
  284. paraloc1.done;
  285. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  286. { load the address of the result in hregister }
  287. hregister:=hlcg.getaddressregister(current_asmdata.CurrAsmList,fieldptrdef);
  288. location_reset(tmpresloc,LOC_REGISTER,def_cgsize(fieldptrdef));
  289. tmpresloc.register:=hregister;
  290. hlcg.gen_load_cgpara_loc(current_asmdata.CurrAsmList,fieldptrdef,respara,tmpresloc,true);
  291. respara.resetiftemp;
  292. hlcg.a_jmp_always(current_asmdata.CurrAsmList,endrelocatelab);
  293. { no relocation needed, load the address of the variable only, the
  294. layout of a threadvar is:
  295. 0 - Threadvar index
  296. sizeof(pint) - Threadvar value in single threading }
  297. hlcg.a_label(current_asmdata.CurrAsmList,norelocatelab);
  298. href:=tvref;
  299. hlcg.g_set_addr_nonbitpacked_record_field_ref(current_asmdata.CurrAsmList,
  300. tv_rec,
  301. tfieldvarsym(tv_non_mt_data_field),href);
  302. { load in the same "hregister" as above, so after this sequence
  303. the address of the threadvar is always in hregister }
  304. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,resultdef,fieldptrdef,href,hregister);
  305. hlcg.a_label(current_asmdata.CurrAsmList,endrelocatelab);
  306. hlcg.reference_reset_base(location.reference,fieldptrdef,hregister,0,location.reference.alignment);
  307. end;
  308. end;
  309. procedure tcgloadnode.pass_generate_code;
  310. var
  311. hregister : tregister;
  312. vs : tabstractnormalvarsym;
  313. gvs : tstaticvarsym;
  314. pd : tprocdef;
  315. href : treference;
  316. newsize : tcgsize;
  317. vd : tdef;
  318. begin
  319. { we don't know the size of all arrays }
  320. newsize:=def_cgsize(resultdef);
  321. { alignment is overridden per case below }
  322. location_reset_ref(location,LOC_REFERENCE,newsize,resultdef.alignment);
  323. case symtableentry.typ of
  324. absolutevarsym :
  325. begin
  326. { this is only for toasm and toaddr }
  327. case tabsolutevarsym(symtableentry).abstyp of
  328. toaddr :
  329. generate_absaddr_access(tabsolutevarsym(symtableentry));
  330. toasm :
  331. location.reference.symbol:=current_asmdata.RefAsmSymbol(tabsolutevarsym(symtableentry).mangledname);
  332. else
  333. internalerror(200310283);
  334. end;
  335. end;
  336. constsym:
  337. begin
  338. if tconstsym(symtableentry).consttyp=constresourcestring then
  339. begin
  340. location_reset_ref(location,LOC_CREFERENCE,def_cgsize(cansistringtype),cansistringtype.size);
  341. location.reference.symbol:=current_asmdata.RefAsmSymbol(make_mangledname('RESSTR',symtableentry.owner,symtableentry.name),AT_DATA);
  342. { Resourcestring layout:
  343. TResourceStringRecord = Packed Record
  344. Name,
  345. CurrentValue,
  346. DefaultValue : AnsiString;
  347. HashValue : LongWord;
  348. end;
  349. }
  350. location.reference.offset:=cansistringtype.size;
  351. end
  352. else
  353. internalerror(22798);
  354. end;
  355. staticvarsym :
  356. begin
  357. gvs:=tstaticvarsym(symtableentry);
  358. if (vo_is_dll_var in gvs.varoptions) then
  359. { DLL variable }
  360. begin
  361. hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
  362. if not(vo_is_weak_external in gvs.varoptions) then
  363. location.reference.symbol:=current_asmdata.RefAsmSymbol(tstaticvarsym(symtableentry).mangledname)
  364. else
  365. location.reference.symbol:=current_asmdata.WeakRefAsmSymbol(tstaticvarsym(symtableentry).mangledname);
  366. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,location.reference,hregister);
  367. reference_reset_base(location.reference,hregister,0,location.reference.alignment);
  368. end
  369. { Thread variable }
  370. else if (vo_is_thread_var in gvs.varoptions) then
  371. generate_threadvar_access(gvs)
  372. { Normal (or external) variable }
  373. else
  374. begin
  375. if gvs.localloc.loc=LOC_INVALID then
  376. if not(vo_is_weak_external in gvs.varoptions) then
  377. reference_reset_symbol(location.reference,current_asmdata.RefAsmSymbol(gvs.mangledname),0,location.reference.alignment)
  378. else
  379. reference_reset_symbol(location.reference,current_asmdata.WeakRefAsmSymbol(gvs.mangledname),0,location.reference.alignment)
  380. else
  381. location:=gvs.localloc;
  382. end;
  383. { make const a LOC_CREFERENCE }
  384. if (gvs.varspez=vs_const) and
  385. (location.loc=LOC_REFERENCE) then
  386. location.loc:=LOC_CREFERENCE;
  387. end;
  388. paravarsym,
  389. localvarsym :
  390. begin
  391. vs:=tabstractnormalvarsym(symtableentry);
  392. { Nested variable }
  393. if assigned(left) then
  394. generate_nested_access(vs)
  395. else
  396. location:=vs.localloc;
  397. { handle call by reference variables when they are not
  398. already copied to local copies. Also ignore the reference
  399. when we need to load the self pointer for objects }
  400. if is_addr_param_load then
  401. begin
  402. if (location.loc in [LOC_CREGISTER,LOC_REGISTER]) then
  403. hregister:=location.register
  404. else
  405. begin
  406. vd:=cpointerdef.getreusable(resultdef);
  407. hregister:=hlcg.getaddressregister(current_asmdata.CurrAsmList,vd);
  408. { we need to load only an address }
  409. location.size:=int_cgsize(vd.size);
  410. hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,vd,vd,location,hregister);
  411. end;
  412. { assume packed records may always be unaligned }
  413. if not(resultdef.typ in [recorddef,objectdef]) or
  414. (tabstractrecordsymtable(tabstractrecorddef(resultdef).symtable).usefieldalignment<>1) then
  415. location_reset_ref(location,LOC_REFERENCE,newsize,resultdef.alignment)
  416. else
  417. location_reset_ref(location,LOC_REFERENCE,newsize,1);
  418. hlcg.reference_reset_base(location.reference,voidpointertype,hregister,0,location.reference.alignment);
  419. end;
  420. { make const a LOC_CREFERENCE }
  421. if (vs.varspez=vs_const) and
  422. (location.loc=LOC_REFERENCE) then
  423. location.loc:=LOC_CREFERENCE;
  424. end;
  425. procsym:
  426. begin
  427. if not assigned(procdef) then
  428. internalerror(200312011);
  429. if assigned(left) then
  430. begin
  431. location_reset(location,LOC_CREGISTER,int_cgsize(voidpointertype.size*2));
  432. secondpass(left);
  433. { load class instance/classrefdef address }
  434. if left.location.loc=LOC_CONSTANT then
  435. { todo: exact type for hlcg (can't use left.resultdef, because can be TP-style object, which is not pointer-sized) }
  436. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,voidpointertype,false);
  437. case left.location.loc of
  438. LOC_CREGISTER,
  439. LOC_REGISTER:
  440. begin
  441. { this is not possible for objects }
  442. if is_object(left.resultdef) then
  443. internalerror(200304234);
  444. location.registerhi:=left.location.register;
  445. end;
  446. LOC_CREFERENCE,
  447. LOC_REFERENCE:
  448. begin
  449. if is_implicit_pointer_object_type(left.resultdef) or
  450. (left.resultdef.typ=classrefdef) then
  451. begin
  452. location.registerhi:=hlcg.getaddressregister(current_asmdata.CurrAsmList,left.resultdef);
  453. hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,left.resultdef,left.resultdef,left.location.reference,location.registerhi)
  454. end
  455. else
  456. begin
  457. location.registerhi:=hlcg.getaddressregister(current_asmdata.CurrAsmList,voidpointertype);
  458. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.resultdef,voidpointertype,left.location.reference,location.registerhi);
  459. end;
  460. location_freetemp(current_asmdata.CurrAsmList,left.location);
  461. end;
  462. else
  463. internalerror(200610311);
  464. end;
  465. { virtual method ? }
  466. if (po_virtualmethod in procdef.procoptions) and
  467. not(loadnf_inherited in loadnodeflags) and
  468. not is_objectpascal_helper(procdef.struct) then
  469. begin
  470. if (not assigned(current_procinfo) or
  471. wpoinfomanager.symbol_live(current_procinfo.procdef.mangledname)) then
  472. tobjectdef(procdef.struct).register_vmt_call(procdef.extnumber);
  473. {$ifdef vtentry}
  474. if not is_interface(procdef.struct) then
  475. begin
  476. inc(current_asmdata.NextVTEntryNr);
  477. current_asmdata.CurrAsmList.Concat(tai_symbol.CreateName('VTREF'+tostr(current_asmdata.NextVTEntryNr)+'_'+procdef._class.vmt_mangledname+'$$'+tostr(vmtoffset div sizeof(pint)),AT_FUNCTION,0));
  478. end;
  479. {$endif vtentry}
  480. { a classrefdef already points to the VMT }
  481. if (left.resultdef.typ<>classrefdef) then
  482. begin
  483. { load vmt pointer }
  484. hlcg.reference_reset_base(href,voidpointertype,location.registerhi,tobjectdef(left.resultdef).vmt_offset,voidpointertype.alignment);
  485. hregister:=hlcg.getaddressregister(current_asmdata.CurrAsmList,voidpointertype);
  486. hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,voidpointertype,voidpointertype,href,hregister);
  487. end
  488. else
  489. hregister:=location.registerhi;
  490. { load method address }
  491. hlcg.reference_reset_base(href,voidpointertype,hregister,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),voidpointertype.alignment);
  492. location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,procdef.address_type);
  493. hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,procdef.address_type,procdef.address_type,href,location.register);
  494. end
  495. else
  496. begin
  497. { load address of the function }
  498. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(procdef.mangledname),0,procdef.address_type.alignment);
  499. location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,procdef.address_type);
  500. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,procdef,procdef.address_type,href,location.register);
  501. end;
  502. { to get methodpointers stored correctly, code and self register must be swapped on
  503. big endian targets }
  504. if target_info.endian=endian_big then
  505. begin
  506. hregister:=location.register;
  507. location.register:=location.registerhi;
  508. location.registerhi:=hregister;
  509. end;
  510. end
  511. else
  512. begin
  513. pd:=tprocdef(tprocsym(symtableentry).ProcdefList[0]);
  514. { def_cgsize does not work for tprocdef, so we use pd.address_type }
  515. location.size:=def_cgsize(pd.address_type);
  516. if not(po_weakexternal in pd.procoptions) then
  517. location.reference.symbol:=current_asmdata.RefAsmSymbol(procdef.mangledname)
  518. else
  519. location.reference.symbol:=current_asmdata.WeakRefAsmSymbol(procdef.mangledname);
  520. end;
  521. end;
  522. labelsym :
  523. if assigned(tlabelsym(symtableentry).asmblocklabel) then
  524. location.reference.symbol:=tlabelsym(symtableentry).asmblocklabel
  525. else
  526. location.reference.symbol:=tcglabelnode((tlabelsym(symtableentry).code)).getasmlabel;
  527. else internalerror(200510032);
  528. end;
  529. end;
  530. {*****************************************************************************
  531. SecondAssignment
  532. *****************************************************************************}
  533. procedure tcgassignmentnode.pass_generate_code;
  534. var
  535. hlabel : tasmlabel;
  536. href : treference;
  537. releaseright : boolean;
  538. alignmentrequirement,
  539. len : aint;
  540. r : tregister;
  541. {$if not defined(cpu64bitalu)}
  542. r64 : tregister64;
  543. {$endif}
  544. oldflowcontrol : tflowcontrol;
  545. begin
  546. { previously, managed types were handled in firstpass
  547. newer FPCs however can identify situations when
  548. assignments of managed types require no special code and the
  549. value could be just copied so this could should be able also to handle
  550. managed types without any special "managing code"}
  551. location_reset(location,LOC_VOID,OS_NO);
  552. {
  553. in most cases we can process first the right node which contains
  554. the most complex code. Exceptions for this are:
  555. - result is in flags, loading left will then destroy the flags
  556. - result is a jump, loading left must be already done before the jump is made
  557. - result need reference count, when left points to a value used in
  558. right then decreasing the refcnt on left can possibly release
  559. the memory before right increased the refcnt, result is that an
  560. empty value is assigned
  561. But not when the result is in the flags, then
  562. loading the left node afterwards can destroy the flags.
  563. }
  564. if not(right.expectloc in [LOC_FLAGS,LOC_JUMP]) and
  565. (node_complexity(right)>node_complexity(left)) then
  566. begin
  567. secondpass(right);
  568. if codegenerror then
  569. exit;
  570. secondpass(left);
  571. if codegenerror then
  572. exit;
  573. end
  574. else
  575. begin
  576. { calculate left sides }
  577. secondpass(left);
  578. if codegenerror then
  579. exit;
  580. { tell the SSA/SSL code that the left side was handled first so
  581. ni SSL is done
  582. }
  583. oldflowcontrol:=flowcontrol;
  584. include(flowcontrol,fc_lefthandled);
  585. secondpass(right);
  586. flowcontrol:=oldflowcontrol;
  587. if codegenerror then
  588. exit;
  589. end;
  590. releaseright:=true;
  591. { shortstring assignments are handled separately }
  592. if is_shortstring(left.resultdef) then
  593. begin
  594. {
  595. we can get here only in the following situations
  596. for the right node:
  597. - empty constant string
  598. - char
  599. }
  600. { The addn is replaced by a blockn or calln that already returns
  601. a shortstring }
  602. if is_shortstring(right.resultdef) and
  603. (right.nodetype in [blockn,calln]) then
  604. begin
  605. { verify that we indeed have nothing to do }
  606. if not(nf_assign_done_in_right in flags) then
  607. internalerror(2015042201);
  608. end
  609. { empty constant string }
  610. else if (right.nodetype=stringconstn) and
  611. (tstringconstnode(right).len=0) then
  612. begin
  613. hlcg.g_ptrtypecast_ref(current_asmdata.CurrAsmList,cpointerdef.getreusable(left.resultdef),tpointerdef(charpointertype),left.location.reference);
  614. hlcg.a_load_const_ref(current_asmdata.CurrAsmList,cansichartype,0,left.location.reference);
  615. end
  616. { char loading }
  617. else if is_char(right.resultdef) then
  618. begin
  619. if right.nodetype=ordconstn then
  620. begin
  621. hlcg.g_ptrtypecast_ref(current_asmdata.CurrAsmList,cpointerdef.getreusable(left.resultdef),cpointerdef.getreusable(u16inttype),left.location.reference);
  622. if (target_info.endian = endian_little) then
  623. hlcg.a_load_const_ref(current_asmdata.CurrAsmList,u16inttype,(tordconstnode(right).value.svalue shl 8) or 1,
  624. setalignment(left.location.reference,1))
  625. else
  626. hlcg.a_load_const_ref(current_asmdata.CurrAsmList,u16inttype,tordconstnode(right).value.svalue or (1 shl 8),
  627. setalignment(left.location.reference,1));
  628. end
  629. else
  630. begin
  631. href:=left.location.reference;
  632. hlcg.g_ptrtypecast_ref(current_asmdata.CurrAsmList,cpointerdef.getreusable(left.resultdef),tpointerdef(charpointertype),href);
  633. hlcg.a_load_const_ref(current_asmdata.CurrAsmList,cansichartype,1,href);
  634. inc(href.offset,1);
  635. case right.location.loc of
  636. LOC_REGISTER,
  637. LOC_CREGISTER :
  638. begin
  639. {$ifndef cpuhighleveltarget}
  640. r:=cg.makeregsize(current_asmdata.CurrAsmList,right.location.register,OS_8);
  641. {$else not cpuhighleveltarget}
  642. r:=hlcg.getintregister(current_asmdata.CurrAsmList,u8inttype);
  643. hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,cansichartype,u8inttype,right.location.register,r);
  644. {$endif cpuhighleveltarget}
  645. hlcg.a_load_reg_ref(current_asmdata.CurrAsmList,u8inttype,u8inttype,r,href);
  646. end;
  647. LOC_REFERENCE,
  648. LOC_CREFERENCE :
  649. hlcg.a_load_ref_ref(current_asmdata.CurrAsmList,cansichartype,cansichartype,right.location.reference,href);
  650. else
  651. internalerror(200205111);
  652. end;
  653. end;
  654. end
  655. else
  656. internalerror(2002042410);
  657. end
  658. { try to reuse memory locations instead of copying }
  659. { copy to a memory location ... }
  660. else if (right.location.loc = LOC_REFERENCE) and
  661. maybechangetemp(current_asmdata.CurrAsmList,left,right.location.reference) then
  662. begin
  663. { if it worked, we're done }
  664. end
  665. else
  666. begin
  667. { SSA support }
  668. hlcg.maybe_change_load_node_reg(current_asmdata.CurrAsmList,left,false);
  669. hlcg.maybe_change_load_node_reg(current_asmdata.CurrAsmList,right,true);
  670. case right.location.loc of
  671. LOC_CONSTANT :
  672. begin
  673. {$ifndef cpu64bitalu}
  674. if (left.location.size in [OS_64,OS_S64]) or (right.location.size in [OS_64,OS_S64]) then
  675. cg64.a_load64_const_loc(current_asmdata.CurrAsmList,right.location.value64,left.location)
  676. else
  677. {$endif not cpu64bitalu}
  678. hlcg.a_load_const_loc(current_asmdata.CurrAsmList,left.resultdef,right.location.value,left.location);
  679. end;
  680. LOC_REFERENCE,
  681. LOC_CREFERENCE :
  682. begin
  683. case left.location.loc of
  684. LOC_REGISTER,
  685. LOC_CREGISTER :
  686. begin
  687. {$ifndef cpuhighleveltarget}
  688. {$ifdef cpu64bitalu}
  689. if left.location.size in [OS_128,OS_S128] then
  690. cg128.a_load128_ref_reg(current_asmdata.CurrAsmList,right.location.reference,left.location.register128)
  691. else
  692. {$else cpu64bitalu}
  693. if left.location.size in [OS_64,OS_S64] then
  694. cg64.a_load64_ref_reg(current_asmdata.CurrAsmList,right.location.reference,left.location.register64)
  695. else
  696. {$endif cpu64bitalu}
  697. {$endif not cpuhighleveltarget}
  698. hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,right.resultdef,left.resultdef,right.location.reference,left.location.register);
  699. end;
  700. LOC_FPUREGISTER,
  701. LOC_CFPUREGISTER :
  702. begin
  703. hlcg.a_loadfpu_ref_reg(current_asmdata.CurrAsmList,
  704. right.resultdef,left.resultdef,
  705. right.location.reference,
  706. left.location.register);
  707. end;
  708. LOC_REFERENCE,
  709. LOC_CREFERENCE :
  710. begin
  711. if (left.resultdef.typ=floatdef) and
  712. (right.resultdef.typ=floatdef) and
  713. (left.location.size<>right.location.size) then
  714. begin
  715. { assume that all float types can be handed by the
  716. fpu if one can be handled by the fpu }
  717. if not use_vectorfpu(left.resultdef) or
  718. not use_vectorfpu(right.resultdef) then
  719. hlcg.a_loadfpu_ref_ref(current_asmdata.CurrAsmList,
  720. right.resultdef,left.resultdef,
  721. right.location.reference,left.location.reference)
  722. else
  723. hlcg.a_loadmm_ref_ref(current_asmdata.CurrAsmList,
  724. right.resultdef,left.resultdef,
  725. right.location.reference,left.location.reference,mms_movescalar)
  726. end
  727. else
  728. begin
  729. { TODO: HACK: unaligned test, maybe remove all unaligned locations (array of char) from the compiler}
  730. { Use unaligned copy when the offset is not aligned }
  731. len:=left.resultdef.size;
  732. { can be 0 in case of formaldef on JVM target }
  733. if len=0 then
  734. len:=sizeof(pint);
  735. { data smaller than an aint has less alignment requirements }
  736. { max(1,...) avoids div by zero in case of an empty record }
  737. alignmentrequirement:=min(max(1,len),sizeof(aint));
  738. if (right.location.reference.offset mod alignmentrequirement<>0) or
  739. (left.location.reference.offset mod alignmentrequirement<>0) or
  740. (right.resultdef.alignment<alignmentrequirement) or
  741. ((right.location.reference.alignment<>0) and
  742. (right.location.reference.alignment<alignmentrequirement)) or
  743. ((left.location.reference.alignment<>0) and
  744. (left.location.reference.alignment<alignmentrequirement)) then
  745. hlcg.g_concatcopy_unaligned(current_asmdata.CurrAsmList,left.resultdef,right.location.reference,left.location.reference)
  746. else
  747. hlcg.g_concatcopy(current_asmdata.CurrAsmList,left.resultdef,right.location.reference,left.location.reference);
  748. end;
  749. end;
  750. LOC_MMREGISTER,
  751. LOC_CMMREGISTER:
  752. begin
  753. {$ifdef x86}
  754. if (right.resultdef.typ=floatdef) and
  755. not use_vectorfpu(right.resultdef) then
  756. begin
  757. { perform size conversion if needed (the mm-code cannot }
  758. { convert an extended into a double/single, since sse }
  759. { doesn't support extended) }
  760. r:=cg.getfpuregister(current_asmdata.CurrAsmList,right.location.size);
  761. tg.gethltemp(current_asmdata.CurrAsmList,left.resultdef,left.resultdef.size,tt_normal,href);
  762. cg.a_loadfpu_ref_reg(current_asmdata.CurrAsmList,right.location.size,right.location.size,right.location.reference,r);
  763. cg.a_loadfpu_reg_ref(current_asmdata.CurrAsmList,right.location.size,left.location.size,r,href);
  764. if releaseright then
  765. location_freetemp(current_asmdata.CurrAsmList,right.location);
  766. releaseright:=true;
  767. location_reset_ref(right.location,LOC_REFERENCE,left.location.size,0);
  768. right.location.reference:=href;
  769. right.resultdef:=left.resultdef;
  770. end;
  771. {$endif}
  772. hlcg.a_loadmm_ref_reg(current_asmdata.CurrAsmList,
  773. right.resultdef,
  774. left.resultdef,
  775. right.location.reference,
  776. left.location.register,mms_movescalar);
  777. end;
  778. LOC_SUBSETREG,
  779. LOC_CSUBSETREG:
  780. hlcg.a_load_ref_subsetreg(current_asmdata.CurrAsmList,right.resultdef,left.resultdef,right.location.reference,left.location.sreg);
  781. LOC_SUBSETREF,
  782. LOC_CSUBSETREF:
  783. {$ifndef cpu64bitalu}
  784. if right.location.size in [OS_64,OS_S64] then
  785. cg64.a_load64_ref_subsetref(current_asmdata.CurrAsmList,right.location.reference,left.location.sref)
  786. else
  787. {$endif not cpu64bitalu}
  788. hlcg.a_load_ref_subsetref(current_asmdata.CurrAsmList,right.resultdef,left.resultdef,right.location.reference,left.location.sref);
  789. else
  790. internalerror(200203284);
  791. end;
  792. end;
  793. {$ifdef SUPPORT_MMX}
  794. LOC_CMMXREGISTER,
  795. LOC_MMXREGISTER:
  796. begin
  797. if left.location.loc=LOC_CMMXREGISTER then
  798. cg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,OS_M64,OS_M64,right.location.register,left.location.register,nil)
  799. else
  800. cg.a_loadmm_reg_ref(current_asmdata.CurrAsmList,OS_M64,OS_M64,right.location.register,left.location.reference,nil);
  801. end;
  802. {$endif SUPPORT_MMX}
  803. LOC_MMREGISTER,
  804. LOC_CMMREGISTER:
  805. begin
  806. if left.resultdef.typ=arraydef then
  807. begin
  808. end
  809. else
  810. begin
  811. case left.location.loc of
  812. LOC_CMMREGISTER,
  813. LOC_MMREGISTER:
  814. hlcg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,right.resultdef,left.resultdef,right.location.register,left.location.register,mms_movescalar);
  815. LOC_REFERENCE,
  816. LOC_CREFERENCE:
  817. hlcg.a_loadmm_reg_ref(current_asmdata.CurrAsmList,right.resultdef,left.resultdef,right.location.register,left.location.reference,mms_movescalar);
  818. else
  819. internalerror(2009112601);
  820. end;
  821. end;
  822. end;
  823. LOC_REGISTER,
  824. LOC_CREGISTER :
  825. begin
  826. {$ifndef cpuhighleveltarget}
  827. {$ifdef cpu64bitalu}
  828. if left.location.size in [OS_128,OS_S128] then
  829. cg128.a_load128_reg_loc(current_asmdata.CurrAsmList,
  830. right.location.register128,left.location)
  831. else
  832. {$else cpu64bitalu}
  833. { also OS_F64 in case of mmreg -> intreg }
  834. if left.location.size in [OS_64,OS_S64,OS_F64] then
  835. cg64.a_load64_reg_loc(current_asmdata.CurrAsmList,
  836. right.location.register64,left.location)
  837. else
  838. {$endif cpu64bitalu}
  839. {$endif not cpuhighleveltarget}
  840. {$ifdef i8086}
  841. { prefer a_load_loc_ref, because it supports i8086-specific types
  842. that use registerhi (like 6-byte method pointers)
  843. (todo: maybe we should add a_load_loc_loc?) }
  844. if left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
  845. hlcg.a_load_loc_ref(current_asmdata.CurrAsmList,right.resultdef,left.resultdef,right.location,left.location.reference)
  846. else
  847. {$endif i8086}
  848. hlcg.a_load_reg_loc(current_asmdata.CurrAsmList,right.resultdef,left.resultdef,right.location.register,left.location);
  849. end;
  850. LOC_FPUREGISTER,
  851. LOC_CFPUREGISTER :
  852. begin
  853. { we can't do direct moves between fpu and mm registers }
  854. if left.location.loc in [LOC_MMREGISTER,LOC_CMMREGISTER] then
  855. begin
  856. {$ifdef x86}
  857. if not use_vectorfpu(right.resultdef) then
  858. begin
  859. { perform size conversion if needed (the mm-code cannot convert an }
  860. { extended into a double/single, since sse doesn't support extended) }
  861. tg.gethltemp(current_asmdata.CurrAsmList,left.resultdef,left.resultdef.size,tt_normal,href);
  862. cg.a_loadfpu_reg_ref(current_asmdata.CurrAsmList,right.location.size,left.location.size,right.location.register,href);
  863. location_reset_ref(right.location,LOC_REFERENCE,left.location.size,0);
  864. right.location.reference:=href;
  865. right.resultdef:=left.resultdef;
  866. end;
  867. {$endif}
  868. hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,right.location,right.resultdef,false);
  869. hlcg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,
  870. right.resultdef,left.resultdef,
  871. right.location.register,left.location.register,mms_movescalar);
  872. end
  873. else
  874. hlcg.a_loadfpu_reg_loc(current_asmdata.CurrAsmList,
  875. right.resultdef,left.resultdef,
  876. right.location.register,left.location);
  877. end;
  878. LOC_SUBSETREG,
  879. LOC_CSUBSETREG:
  880. begin
  881. hlcg.a_load_subsetreg_loc(current_asmdata.CurrAsmList,
  882. right.resultdef,left.resultdef,right.location.sreg,left.location);
  883. end;
  884. LOC_SUBSETREF,
  885. LOC_CSUBSETREF:
  886. begin
  887. {$ifndef cpu64bitalu}
  888. if right.location.size in [OS_64,OS_S64] then
  889. cg64.a_load64_subsetref_loc(current_asmdata.CurrAsmList,right.location.sref,left.location)
  890. else
  891. {$endif not cpu64bitalu}
  892. hlcg.a_load_subsetref_loc(current_asmdata.CurrAsmList,
  893. right.resultdef,left.resultdef,right.location.sref,left.location);
  894. end;
  895. LOC_JUMP :
  896. begin
  897. current_asmdata.getjumplabel(hlabel);
  898. hlcg.a_label(current_asmdata.CurrAsmList,right.location.truelabel);
  899. if is_pasbool(left.resultdef) then
  900. begin
  901. {$ifndef cpu64bitalu}
  902. if left.location.size in [OS_64,OS_S64] then
  903. cg64.a_load64_const_loc(current_asmdata.CurrAsmList,1,left.location)
  904. else
  905. {$endif not cpu64bitalu}
  906. hlcg.a_load_const_loc(current_asmdata.CurrAsmList,left.resultdef,1,left.location)
  907. end
  908. else
  909. begin
  910. {$ifndef cpu64bitalu}
  911. if left.location.size in [OS_64,OS_S64] then
  912. cg64.a_load64_const_loc(current_asmdata.CurrAsmList,-1,left.location)
  913. else
  914. {$endif not cpu64bitalu}
  915. hlcg.a_load_const_loc(current_asmdata.CurrAsmList,left.resultdef,-1,left.location);
  916. end;
  917. hlcg.a_jmp_always(current_asmdata.CurrAsmList,hlabel);
  918. hlcg.a_label(current_asmdata.CurrAsmList,right.location.falselabel);
  919. {$ifndef cpu64bitalu}
  920. if left.location.size in [OS_64,OS_S64] then
  921. cg64.a_load64_const_loc(current_asmdata.CurrAsmList,0,left.location)
  922. else
  923. {$endif not cpu64bitalu}
  924. hlcg.a_load_const_loc(current_asmdata.CurrAsmList,left.resultdef,0,left.location);
  925. hlcg.a_label(current_asmdata.CurrAsmList,hlabel);
  926. end;
  927. {$ifdef cpuflags}
  928. LOC_FLAGS :
  929. begin
  930. if is_pasbool(left.resultdef) then
  931. begin
  932. case left.location.loc of
  933. LOC_REGISTER,LOC_CREGISTER:
  934. {$ifndef cpu64bitalu}
  935. if left.location.size in [OS_S64,OS_64] then
  936. begin
  937. cg.g_flags2reg(current_asmdata.CurrAsmList,OS_32,right.location.resflags,left.location.register64.reglo);
  938. cg.a_reg_dealloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
  939. cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_32,0,left.location.register64.reghi);
  940. end
  941. else
  942. {$endif not cpu64bitalu}
  943. begin
  944. cg.g_flags2reg(current_asmdata.CurrAsmList,left.location.size,right.location.resflags,left.location.register);
  945. cg.a_reg_dealloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
  946. end;
  947. LOC_REFERENCE:
  948. { i8086 and i386 have hacks in their code generators so that they can
  949. deal with 64 bit locations in this parcticular case }
  950. {$if not defined(cpu64bitalu) and not defined(x86)}
  951. if left.location.size in [OS_S64,OS_64] then
  952. begin
  953. r64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  954. r64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  955. cg.g_flags2reg(current_asmdata.CurrAsmList,OS_32,right.location.resflags,r64.reglo);
  956. cg.a_reg_dealloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
  957. cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_32,0,r64.reghi);
  958. cg64.a_load64_reg_ref(current_asmdata.CurrAsmList,r64,left.location.reference);
  959. end
  960. else
  961. {$endif not cpu64bitalu}
  962. begin
  963. cg.g_flags2ref(current_asmdata.CurrAsmList,left.location.size,right.location.resflags,left.location.reference);
  964. cg.a_reg_dealloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
  965. end;
  966. LOC_SUBSETREG,LOC_SUBSETREF:
  967. begin
  968. r:=cg.getintregister(current_asmdata.CurrAsmList,left.location.size);
  969. cg.g_flags2reg(current_asmdata.CurrAsmList,left.location.size,right.location.resflags,r);
  970. cg.a_reg_dealloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
  971. hlcg.a_load_reg_loc(current_asmdata.CurrAsmList,left.resultdef,left.resultdef,r,left.location);
  972. end;
  973. else
  974. internalerror(200203273);
  975. end;
  976. end
  977. else
  978. begin
  979. {$ifndef cpu64bitalu}
  980. if left.location.size in [OS_S64,OS_64] then
  981. begin
  982. r64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  983. r64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  984. cg.g_flags2reg(current_asmdata.CurrAsmList,OS_32,right.location.resflags,r64.reglo);
  985. cg.a_reg_dealloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
  986. cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_32,0,r64.reghi);
  987. cg64.a_op64_reg_reg(current_asmdata.CurrAsmList,OP_NEG,OS_S64,
  988. r64,r64);
  989. cg64.a_load64_reg_loc(current_asmdata.CurrAsmList,r64,left.location);
  990. end
  991. else
  992. {$endif not cpu64bitalu}
  993. begin
  994. r:=cg.getintregister(current_asmdata.CurrAsmList,left.location.size);
  995. cg.g_flags2reg(current_asmdata.CurrAsmList,left.location.size,right.location.resflags,r);
  996. cg.a_reg_dealloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
  997. cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_NEG,left.location.size,r,r);
  998. hlcg.a_load_reg_loc(current_asmdata.CurrAsmList,left.resultdef,left.resultdef,r,left.location);
  999. end
  1000. end;
  1001. end;
  1002. {$endif cpuflags}
  1003. end;
  1004. end;
  1005. if releaseright then
  1006. location_freetemp(current_asmdata.CurrAsmList,right.location);
  1007. end;
  1008. {*****************************************************************************
  1009. SecondArrayConstruct
  1010. *****************************************************************************}
  1011. const
  1012. vtInteger = 0;
  1013. vtBoolean = 1;
  1014. vtChar = 2;
  1015. vtExtended = 3;
  1016. vtString = 4;
  1017. vtPointer = 5;
  1018. vtPChar = 6;
  1019. vtObject = 7;
  1020. vtClass = 8;
  1021. vtWideChar = 9;
  1022. vtPWideChar = 10;
  1023. vtAnsiString32 = 11;
  1024. vtCurrency = 12;
  1025. vtVariant = 13;
  1026. vtInterface = 14;
  1027. vtWideString = 15;
  1028. vtInt64 = 16;
  1029. vtQWord = 17;
  1030. vtUnicodeString = 18;
  1031. vtAnsiString16 = 19;
  1032. vtAnsiString64 = 20;
  1033. procedure tcgarrayconstructornode.makearrayref(var ref: treference; eledef: tdef);
  1034. begin
  1035. { do nothing by default }
  1036. end;
  1037. procedure tcgarrayconstructornode.advancearrayoffset(var ref: treference; elesize: asizeint);
  1038. begin
  1039. inc(ref.offset,elesize);
  1040. end;
  1041. procedure tcgarrayconstructornode.pass_generate_code;
  1042. var
  1043. hp : tarrayconstructornode;
  1044. href,
  1045. fref : treference;
  1046. lt : tdef;
  1047. paraloc : tcgparalocation;
  1048. varvtypefield,
  1049. varfield : tfieldvarsym;
  1050. vtype : longint;
  1051. eledef: tdef;
  1052. elesize : longint;
  1053. tmpreg : tregister;
  1054. vaddr : boolean;
  1055. freetemp,
  1056. dovariant: boolean;
  1057. begin
  1058. if is_packed_array(resultdef) then
  1059. internalerror(200608042);
  1060. dovariant:=
  1061. ((nf_forcevaria in flags) or is_variant_array(resultdef)) and
  1062. not(target_info.system in systems_managed_vm);
  1063. eledef:=tarraydef(resultdef).elementdef;
  1064. elesize:=eledef.size;
  1065. if dovariant then
  1066. varvtypefield:=tfieldvarsym(search_struct_member_no_helper(trecorddef(eledef),'VTYPE'))
  1067. else
  1068. varvtypefield:=nil;
  1069. { alignment is filled in by tg.gethltemp below }
  1070. location_reset_ref(location,LOC_CREFERENCE,OS_NO,0);
  1071. fillchar(paraloc,sizeof(paraloc),0);
  1072. { Allocate always a temp, also if no elements are required, to
  1073. be sure that location is valid (PFV) }
  1074. { on the JVM platform, an array can have 0 elements; since the length
  1075. of the array is part of the array itself, make sure we allocate one
  1076. of the proper length to avoid getting unexpected results later --
  1077. allocating a temp of size 0 also forces it to be size 4 on regular
  1078. targets }
  1079. tg.gethltemp(current_asmdata.CurrAsmList,resultdef,(tarraydef(resultdef).highrange+1)*elesize,tt_normal,location.reference);
  1080. href:=location.reference;
  1081. makearrayref(href,eledef);
  1082. { Process nodes in array constructor }
  1083. hp:=self;
  1084. while assigned(hp) do
  1085. begin
  1086. if assigned(hp.left) then
  1087. begin
  1088. freetemp:=true;
  1089. secondpass(hp.left);
  1090. if (hp.left.location.loc=LOC_JUMP)<>
  1091. (hp.left.expectloc=LOC_JUMP) then
  1092. internalerror(2007103101);
  1093. { Move flags and jump in register }
  1094. if hp.left.location.loc in [LOC_FLAGS,LOC_JUMP] then
  1095. hlcg.location_force_reg(current_asmdata.CurrAsmList,hp.left.location,hp.left.resultdef,hp.left.resultdef,false);
  1096. if dovariant then
  1097. begin
  1098. { find the correct vtype value }
  1099. vtype:=$ff;
  1100. varfield:=nil;
  1101. vaddr:=false;
  1102. lt:=hp.left.resultdef;
  1103. case lt.typ of
  1104. enumdef,
  1105. orddef :
  1106. begin
  1107. if is_64bit(lt) then
  1108. begin
  1109. case torddef(lt).ordtype of
  1110. scurrency:
  1111. begin
  1112. vtype:=vtCurrency;
  1113. varfield:=tfieldvarsym(search_struct_member_no_helper(trecorddef(eledef),'VCURRENCY'));
  1114. end;
  1115. s64bit:
  1116. begin
  1117. vtype:=vtInt64;
  1118. varfield:=tfieldvarsym(search_struct_member_no_helper(trecorddef(eledef),'VINT64'));
  1119. end;
  1120. u64bit:
  1121. begin
  1122. vtype:=vtQWord;
  1123. varfield:=tfieldvarsym(search_struct_member_no_helper(trecorddef(eledef),'VQWORD'));
  1124. end;
  1125. end;
  1126. freetemp:=false;
  1127. vaddr:=true;
  1128. end
  1129. else if (lt.typ=enumdef) or
  1130. is_integer(lt) then
  1131. begin
  1132. vtype:=vtInteger;
  1133. varfield:=tfieldvarsym(search_struct_member_no_helper(trecorddef(eledef),'VINTEGER'));
  1134. end
  1135. else
  1136. if is_boolean(lt) then
  1137. begin
  1138. vtype:=vtBoolean;
  1139. varfield:=tfieldvarsym(search_struct_member_no_helper(trecorddef(eledef),'VINTEGER'));
  1140. end
  1141. else
  1142. if (lt.typ=orddef) then
  1143. begin
  1144. case torddef(lt).ordtype of
  1145. uchar:
  1146. begin
  1147. vtype:=vtChar;
  1148. varfield:=tfieldvarsym(search_struct_member_no_helper(trecorddef(eledef),'VINTEGER'));
  1149. end;
  1150. uwidechar:
  1151. begin
  1152. vtype:=vtWideChar;
  1153. varfield:=tfieldvarsym(search_struct_member_no_helper(trecorddef(eledef),'VINTEGER'));
  1154. end;
  1155. end;
  1156. end;
  1157. end;
  1158. floatdef :
  1159. begin
  1160. if is_currency(lt) then
  1161. begin
  1162. vtype:=vtCurrency;
  1163. varfield:=tfieldvarsym(search_struct_member_no_helper(trecorddef(eledef),'VCURRENCY'));
  1164. end
  1165. else
  1166. begin
  1167. vtype:=vtExtended;
  1168. varfield:=tfieldvarsym(search_struct_member_no_helper(trecorddef(eledef),'VEXTENDED'));
  1169. end;
  1170. freetemp:=false;
  1171. vaddr:=true;
  1172. end;
  1173. procvardef,
  1174. pointerdef :
  1175. begin
  1176. if is_pchar(lt) then
  1177. begin
  1178. vtype:=vtPChar;
  1179. varfield:=tfieldvarsym(search_struct_member_no_helper(trecorddef(eledef),'VPCHAR'));
  1180. end
  1181. else if is_pwidechar(lt) then
  1182. begin
  1183. vtype:=vtPWideChar;
  1184. varfield:=tfieldvarsym(search_struct_member_no_helper(trecorddef(eledef),'VPWIDECHAR'));
  1185. end
  1186. else
  1187. begin
  1188. vtype:=vtPointer;
  1189. varfield:=tfieldvarsym(search_struct_member_no_helper(trecorddef(eledef),'VPOINTER'));
  1190. end;
  1191. end;
  1192. variantdef :
  1193. begin
  1194. vtype:=vtVariant;
  1195. varfield:=tfieldvarsym(search_struct_member_no_helper(trecorddef(eledef),'VVARIANT'));
  1196. vaddr:=true;
  1197. freetemp:=false;
  1198. end;
  1199. classrefdef :
  1200. begin
  1201. vtype:=vtClass;
  1202. varfield:=tfieldvarsym(search_struct_member_no_helper(trecorddef(eledef),'VCLASS'));
  1203. end;
  1204. objectdef :
  1205. if is_interface(lt) then
  1206. begin
  1207. vtype:=vtInterface;
  1208. varfield:=tfieldvarsym(search_struct_member_no_helper(trecorddef(eledef),'VINTERFACE'));
  1209. end
  1210. { vtObject really means a class based on TObject }
  1211. else if is_class(lt) then
  1212. begin
  1213. vtype:=vtObject;
  1214. varfield:=tfieldvarsym(search_struct_member_no_helper(trecorddef(eledef),'VOBJECT'));
  1215. end
  1216. else
  1217. internalerror(200505171);
  1218. stringdef :
  1219. begin
  1220. if is_shortstring(lt) then
  1221. begin
  1222. vtype:=vtString;
  1223. varfield:=tfieldvarsym(search_struct_member_no_helper(trecorddef(eledef),'VSTRING'));
  1224. vaddr:=true;
  1225. freetemp:=false;
  1226. end
  1227. else
  1228. if is_ansistring(lt) then
  1229. begin
  1230. vtype:=vtAnsiString;
  1231. varfield:=tfieldvarsym(search_struct_member_no_helper(trecorddef(eledef),'VANSISTRING'));
  1232. freetemp:=false;
  1233. end
  1234. else
  1235. if is_widestring(lt) then
  1236. begin
  1237. vtype:=vtWideString;
  1238. varfield:=tfieldvarsym(search_struct_member_no_helper(trecorddef(eledef),'VWIDESTRING'));
  1239. freetemp:=false;
  1240. end
  1241. else
  1242. if is_unicodestring(lt) then
  1243. begin
  1244. vtype:=vtUnicodeString;
  1245. varfield:=tfieldvarsym(search_struct_member_no_helper(trecorddef(eledef),'VUNICODESTRING'));
  1246. freetemp:=false;
  1247. end;
  1248. end;
  1249. end;
  1250. if vtype=$ff then
  1251. internalerror(14357);
  1252. if not assigned(varfield) then
  1253. internalerror(2015102901);
  1254. { write changing field update href to the next element }
  1255. fref:=href;
  1256. hlcg.g_set_addr_nonbitpacked_record_field_ref(current_asmdata.CurrAsmList,trecorddef(eledef),varfield,fref);
  1257. if vaddr then
  1258. begin
  1259. hlcg.location_force_mem(current_asmdata.CurrAsmList,hp.left.location,lt);
  1260. tmpreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,cpointerdef.getreusable(lt));
  1261. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,hp.left.resultdef,cpointerdef.getreusable(lt),hp.left.location.reference,tmpreg);
  1262. hlcg.a_load_reg_ref(current_asmdata.CurrAsmList,cpointerdef.getreusable(lt),varfield.vardef,tmpreg,fref);
  1263. end
  1264. else
  1265. hlcg.a_load_loc_ref(current_asmdata.CurrAsmList,hp.left.resultdef,varfield.vardef,hp.left.location,fref);
  1266. { update href to the vtype field and write it }
  1267. fref:=href;
  1268. hlcg.g_set_addr_nonbitpacked_record_field_ref(current_asmdata.CurrAsmList,trecorddef(eledef),varvtypefield,fref);
  1269. hlcg.a_load_const_ref(current_asmdata.CurrAsmList,varvtypefield.vardef,vtype,fref);
  1270. { goto next array element }
  1271. advancearrayoffset(href,elesize);
  1272. end
  1273. else
  1274. { normal array constructor of the same type }
  1275. begin
  1276. if is_managed_type(resultdef) then
  1277. freetemp:=false;
  1278. case hp.left.location.loc of
  1279. LOC_MMREGISTER,
  1280. LOC_CMMREGISTER:
  1281. hlcg.a_loadmm_reg_ref(current_asmdata.CurrAsmList,hp.left.resultdef,hp.left.resultdef,
  1282. hp.left.location.register,href,mms_movescalar);
  1283. LOC_FPUREGISTER,
  1284. LOC_CFPUREGISTER :
  1285. hlcg.a_loadfpu_reg_ref(current_asmdata.CurrAsmList,hp.left.resultdef,hp.left.resultdef,hp.left.location.register,href);
  1286. LOC_REFERENCE,
  1287. LOC_CREFERENCE :
  1288. begin
  1289. if is_shortstring(hp.left.resultdef) then
  1290. hlcg.g_copyshortstring(current_asmdata.CurrAsmList,hp.left.location.reference,href,
  1291. Tstringdef(hp.left.resultdef))
  1292. else
  1293. hlcg.g_concatcopy(current_asmdata.CurrAsmList,eledef,hp.left.location.reference,href);
  1294. end;
  1295. else
  1296. begin
  1297. {$ifndef cpuhighleveltarget}
  1298. {$ifdef cpu64bitalu}
  1299. if hp.left.location.size in [OS_128,OS_S128] then
  1300. cg128.a_load128_loc_ref(current_asmdata.CurrAsmList,hp.left.location,href)
  1301. else
  1302. {$else cpu64bitalu}
  1303. if hp.left.location.size in [OS_64,OS_S64] then
  1304. cg64.a_load64_loc_ref(current_asmdata.CurrAsmList,hp.left.location,href)
  1305. else
  1306. {$endif cpu64bitalu}
  1307. {$endif not cpuhighleveltarget}
  1308. hlcg.a_load_loc_ref(current_asmdata.CurrAsmList,eledef,eledef,hp.left.location,href);
  1309. end;
  1310. end;
  1311. advancearrayoffset(href,elesize);
  1312. end;
  1313. if freetemp then
  1314. location_freetemp(current_asmdata.CurrAsmList,hp.left.location);
  1315. end;
  1316. { load next entry }
  1317. hp:=tarrayconstructornode(hp.right);
  1318. end;
  1319. end;
  1320. {*****************************************************************************
  1321. SecondRTTI
  1322. *****************************************************************************}
  1323. procedure tcgrttinode.pass_generate_code;
  1324. begin
  1325. location_reset_ref(location,LOC_CREFERENCE,OS_NO,sizeof(pint));
  1326. case rttidatatype of
  1327. rdt_normal:
  1328. location.reference.symbol:=RTTIWriter.get_rtti_label(rttidef,rttitype);
  1329. rdt_ord2str:
  1330. location.reference.symbol:=RTTIWriter.get_rtti_label_ord2str(rttidef,rttitype);
  1331. rdt_str2ord:
  1332. location.reference.symbol:=RTTIWriter.get_rtti_label_str2ord(rttidef,rttitype);
  1333. end;
  1334. end;
  1335. begin
  1336. cloadnode:=tcgloadnode;
  1337. cassignmentnode:=tcgassignmentnode;
  1338. carrayconstructornode:=tcgarrayconstructornode;
  1339. crttinode:=tcgrttinode;
  1340. end.