ncgld.pas 73 KB

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