ncgld.pas 70 KB

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