ncgld.pas 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103
  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. node,nld,cgutils;
  23. type
  24. tcgloadnode = class(tloadnode)
  25. procedure pass_generate_code;override;
  26. procedure generate_picvaraccess;virtual;
  27. procedure changereflocation(const ref: treference);
  28. end;
  29. tcgassignmentnode = class(tassignmentnode)
  30. procedure pass_generate_code;override;
  31. end;
  32. tcgarrayconstructornode = class(tarrayconstructornode)
  33. procedure pass_generate_code;override;
  34. end;
  35. tcgrttinode = class(trttinode)
  36. procedure pass_generate_code;override;
  37. end;
  38. implementation
  39. uses
  40. cutils,
  41. systems,
  42. verbose,globtype,globals,constexp,
  43. nutils,
  44. symconst,symtype,symdef,symsym,defutil,paramgr,
  45. ncnv,ncon,nmem,nbas,ncgrtti,
  46. aasmbase,aasmtai,aasmdata,aasmcpu,
  47. cgbase,pass_2,
  48. procinfo,
  49. cpubase,parabase,
  50. tgobj,ncgutil,
  51. cgobj,
  52. ncgbas,ncgflw;
  53. {*****************************************************************************
  54. SSA (for memory temps) support
  55. *****************************************************************************}
  56. type
  57. preplacerefrec = ^treplacerefrec;
  58. treplacerefrec = record
  59. old, new: preference;
  60. ressym: tsym;
  61. end;
  62. function doreplaceref(var n: tnode; para: pointer): foreachnoderesult;
  63. var
  64. rr: preplacerefrec absolute para;
  65. begin
  66. result := fen_false;
  67. case n.nodetype of
  68. loadn:
  69. begin
  70. { regular variable }
  71. if (tabstractvarsym(tloadnode(n).symtableentry).varoptions * [vo_is_dll_var, vo_is_thread_var] = []) and
  72. not assigned(tloadnode(n).left) and
  73. { not function result, or no exit in function }
  74. (((tloadnode(n).symtableentry <> rr^.ressym) and
  75. not(vo_is_funcret in tabstractvarsym(tloadnode(n).symtableentry).varoptions)) or
  76. not(fc_exit in flowcontrol)) and
  77. { stored in memory... }
  78. (tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.loc in [LOC_REFERENCE]) and
  79. { ... at the place we are looking for }
  80. references_equal(tabstractnormalvarsym(tloadnode(n).symtableentry).localloc.reference,rr^.old^) then
  81. begin
  82. { relocate variable }
  83. tcgloadnode(n).changereflocation(rr^.new^);
  84. result := fen_norecurse_true;
  85. end;
  86. end;
  87. temprefn:
  88. begin
  89. if (ti_valid in ttemprefnode(n).tempinfo^.flags) and
  90. { memory temp... }
  91. (ttemprefnode(n).tempinfo^.location.loc in [LOC_REFERENCE]) and
  92. { ... at the place we are looking for }
  93. references_equal(ttemprefnode(n).tempinfo^.location.reference,rr^.old^) then
  94. begin
  95. { relocate the temp }
  96. tcgtemprefnode(n).changelocation(rr^.new^);
  97. result := fen_norecurse_true;
  98. end;
  99. end;
  100. { optimize the searching a bit }
  101. derefn,addrn,
  102. calln,inlinen,casen,
  103. addn,subn,muln,
  104. andn,orn,xorn,
  105. ltn,lten,gtn,gten,equaln,unequaln,
  106. slashn,divn,shrn,shln,notn,
  107. inn,
  108. asn,isn:
  109. result := fen_norecurse_false;
  110. end;
  111. end;
  112. function maybechangetemp(list: TAsmList; var n: tnode; const newref: treference): boolean;
  113. var
  114. rr: treplacerefrec;
  115. begin
  116. result := false;
  117. { only do for -O2 or higher (breaks debugging since }
  118. { variables move to different memory locations) }
  119. if not(cs_opt_level2 in current_settings.optimizerswitches) or
  120. { must be a copy to a memory location ... }
  121. (n.location.loc <> LOC_REFERENCE) or
  122. { not inside a control flow statement and no goto's in sight }
  123. ([fc_inflowcontrol,fc_gotolabel] * flowcontrol <> []) or
  124. { source and destination are temps (= not global variables) }
  125. not tg.istemp(n.location.reference) or
  126. not tg.istemp(newref) or
  127. { and both point to the start of a temp, and the source is a }
  128. { non-persistent temp (otherwise we need some kind of copy- }
  129. { on-write support in case later on both are still used) }
  130. (tg.gettypeoftemp(newref) <> tt_normal) or
  131. not (tg.gettypeoftemp(n.location.reference) in [tt_normal,tt_persistent]) or
  132. { and both have the same size }
  133. (tg.sizeoftemp(current_asmdata.CurrAsmList,newref) <> tg.sizeoftemp(current_asmdata.CurrAsmList,n.location.reference)) then
  134. exit;
  135. { find the source of the old reference (loadnode or tempnode) }
  136. { and replace it with the new reference }
  137. rr.old := @n.location.reference;
  138. rr.new := @newref;
  139. rr.ressym := nil;
  140. if (current_procinfo.procdef.funcretloc[calleeside].loc<>LOC_VOID) and
  141. assigned(current_procinfo.procdef.funcretsym) and
  142. (tabstractvarsym(current_procinfo.procdef.funcretsym).refs <> 0) then
  143. if (current_procinfo.procdef.proctypeoption=potype_constructor) then
  144. rr.ressym:=tsym(current_procinfo.procdef.parast.Find('self'))
  145. else
  146. rr.ressym:=current_procinfo.procdef.funcretsym;
  147. { if source not found, don't do anything }
  148. if not foreachnodestatic(n,@doreplaceref,@rr) then
  149. exit;
  150. n.location.reference := newref;
  151. result:=true;
  152. end;
  153. {*****************************************************************************
  154. SecondLoad
  155. *****************************************************************************}
  156. procedure tcgloadnode.generate_picvaraccess;
  157. begin
  158. {$ifndef sparc}
  159. location.reference.base:=current_procinfo.got;
  160. location.reference.symbol:=current_asmdata.RefAsmSymbol(tstaticvarsym(symtableentry).mangledname+'@GOT');
  161. {$endif sparc}
  162. end;
  163. procedure tcgloadnode.changereflocation(const ref: treference);
  164. var
  165. oldtemptype: ttemptype;
  166. begin
  167. if (location.loc<>LOC_REFERENCE) then
  168. internalerror(2007020812);
  169. if not tg.istemp(location.reference) then
  170. internalerror(2007020813);
  171. oldtemptype:=tg.gettypeoftemp(location.reference);
  172. if (oldtemptype = tt_persistent) then
  173. tg.ChangeTempType(current_asmdata.CurrAsmList,location.reference,tt_normal);
  174. tg.ungettemp(current_asmdata.CurrAsmList,location.reference);
  175. location.reference:=ref;
  176. tg.ChangeTempType(current_asmdata.CurrAsmList,location.reference,oldtemptype);
  177. tabstractnormalvarsym(symtableentry).localloc:=location;
  178. end;
  179. procedure tcgloadnode.pass_generate_code;
  180. var
  181. hregister : tregister;
  182. vs : tabstractnormalvarsym;
  183. gvs : tstaticvarsym;
  184. pd : tprocdef;
  185. href : treference;
  186. newsize : tcgsize;
  187. endrelocatelab,
  188. norelocatelab : tasmlabel;
  189. paraloc1 : tcgpara;
  190. begin
  191. { we don't know the size of all arrays }
  192. newsize:=def_cgsize(resultdef);
  193. location_reset(location,LOC_REFERENCE,newsize);
  194. case symtableentry.typ of
  195. absolutevarsym :
  196. begin
  197. { this is only for toasm and toaddr }
  198. case tabsolutevarsym(symtableentry).abstyp of
  199. toaddr :
  200. begin
  201. {$ifdef i386}
  202. if tabsolutevarsym(symtableentry).absseg then
  203. location.reference.segment:=NR_FS;
  204. {$endif i386}
  205. location.reference.offset:=tabsolutevarsym(symtableentry).addroffset;
  206. end;
  207. toasm :
  208. location.reference.symbol:=current_asmdata.RefAsmSymbol(tabsolutevarsym(symtableentry).mangledname);
  209. else
  210. internalerror(200310283);
  211. end;
  212. end;
  213. constsym:
  214. begin
  215. if tconstsym(symtableentry).consttyp=constresourcestring then
  216. begin
  217. location_reset(location,LOC_CREFERENCE,OS_ADDR);
  218. location.reference.symbol:=current_asmdata.RefAsmSymbol(make_mangledname('RESSTR',symtableentry.owner,symtableentry.name));
  219. { Resourcestring layout:
  220. TResourceStringRecord = Packed Record
  221. Name,
  222. CurrentValue,
  223. DefaultValue : AnsiString;
  224. HashValue : LongWord;
  225. end;
  226. }
  227. location.reference.offset:=sizeof(aint);
  228. end
  229. else
  230. internalerror(22798);
  231. end;
  232. staticvarsym :
  233. begin
  234. gvs:=tstaticvarsym(symtableentry);
  235. if ([vo_is_dll_var,vo_is_external] * gvs.varoptions <> []) then
  236. begin
  237. location.reference.base := cg.g_indirect_sym_load(current_asmdata.CurrAsmList,tstaticvarsym(symtableentry).mangledname);
  238. if (location.reference.base <> NR_NO) then
  239. exit;
  240. end;
  241. if (vo_is_dll_var in gvs.varoptions) then
  242. { DLL variable }
  243. begin
  244. hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
  245. location.reference.symbol:=current_asmdata.RefAsmSymbol(tstaticvarsym(symtableentry).mangledname);
  246. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,location.reference,hregister);
  247. reference_reset_base(location.reference,hregister,0);
  248. end
  249. { Thread variable }
  250. else if (vo_is_thread_var in gvs.varoptions) and
  251. not(tf_section_threadvars in target_info.flags) then
  252. begin
  253. if (tf_section_threadvars in target_info.flags) then
  254. begin
  255. if gvs.localloc.loc=LOC_INVALID then
  256. reference_reset_symbol(location.reference,current_asmdata.RefAsmSymbol(gvs.mangledname),0)
  257. else
  258. location:=gvs.localloc;
  259. {$ifdef i386}
  260. case target_info.system of
  261. system_i386_linux:
  262. location.reference.segment:=NR_GS;
  263. system_i386_win32:
  264. location.reference.segment:=NR_FS;
  265. end;
  266. {$endif i386}
  267. end
  268. else
  269. begin
  270. {
  271. Thread var loading is optimized to first check if
  272. a relocate function is available. When the function
  273. is available it is called to retrieve the address.
  274. Otherwise the address is loaded with the symbol
  275. The code needs to be in the order to first handle the
  276. call and then the address load to be sure that the
  277. register that is used for returning is the same (PFV)
  278. }
  279. current_asmdata.getjumplabel(norelocatelab);
  280. current_asmdata.getjumplabel(endrelocatelab);
  281. { make sure hregister can't allocate the register necessary for the parameter }
  282. paraloc1.init;
  283. paramanager.getintparaloc(pocall_default,1,paraloc1);
  284. hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
  285. reference_reset_symbol(href,current_asmdata.RefAsmSymbol('FPC_THREADVAR_RELOCATE'),0);
  286. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,href,hregister);
  287. cg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,OS_ADDR,OC_EQ,0,hregister,norelocatelab);
  288. { don't save the allocated register else the result will be destroyed later }
  289. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(tstaticvarsym(symtableentry).mangledname),0);
  290. paramanager.allocparaloc(current_asmdata.CurrAsmList,paraloc1);
  291. cg.a_param_ref(current_asmdata.CurrAsmList,OS_32,href,paraloc1);
  292. paramanager.freeparaloc(current_asmdata.CurrAsmList,paraloc1);
  293. paraloc1.done;
  294. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  295. cg.a_call_reg(current_asmdata.CurrAsmList,hregister);
  296. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  297. cg.getcpuregister(current_asmdata.CurrAsmList,NR_FUNCTION_RESULT_REG);
  298. cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_FUNCTION_RESULT_REG);
  299. hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
  300. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_ADDR,NR_FUNCTION_RESULT_REG,hregister);
  301. cg.a_jmp_always(current_asmdata.CurrAsmList,endrelocatelab);
  302. cg.a_label(current_asmdata.CurrAsmList,norelocatelab);
  303. { no relocation needed, load the address of the variable only, the
  304. layout of a threadvar is (4 bytes pointer):
  305. 0 - Threadvar index
  306. 4 - Threadvar value in single threading }
  307. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(tstaticvarsym(symtableentry).mangledname),sizeof(aint));
  308. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,hregister);
  309. cg.a_label(current_asmdata.CurrAsmList,endrelocatelab);
  310. location.reference.base:=hregister;
  311. end;
  312. end
  313. { Normal (or external) variable }
  314. else
  315. begin
  316. if gvs.localloc.loc=LOC_INVALID then
  317. reference_reset_symbol(location.reference,current_asmdata.RefAsmSymbol(gvs.mangledname),0)
  318. else
  319. location:=gvs.localloc;
  320. end;
  321. { make const a LOC_CREFERENCE }
  322. if (gvs.varspez=vs_const) and
  323. (location.loc=LOC_REFERENCE) then
  324. location.loc:=LOC_CREFERENCE;
  325. end;
  326. paravarsym,
  327. localvarsym :
  328. begin
  329. vs:=tabstractnormalvarsym(symtableentry);
  330. { Nested variable }
  331. if assigned(left) then
  332. begin
  333. secondpass(left);
  334. if left.location.loc<>LOC_REGISTER then
  335. internalerror(200309286);
  336. if vs.localloc.loc<>LOC_REFERENCE then
  337. internalerror(200409241);
  338. reference_reset_base(location.reference,left.location.register,vs.localloc.reference.offset);
  339. end
  340. else
  341. location:=vs.localloc;
  342. { handle call by reference variables when they are not
  343. alreayd copied to local copies. Also ignore the reference
  344. when we need to load the self pointer for objects }
  345. if is_addr_param_load then
  346. begin
  347. if (location.loc in [LOC_CREGISTER,LOC_REGISTER]) then
  348. hregister:=location.register
  349. else
  350. begin
  351. hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
  352. { we need to load only an address }
  353. location.size:=OS_ADDR;
  354. cg.a_load_loc_reg(current_asmdata.CurrAsmList,location.size,location,hregister);
  355. end;
  356. location_reset(location,LOC_REFERENCE,newsize);
  357. location.reference.base:=hregister;
  358. end;
  359. { make const a LOC_CREFERENCE }
  360. if (vs.varspez=vs_const) and
  361. (location.loc=LOC_REFERENCE) then
  362. location.loc:=LOC_CREFERENCE;
  363. end;
  364. procsym:
  365. begin
  366. if not assigned(procdef) then
  367. internalerror(200312011);
  368. if assigned(left) then
  369. begin
  370. if (sizeof(aint) = 4) then
  371. location_reset(location,LOC_CREFERENCE,OS_64)
  372. else if (sizeof(aint) = 8) then
  373. location_reset(location,LOC_CREFERENCE,OS_128)
  374. else
  375. internalerror(20020520);
  376. tg.GetTemp(current_asmdata.CurrAsmList,2*sizeof(aint),tt_normal,location.reference);
  377. secondpass(left);
  378. { load class instance/classrefdef address }
  379. if left.location.loc=LOC_CONSTANT then
  380. location_force_reg(current_asmdata.CurrAsmList,left.location,OS_ADDR,false);
  381. case left.location.loc of
  382. LOC_CREGISTER,
  383. LOC_REGISTER:
  384. begin
  385. { this is not possible for objects }
  386. if is_object(left.resultdef) then
  387. internalerror(200304234);
  388. hregister:=left.location.register;
  389. end;
  390. LOC_CREFERENCE,
  391. LOC_REFERENCE:
  392. begin
  393. hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
  394. if not is_object(left.resultdef) then
  395. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,left.location.reference,hregister)
  396. else
  397. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.location.reference,hregister);
  398. location_freetemp(current_asmdata.CurrAsmList,left.location);
  399. end;
  400. else
  401. internalerror(200610311);
  402. end;
  403. { store the class instance or classredef address }
  404. href:=location.reference;
  405. inc(href.offset,sizeof(aint));
  406. cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,hregister,href);
  407. { virtual method ? }
  408. if (po_virtualmethod in procdef.procoptions) and
  409. not(nf_inherited in flags) then
  410. begin
  411. { a classrefdef already points to the VMT }
  412. if (left.resultdef.typ<>classrefdef) then
  413. begin
  414. { load vmt pointer }
  415. reference_reset_base(href,hregister,0);
  416. hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
  417. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,href,hregister);
  418. end;
  419. { load method address }
  420. reference_reset_base(href,hregister,procdef._class.vmtmethodoffset(procdef.extnumber));
  421. hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
  422. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,href,hregister);
  423. { ... and store it }
  424. cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,hregister,location.reference);
  425. end
  426. else
  427. begin
  428. { load address of the function }
  429. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(procdef.mangledname),0);
  430. hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
  431. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,hregister);
  432. cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,hregister,location.reference);
  433. end;
  434. end
  435. else
  436. begin
  437. pd:=tprocdef(tprocsym(symtableentry).ProcdefList[0]);
  438. if (po_external in pd.procoptions) then
  439. location.reference.base := cg.g_indirect_sym_load(current_asmdata.CurrAsmList,pd.mangledname);
  440. {!!!!! Be aware, work on virtual methods too }
  441. if (location.reference.base = NR_NO) then
  442. location.reference.symbol:=current_asmdata.RefAsmSymbol(procdef.mangledname);
  443. end;
  444. end;
  445. labelsym :
  446. location.reference.symbol:=tcglabelnode((tlabelsym(symtableentry).code)).getasmlabel;
  447. else internalerror(200510032);
  448. end;
  449. end;
  450. {*****************************************************************************
  451. SecondAssignment
  452. *****************************************************************************}
  453. procedure tcgassignmentnode.pass_generate_code;
  454. var
  455. otlabel,hlabel,oflabel : tasmlabel;
  456. href : treference;
  457. releaseright : boolean;
  458. len : aint;
  459. r:Tregister;
  460. begin
  461. location_reset(location,LOC_VOID,OS_NO);
  462. otlabel:=current_procinfo.CurrTrueLabel;
  463. oflabel:=current_procinfo.CurrFalseLabel;
  464. current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel);
  465. current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel);
  466. {
  467. in most cases we can process first the right node which contains
  468. the most complex code. Exceptions for this are:
  469. - result is in flags, loading left will then destroy the flags
  470. - result is a jump, loading left must be already done before the jump is made
  471. - result need reference count, when left points to a value used in
  472. right then decreasing the refcnt on left can possibly release
  473. the memory before right increased the refcnt, result is that an
  474. empty value is assigned
  475. But not when the result is in the flags, then
  476. loading the left node afterwards can destroy the flags.
  477. }
  478. if not(right.expectloc in [LOC_FLAGS,LOC_JUMP]) and
  479. ((right.resultdef.needs_inittable) or
  480. (node_complexity(right)>node_complexity(left))) then
  481. begin
  482. secondpass(right);
  483. { increment source reference counter, this is
  484. useless for constants }
  485. if (right.resultdef.needs_inittable) and
  486. not is_constnode(right) then
  487. begin
  488. location_force_mem(current_asmdata.CurrAsmList,right.location);
  489. location_get_data_ref(current_asmdata.CurrAsmList,right.location,href,false);
  490. cg.g_incrrefcount(current_asmdata.CurrAsmList,right.resultdef,href);
  491. end;
  492. if codegenerror then
  493. exit;
  494. { left can't be never a 64 bit LOC_REGISTER, so the 3. arg }
  495. { can be false }
  496. secondpass(left);
  497. { decrement destination reference counter }
  498. if (left.resultdef.needs_inittable) then
  499. begin
  500. location_get_data_ref(current_asmdata.CurrAsmList,left.location,href,false);
  501. cg.g_decrrefcount(current_asmdata.CurrAsmList,left.resultdef,href);
  502. end;
  503. if codegenerror then
  504. exit;
  505. end
  506. else
  507. begin
  508. { calculate left sides }
  509. secondpass(left);
  510. { decrement destination reference counter }
  511. if (left.resultdef.needs_inittable) then
  512. begin
  513. location_get_data_ref(current_asmdata.CurrAsmList,left.location,href,false);
  514. cg.g_decrrefcount(current_asmdata.CurrAsmList,left.resultdef,href);
  515. end;
  516. if codegenerror then
  517. exit;
  518. { left can't be never a 64 bit LOC_REGISTER, so the 3. arg }
  519. { can be false }
  520. secondpass(right);
  521. { increment source reference counter, this is
  522. useless for string constants}
  523. if (right.resultdef.needs_inittable) and
  524. (right.nodetype<>stringconstn) then
  525. begin
  526. location_force_mem(current_asmdata.CurrAsmList,right.location);
  527. location_get_data_ref(current_asmdata.CurrAsmList,right.location,href,false);
  528. cg.g_incrrefcount(current_asmdata.CurrAsmList,right.resultdef,href);
  529. end;
  530. if codegenerror then
  531. exit;
  532. end;
  533. releaseright:=true;
  534. { shortstring assignments are handled separately }
  535. if is_shortstring(left.resultdef) then
  536. begin
  537. {
  538. we can get here only in the following situations
  539. for the right node:
  540. - empty constant string
  541. - char
  542. }
  543. { The addn is replaced by a blockn or calln that already returns
  544. a shortstring }
  545. if is_shortstring(right.resultdef) and
  546. (right.nodetype in [blockn,calln]) then
  547. begin
  548. { nothing to do }
  549. end
  550. { empty constant string }
  551. else if (right.nodetype=stringconstn) and
  552. (tstringconstnode(right).len=0) then
  553. begin
  554. cg.a_load_const_ref(current_asmdata.CurrAsmList,OS_8,0,left.location.reference);
  555. end
  556. { char loading }
  557. else if is_char(right.resultdef) then
  558. begin
  559. if right.nodetype=ordconstn then
  560. begin
  561. if (target_info.endian = endian_little) then
  562. cg.a_load_const_ref(current_asmdata.CurrAsmList,OS_16,(tordconstnode(right).value.svalue shl 8) or 1,
  563. setalignment(left.location.reference,1))
  564. else
  565. cg.a_load_const_ref(current_asmdata.CurrAsmList,OS_16,tordconstnode(right).value.svalue or (1 shl 8),
  566. setalignment(left.location.reference,1));
  567. end
  568. else
  569. begin
  570. href:=left.location.reference;
  571. cg.a_load_const_ref(current_asmdata.CurrAsmList,OS_8,1,href);
  572. inc(href.offset,1);
  573. case right.location.loc of
  574. LOC_REGISTER,
  575. LOC_CREGISTER :
  576. begin
  577. r:=cg.makeregsize(current_asmdata.CurrAsmList,right.location.register,OS_8);
  578. cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_8,OS_8,r,href);
  579. end;
  580. LOC_REFERENCE,
  581. LOC_CREFERENCE :
  582. cg.a_load_ref_ref(current_asmdata.CurrAsmList,OS_8,OS_8,right.location.reference,href);
  583. else
  584. internalerror(200205111);
  585. end;
  586. end;
  587. end
  588. else
  589. internalerror(200204249);
  590. end
  591. { try to reuse memory locations instead of copying }
  592. { copy to a memory location ... }
  593. else if (right.location.loc = LOC_REFERENCE) and
  594. maybechangetemp(current_asmdata.CurrAsmList,left,right.location.reference) then
  595. begin
  596. { if it worked, we're done }
  597. end
  598. else
  599. begin
  600. { SSA support }
  601. maybechangeloadnodereg(current_asmdata.CurrAsmList,left,false);
  602. maybechangeloadnodereg(current_asmdata.CurrAsmList,right,true);
  603. case right.location.loc of
  604. LOC_CONSTANT :
  605. begin
  606. {$ifndef cpu64bit}
  607. if (left.location.size in [OS_64,OS_S64]) or (right.location.size in [OS_64,OS_S64]) then
  608. cg64.a_load64_const_loc(current_asmdata.CurrAsmList,right.location.value64,left.location)
  609. else
  610. {$endif cpu64bit}
  611. cg.a_load_const_loc(current_asmdata.CurrAsmList,right.location.value,left.location);
  612. end;
  613. LOC_REFERENCE,
  614. LOC_CREFERENCE :
  615. begin
  616. case left.location.loc of
  617. LOC_REGISTER,
  618. LOC_CREGISTER :
  619. begin
  620. {$ifndef cpu64bit}
  621. if left.location.size in [OS_64,OS_S64] then
  622. cg64.a_load64_ref_reg(current_asmdata.CurrAsmList,right.location.reference,left.location.register64)
  623. else
  624. {$endif cpu64bit}
  625. cg.a_load_ref_reg(current_asmdata.CurrAsmList,right.location.size,left.location.size,right.location.reference,left.location.register);
  626. end;
  627. LOC_FPUREGISTER,
  628. LOC_CFPUREGISTER :
  629. begin
  630. cg.a_loadfpu_ref_reg(current_asmdata.CurrAsmList,
  631. right.location.size,left.location.size,
  632. right.location.reference,
  633. left.location.register);
  634. end;
  635. LOC_REFERENCE,
  636. LOC_CREFERENCE :
  637. begin
  638. {$warning HACK: unaligned test, maybe remove all unaligned locations (array of char) from the compiler}
  639. { Use unaligned copy when the offset is not aligned }
  640. len:=left.resultdef.size;
  641. if (right.location.reference.offset mod sizeof(aint)<>0) or
  642. (left.location.reference.offset mod sizeof(aint)<>0) or
  643. (right.resultdef.alignment<sizeof(aint)) or
  644. ((right.location.reference.alignment<>0) and
  645. (right.location.reference.alignment<sizeof(aint))) or
  646. ((left.location.reference.alignment<>0) and
  647. (left.location.reference.alignment<sizeof(aint))) then
  648. cg.g_concatcopy_unaligned(current_asmdata.CurrAsmList,right.location.reference,left.location.reference,len)
  649. else
  650. cg.g_concatcopy(current_asmdata.CurrAsmList,right.location.reference,left.location.reference,len);
  651. end;
  652. LOC_MMREGISTER,
  653. LOC_CMMREGISTER:
  654. cg.a_loadmm_ref_reg(current_asmdata.CurrAsmList,
  655. right.location.size,
  656. left.location.size,
  657. right.location.reference,
  658. left.location.register,mms_movescalar);
  659. LOC_SUBSETREG,
  660. LOC_CSUBSETREG:
  661. cg.a_load_ref_subsetreg(current_asmdata.CurrAsmList,right.location.size,left.location.size,right.location.reference,left.location.sreg);
  662. LOC_SUBSETREF,
  663. LOC_CSUBSETREF:
  664. {$ifndef cpu64bit}
  665. if right.location.size in [OS_64,OS_S64] then
  666. cg64.a_load64_ref_subsetref(current_asmdata.CurrAsmList,right.location.reference,left.location.sref)
  667. else
  668. {$endif cpu64bit}
  669. cg.a_load_ref_subsetref(current_asmdata.CurrAsmList,right.location.size,left.location.size,right.location.reference,left.location.sref);
  670. else
  671. internalerror(200203284);
  672. end;
  673. end;
  674. {$ifdef SUPPORT_MMX}
  675. LOC_CMMXREGISTER,
  676. LOC_MMXREGISTER:
  677. begin
  678. if left.location.loc=LOC_CMMXREGISTER then
  679. cg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,OS_M64,OS_M64,right.location.register,left.location.register,nil)
  680. else
  681. cg.a_loadmm_reg_ref(current_asmdata.CurrAsmList,OS_M64,OS_M64,right.location.register,left.location.reference,nil);
  682. end;
  683. {$endif SUPPORT_MMX}
  684. LOC_MMREGISTER,
  685. LOC_CMMREGISTER:
  686. begin
  687. if left.resultdef.typ=arraydef then
  688. begin
  689. end
  690. else
  691. begin
  692. if left.location.loc=LOC_CMMREGISTER then
  693. cg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,right.location.size,left.location.size,right.location.register,left.location.register,mms_movescalar)
  694. else
  695. cg.a_loadmm_reg_ref(current_asmdata.CurrAsmList,right.location.size,left.location.size,right.location.register,left.location.reference,mms_movescalar);
  696. end;
  697. end;
  698. LOC_REGISTER,
  699. LOC_CREGISTER :
  700. begin
  701. {$ifndef cpu64bit}
  702. if left.location.size in [OS_64,OS_S64] then
  703. cg64.a_load64_reg_loc(current_asmdata.CurrAsmList,
  704. right.location.register64,left.location)
  705. else
  706. {$endif cpu64bit}
  707. cg.a_load_reg_loc(current_asmdata.CurrAsmList,right.location.size,right.location.register,left.location);
  708. end;
  709. LOC_FPUREGISTER,
  710. LOC_CFPUREGISTER :
  711. begin
  712. { we can't do direct moves between fpu and mm registers }
  713. if left.location.loc in [LOC_MMREGISTER,LOC_CMMREGISTER] then
  714. begin
  715. location_force_mmregscalar(current_asmdata.CurrAsmList,right.location,false);
  716. cg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,
  717. right.location.size,left.location.size,
  718. right.location.register,left.location.register,mms_movescalar);
  719. end
  720. else
  721. cg.a_loadfpu_reg_loc(current_asmdata.CurrAsmList,
  722. right.location.size,
  723. right.location.register,left.location);
  724. end;
  725. LOC_SUBSETREG,
  726. LOC_CSUBSETREG:
  727. begin
  728. cg.a_load_subsetreg_loc(current_asmdata.CurrAsmList,
  729. right.location.size,right.location.sreg,left.location);
  730. end;
  731. LOC_SUBSETREF,
  732. LOC_CSUBSETREF:
  733. begin
  734. {$ifndef cpu64bit}
  735. if right.location.size in [OS_64,OS_S64] then
  736. cg64.a_load64_subsetref_loc(current_asmdata.CurrAsmList,right.location.sref,left.location)
  737. else
  738. {$endif cpu64bit}
  739. cg.a_load_subsetref_loc(current_asmdata.CurrAsmList,
  740. right.location.size,right.location.sref,left.location);
  741. end;
  742. LOC_JUMP :
  743. begin
  744. current_asmdata.getjumplabel(hlabel);
  745. cg.a_label(current_asmdata.CurrAsmList,current_procinfo.CurrTrueLabel);
  746. cg.a_load_const_loc(current_asmdata.CurrAsmList,1,left.location);
  747. cg.a_jmp_always(current_asmdata.CurrAsmList,hlabel);
  748. cg.a_label(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
  749. cg.a_load_const_loc(current_asmdata.CurrAsmList,0,left.location);
  750. cg.a_label(current_asmdata.CurrAsmList,hlabel);
  751. end;
  752. {$ifdef cpuflags}
  753. LOC_FLAGS :
  754. begin
  755. {This can be a wordbool or longbool too, no?}
  756. case left.location.loc of
  757. LOC_REGISTER,LOC_CREGISTER:
  758. cg.g_flags2reg(current_asmdata.CurrAsmList,def_cgsize(left.resultdef),right.location.resflags,left.location.register);
  759. LOC_REFERENCE:
  760. cg.g_flags2ref(current_asmdata.CurrAsmList,def_cgsize(left.resultdef),right.location.resflags,left.location.reference);
  761. LOC_SUBSETREG,LOC_SUBSETREF:
  762. begin
  763. r:=cg.getintregister(current_asmdata.CurrAsmList,def_cgsize(left.resultdef));
  764. cg.g_flags2reg(current_asmdata.CurrAsmList,def_cgsize(left.resultdef),right.location.resflags,r);
  765. cg.a_load_reg_loc(current_asmdata.CurrAsmList,def_cgsize(left.resultdef),r,left.location);
  766. end;
  767. else
  768. internalerror(200203273);
  769. end;
  770. end;
  771. {$endif cpuflags}
  772. end;
  773. end;
  774. if releaseright then
  775. location_freetemp(current_asmdata.CurrAsmList,right.location);
  776. current_procinfo.CurrTrueLabel:=otlabel;
  777. current_procinfo.CurrFalseLabel:=oflabel;
  778. end;
  779. {*****************************************************************************
  780. SecondArrayConstruct
  781. *****************************************************************************}
  782. const
  783. vtInteger = 0;
  784. vtBoolean = 1;
  785. vtChar = 2;
  786. vtExtended = 3;
  787. vtString = 4;
  788. vtPointer = 5;
  789. vtPChar = 6;
  790. vtObject = 7;
  791. vtClass = 8;
  792. vtWideChar = 9;
  793. vtPWideChar = 10;
  794. vtAnsiString32 = 11;
  795. vtCurrency = 12;
  796. vtVariant = 13;
  797. vtInterface = 14;
  798. vtWideString = 15;
  799. vtInt64 = 16;
  800. vtQWord = 17;
  801. vtAnsiString16 = 18;
  802. vtAnsiString64 = 19;
  803. procedure tcgarrayconstructornode.pass_generate_code;
  804. var
  805. hp : tarrayconstructornode;
  806. href : treference;
  807. lt : tdef;
  808. vaddr : boolean;
  809. vtype : longint;
  810. freetemp,
  811. dovariant : boolean;
  812. elesize : longint;
  813. tmpreg : tregister;
  814. paraloc : tcgparalocation;
  815. otlabel,
  816. oflabel : tasmlabel;
  817. begin
  818. if is_packed_array(resultdef) then
  819. internalerror(200608042);
  820. dovariant:=(nf_forcevaria in flags) or is_variant_array(resultdef);
  821. if dovariant then
  822. elesize:=sizeof(aint)+sizeof(aint)
  823. else
  824. elesize:=tarraydef(resultdef).elesize;
  825. location_reset(location,LOC_CREFERENCE,OS_NO);
  826. fillchar(paraloc,sizeof(paraloc),0);
  827. { Allocate always a temp, also if no elements are required, to
  828. be sure that location is valid (PFV) }
  829. if tarraydef(resultdef).highrange=-1 then
  830. tg.GetTemp(current_asmdata.CurrAsmList,elesize,tt_normal,location.reference)
  831. else
  832. tg.GetTemp(current_asmdata.CurrAsmList,(tarraydef(resultdef).highrange+1)*elesize,tt_normal,location.reference);
  833. href:=location.reference;
  834. { Process nodes in array constructor }
  835. hp:=self;
  836. while assigned(hp) do
  837. begin
  838. if assigned(hp.left) then
  839. begin
  840. freetemp:=true;
  841. if (hp.left.expectloc=LOC_JUMP) then
  842. begin
  843. otlabel:=current_procinfo.CurrTrueLabel;
  844. oflabel:=current_procinfo.CurrFalseLabel;
  845. current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel);
  846. current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel);
  847. end;
  848. secondpass(hp.left);
  849. { Move flags and jump in register }
  850. if hp.left.location.loc in [LOC_FLAGS,LOC_JUMP] then
  851. location_force_reg(current_asmdata.CurrAsmList,hp.left.location,def_cgsize(hp.left.resultdef),false);
  852. if (hp.left.location.loc=LOC_JUMP) then
  853. begin
  854. if (hp.left.expectloc<>LOC_JUMP) then
  855. internalerror(2007103101);
  856. current_procinfo.CurrTrueLabel:=otlabel;
  857. current_procinfo.CurrFalseLabel:=oflabel;
  858. end;
  859. if dovariant then
  860. begin
  861. { find the correct vtype value }
  862. vtype:=$ff;
  863. vaddr:=false;
  864. lt:=hp.left.resultdef;
  865. case lt.typ of
  866. enumdef,
  867. orddef :
  868. begin
  869. if is_64bit(lt) then
  870. begin
  871. case torddef(lt).ordtype of
  872. scurrency:
  873. vtype:=vtCurrency;
  874. s64bit:
  875. vtype:=vtInt64;
  876. u64bit:
  877. vtype:=vtQWord;
  878. end;
  879. freetemp:=false;
  880. vaddr:=true;
  881. end
  882. else if (lt.typ=enumdef) or
  883. is_integer(lt) then
  884. vtype:=vtInteger
  885. else
  886. if is_boolean(lt) then
  887. vtype:=vtBoolean
  888. else
  889. if (lt.typ=orddef) then
  890. begin
  891. case torddef(lt).ordtype of
  892. uchar:
  893. vtype:=vtChar;
  894. uwidechar:
  895. vtype:=vtWideChar;
  896. end;
  897. end;
  898. end;
  899. floatdef :
  900. begin
  901. if is_currency(lt) then
  902. vtype:=vtCurrency
  903. else
  904. vtype:=vtExtended;
  905. freetemp:=false;
  906. vaddr:=true;
  907. end;
  908. procvardef,
  909. pointerdef :
  910. begin
  911. if is_pchar(lt) then
  912. vtype:=vtPChar
  913. else if is_pwidechar(lt) then
  914. vtype:=vtPWideChar
  915. else
  916. vtype:=vtPointer;
  917. end;
  918. variantdef :
  919. begin
  920. vtype:=vtVariant;
  921. vaddr:=true;
  922. freetemp:=false;
  923. end;
  924. classrefdef :
  925. vtype:=vtClass;
  926. objectdef :
  927. if is_interface(lt) then
  928. vtype:=vtInterface
  929. { vtObject really means a class based on TObject }
  930. else if is_class(lt) then
  931. vtype:=vtObject
  932. else
  933. internalerror(200505171);
  934. stringdef :
  935. begin
  936. if is_shortstring(lt) then
  937. begin
  938. vtype:=vtString;
  939. vaddr:=true;
  940. freetemp:=false;
  941. end
  942. else
  943. if is_ansistring(lt) then
  944. begin
  945. vtype:=vtAnsiString;
  946. freetemp:=false;
  947. end
  948. else
  949. if is_widestring(lt) then
  950. begin
  951. vtype:=vtWideString;
  952. freetemp:=false;
  953. end;
  954. end;
  955. end;
  956. if vtype=$ff then
  957. internalerror(14357);
  958. { write changing field update href to the next element }
  959. inc(href.offset,sizeof(aint));
  960. if vaddr then
  961. begin
  962. location_force_mem(current_asmdata.CurrAsmList,hp.left.location);
  963. tmpreg:=cg.getaddressregister(current_asmdata.CurrAsmList);
  964. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,hp.left.location.reference,tmpreg);
  965. cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,tmpreg,href);
  966. end
  967. else
  968. cg.a_load_loc_ref(current_asmdata.CurrAsmList,OS_ADDR,hp.left.location,href);
  969. { update href to the vtype field and write it }
  970. dec(href.offset,sizeof(aint));
  971. cg.a_load_const_ref(current_asmdata.CurrAsmList, OS_INT,vtype,href);
  972. { goto next array element }
  973. inc(href.offset,sizeof(aint)*2);
  974. end
  975. else
  976. { normal array constructor of the same type }
  977. begin
  978. if resultdef.needs_inittable then
  979. freetemp:=false;
  980. case hp.left.location.loc of
  981. LOC_MMREGISTER,
  982. LOC_CMMREGISTER:
  983. cg.a_loadmm_reg_ref(current_asmdata.CurrAsmList,hp.left.location.size,hp.left.location.size,
  984. hp.left.location.register,href,mms_movescalar);
  985. LOC_FPUREGISTER,
  986. LOC_CFPUREGISTER :
  987. cg.a_loadfpu_reg_ref(current_asmdata.CurrAsmList,hp.left.location.size,hp.left.location.size,hp.left.location.register,href);
  988. LOC_REFERENCE,
  989. LOC_CREFERENCE :
  990. begin
  991. if is_shortstring(hp.left.resultdef) then
  992. cg.g_copyshortstring(current_asmdata.CurrAsmList,hp.left.location.reference,href,
  993. Tstringdef(hp.left.resultdef).len)
  994. else
  995. cg.g_concatcopy(current_asmdata.CurrAsmList,hp.left.location.reference,href,elesize);
  996. end;
  997. else
  998. begin
  999. {$ifndef cpu64bit}
  1000. if hp.left.location.size in [OS_64,OS_S64] then
  1001. cg64.a_load64_loc_ref(current_asmdata.CurrAsmList,hp.left.location,href)
  1002. else
  1003. {$endif cpu64bit}
  1004. cg.a_load_loc_ref(current_asmdata.CurrAsmList,hp.left.location.size,hp.left.location,href);
  1005. end;
  1006. end;
  1007. inc(href.offset,elesize);
  1008. end;
  1009. if freetemp then
  1010. location_freetemp(current_asmdata.CurrAsmList,hp.left.location);
  1011. end;
  1012. { load next entry }
  1013. hp:=tarrayconstructornode(hp.right);
  1014. end;
  1015. end;
  1016. {*****************************************************************************
  1017. SecondRTTI
  1018. *****************************************************************************}
  1019. procedure tcgrttinode.pass_generate_code;
  1020. begin
  1021. location_reset(location,LOC_CREFERENCE,OS_NO);
  1022. case rttidatatype of
  1023. rdt_normal:
  1024. location.reference.symbol:=RTTIWriter.get_rtti_label(rttidef,rttitype);
  1025. rdt_ord2str:
  1026. location.reference.symbol:=RTTIWriter.get_rtti_label_ord2str(rttidef,rttitype);
  1027. rdt_str2ord:
  1028. location.reference.symbol:=RTTIWriter.get_rtti_label_str2ord(rttidef,rttitype);
  1029. end;
  1030. end;
  1031. begin
  1032. cloadnode:=tcgloadnode;
  1033. cassignmentnode:=tcgassignmentnode;
  1034. carrayconstructornode:=tcgarrayconstructornode;
  1035. crttinode:=tcgrttinode;
  1036. end.