ncgbas.pas 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. {
  2. Copyright (c) 2000-2002 by Florian Klaempfl
  3. This unit implements some basic nodes
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit ncgbas;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. cpubase,cgutils,
  22. node,nbas;
  23. type
  24. tcgnothingnode = class(tnothingnode)
  25. procedure pass_generate_code;override;
  26. end;
  27. tcgasmnode = class(tasmnode)
  28. procedure pass_generate_code;override;
  29. end;
  30. tcgstatementnode = class(tstatementnode)
  31. procedure pass_generate_code;override;
  32. end;
  33. tcgblocknode = class(tblocknode)
  34. procedure pass_generate_code;override;
  35. end;
  36. tcgtempcreatenode = class(ttempcreatenode)
  37. procedure pass_generate_code;override;
  38. end;
  39. tcgtemprefnode = class(ttemprefnode)
  40. procedure pass_generate_code;override;
  41. { Changes the location of this temp to ref. Useful when assigning }
  42. { another temp to this one. The current location will be freed. }
  43. { Can only be called in pass 2 (since earlier, the temp location }
  44. { isn't known yet) }
  45. procedure changelocation(const ref: treference);
  46. end;
  47. tcgtempdeletenode = class(ttempdeletenode)
  48. procedure pass_generate_code;override;
  49. end;
  50. implementation
  51. uses
  52. globtype,globals,systems,
  53. cutils,verbose,
  54. aasmbase,aasmtai,aasmdata,aasmcpu,
  55. symsym,symconst,symdef,defutil,
  56. nflw,pass_2,ncgutil,
  57. cgbase,cgobj,hlcgobj,
  58. procinfo,
  59. tgobj
  60. ;
  61. {*****************************************************************************
  62. TNOTHING
  63. *****************************************************************************}
  64. procedure tcgnothingnode.pass_generate_code;
  65. begin
  66. location_reset(location,LOC_VOID,OS_NO);
  67. { avoid an abstract rte }
  68. end;
  69. {*****************************************************************************
  70. TSTATEMENTNODE
  71. *****************************************************************************}
  72. procedure tcgstatementnode.pass_generate_code;
  73. var
  74. hp : tstatementnode;
  75. begin
  76. location_reset(location,LOC_VOID,OS_NO);
  77. hp:=self;
  78. while assigned(hp) do
  79. begin
  80. if assigned(hp.left) then
  81. begin
  82. secondpass(hp.left);
  83. { Compiler inserted blocks can return values }
  84. location_copy(hp.location,hp.left.location);
  85. end;
  86. hp:=tstatementnode(hp.right);
  87. end;
  88. end;
  89. {*****************************************************************************
  90. TASMNODE
  91. *****************************************************************************}
  92. procedure tcgasmnode.pass_generate_code;
  93. procedure ReLabel(var p:tasmsymbol);
  94. begin
  95. { Only relabel local tasmlabels }
  96. if (p.bind = AB_LOCAL) and
  97. (p is tasmlabel) then
  98. begin
  99. if not assigned(p.altsymbol) then
  100. current_asmdata.GenerateAltSymbol(p);
  101. p:=p.altsymbol;
  102. p.increfs;
  103. end;
  104. end;
  105. procedure ResolveRef(var op:toper);
  106. var
  107. sym : tabstractnormalvarsym;
  108. {$ifdef x86}
  109. scale : byte;
  110. {$endif x86}
  111. forceref,
  112. getoffset : boolean;
  113. indexreg : tregister;
  114. sofs : longint;
  115. begin
  116. if (op.typ=top_local) then
  117. begin
  118. sofs:=op.localoper^.localsymofs;
  119. indexreg:=op.localoper^.localindexreg;
  120. {$ifdef x86}
  121. scale:=op.localoper^.localscale;
  122. {$endif x86}
  123. getoffset:=op.localoper^.localgetoffset;
  124. forceref:=op.localoper^.localforceref;
  125. sym:=tabstractnormalvarsym(pointer(op.localoper^.localsym));
  126. dispose(op.localoper);
  127. case sym.localloc.loc of
  128. LOC_REFERENCE :
  129. begin
  130. if getoffset then
  131. begin
  132. if indexreg=NR_NO then
  133. begin
  134. op.typ:=top_const;
  135. op.val:=sym.localloc.reference.offset+sofs;
  136. end
  137. else
  138. begin
  139. op.typ:=top_ref;
  140. new(op.ref);
  141. reference_reset_base(op.ref^,indexreg,sym.localloc.reference.offset+sofs,
  142. newalignment(sym.localloc.reference.alignment,sofs));
  143. end;
  144. end
  145. else
  146. begin
  147. op.typ:=top_ref;
  148. new(op.ref);
  149. reference_reset_base(op.ref^,sym.localloc.reference.base,sym.localloc.reference.offset+sofs,
  150. newalignment(sym.localloc.reference.alignment,sofs));
  151. op.ref^.index:=indexreg;
  152. {$ifdef x86}
  153. op.ref^.scalefactor:=scale;
  154. {$endif x86}
  155. end;
  156. end;
  157. LOC_REGISTER :
  158. begin
  159. if getoffset then
  160. Message(asmr_e_invalid_reference_syntax);
  161. { Subscribed access }
  162. if forceref or
  163. (sofs<>0) then
  164. begin
  165. op.typ:=top_ref;
  166. new(op.ref);
  167. { no idea about the actual alignment }
  168. reference_reset_base(op.ref^,sym.localloc.register,sofs,1);
  169. op.ref^.index:=indexreg;
  170. {$ifdef x86}
  171. op.ref^.scalefactor:=scale;
  172. {$endif x86}
  173. end
  174. else
  175. begin
  176. op.typ:=top_reg;
  177. op.reg:=sym.localloc.register;
  178. end;
  179. end;
  180. LOC_MMREGISTER :
  181. begin
  182. if getoffset then
  183. Message(asmr_e_invalid_reference_syntax);
  184. { Subscribed access }
  185. if forceref or (sofs<>0) then
  186. internalerror(201001032)
  187. else
  188. begin
  189. op.typ:=top_reg;
  190. op.reg:=sym.localloc.register;
  191. end;
  192. end;
  193. LOC_INVALID :
  194. begin
  195. { in "assembler; nostackframe;" routines, the
  196. funcret loc is set to LOC_INVALID in case the
  197. result is returned via a complex location
  198. (more than one register, ...) }
  199. if (vo_is_funcret in tabstractvarsym(sym).varoptions) then
  200. Message(asmr_e_complex_function_result_location)
  201. else
  202. internalerror(2012082101);
  203. { recover }
  204. op.typ:=top_reg;
  205. op.reg:=NR_FUNCTION_RETURN_REG;
  206. end;
  207. else
  208. internalerror(201001031);
  209. end;
  210. end;
  211. end;
  212. var
  213. hp,hp2 : tai;
  214. i : longint;
  215. begin
  216. location_reset(location,LOC_VOID,OS_NO);
  217. if (nf_get_asm_position in flags) then
  218. begin
  219. { Add a marker, to be sure the list is not empty }
  220. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_Position));
  221. currenttai:=tai(current_asmdata.CurrAsmList.last);
  222. exit;
  223. end;
  224. { Allocate registers used in the assembler block }
  225. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,used_regs_int);
  226. if (po_inline in current_procinfo.procdef.procoptions) then
  227. begin
  228. hp:=tai(p_asm.first);
  229. while assigned(hp) do
  230. begin
  231. hp2:=tai(hp.getcopy);
  232. case hp2.typ of
  233. ait_label :
  234. ReLabel(tasmsymbol(tai_label(hp2).labsym));
  235. ait_const :
  236. begin
  237. if assigned(tai_const(hp2).sym) then
  238. ReLabel(tai_const(hp2).sym);
  239. if assigned(tai_const(hp2).endsym) then
  240. ReLabel(tai_const(hp2).endsym);
  241. end;
  242. ait_instruction :
  243. begin
  244. { remove cached insentry, because the new code can
  245. require another less optimized instruction }
  246. {$ifdef i386}
  247. {$ifndef NOAG386BIN}
  248. taicpu(hp2).ResetPass1;
  249. {$endif}
  250. {$endif}
  251. { fixup the references }
  252. for i:=1 to taicpu(hp2).ops do
  253. begin
  254. ResolveRef(taicpu(hp2).oper[i-1]^);
  255. with taicpu(hp2).oper[i-1]^ do
  256. begin
  257. case typ of
  258. top_ref :
  259. begin
  260. if assigned(ref^.symbol) then
  261. ReLabel(ref^.symbol);
  262. if assigned(ref^.relsymbol) then
  263. ReLabel(ref^.relsymbol);
  264. end;
  265. end;
  266. end;
  267. end;
  268. {$ifdef x86}
  269. { can only be checked now that all local operands }
  270. { have been resolved }
  271. taicpu(hp2).CheckIfValid;
  272. {$endif x86}
  273. end;
  274. end;
  275. current_asmdata.CurrAsmList.concat(hp2);
  276. hp:=tai(hp.next);
  277. end;
  278. { restore used symbols }
  279. current_asmdata.ResetAltSymbols;
  280. end
  281. else
  282. begin
  283. hp:=tai(p_asm.first);
  284. while assigned(hp) do
  285. begin
  286. case hp.typ of
  287. ait_instruction :
  288. begin
  289. { remove cached insentry, because the new code can
  290. require another less optimized instruction }
  291. {$ifdef i386}
  292. {$ifndef NOAG386BIN}
  293. taicpu(hp).ResetPass1;
  294. {$endif}
  295. {$endif}
  296. { fixup the references }
  297. for i:=1 to taicpu(hp).ops do
  298. ResolveRef(taicpu(hp).oper[i-1]^);
  299. {$ifdef x86}
  300. { can only be checked now that all local operands }
  301. { have been resolved }
  302. taicpu(hp).CheckIfValid;
  303. {$endif x86}
  304. end;
  305. end;
  306. hp:=tai(hp.next);
  307. end;
  308. { insert the list }
  309. current_asmdata.CurrAsmList.concatlist(p_asm);
  310. end;
  311. { Release register used in the assembler block }
  312. cg.dealloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,used_regs_int);
  313. end;
  314. {*****************************************************************************
  315. TBLOCKNODE
  316. *****************************************************************************}
  317. procedure tcgblocknode.pass_generate_code;
  318. var
  319. hp : tstatementnode;
  320. oldexitlabel : tasmlabel;
  321. oldflowcontrol : tflowcontrol;
  322. begin
  323. location_reset(location,LOC_VOID,OS_NO);
  324. { replace exitlabel? }
  325. if nf_block_with_exit in flags then
  326. begin
  327. oldexitlabel:=current_procinfo.CurrExitLabel;
  328. current_asmdata.getjumplabel(current_procinfo.CurrExitLabel);
  329. oldflowcontrol:=flowcontrol;
  330. { the nested block will not span an exit statement of the parent }
  331. exclude(flowcontrol,fc_exit);
  332. end;
  333. { do second pass on left node }
  334. if assigned(left) then
  335. begin
  336. hp:=tstatementnode(left);
  337. while assigned(hp) do
  338. begin
  339. if assigned(hp.left) then
  340. begin
  341. secondpass(hp.left);
  342. location_copy(hp.location,hp.left.location);
  343. end;
  344. location_copy(location,hp.location);
  345. hp:=tstatementnode(hp.right);
  346. end;
  347. end;
  348. { write exitlabel }
  349. if nf_block_with_exit in flags then
  350. begin
  351. cg.a_label(current_asmdata.CurrAsmList,current_procinfo.CurrExitLabel);
  352. current_procinfo.CurrExitLabel:=oldexitlabel;
  353. { the exit statements inside this block are not exit statements }
  354. { out of the parent }
  355. flowcontrol:=oldflowcontrol+(flowcontrol - [fc_exit]);
  356. end;
  357. end;
  358. {*****************************************************************************
  359. TTEMPCREATENODE
  360. *****************************************************************************}
  361. procedure tcgtempcreatenode.pass_generate_code;
  362. begin
  363. location_reset(location,LOC_VOID,OS_NO);
  364. { if we're secondpassing the same tcgtempcreatenode twice, we have a bug }
  365. if (ti_valid in tempinfo^.flags) then
  366. internalerror(200108222);
  367. { in case of ti_reference, the location will be initialised using the
  368. location of the tempinitnode once the first temprefnode is processed }
  369. if not(ti_reference in tempinfo^.flags) then
  370. begin
  371. { get a (persistent) temp }
  372. if is_managed_type(tempinfo^.typedef) then
  373. begin
  374. location_reset_ref(tempinfo^.location,LOC_REFERENCE,def_cgsize(tempinfo^.typedef),0);
  375. tg.gethltemptyped(current_asmdata.CurrAsmList,tempinfo^.typedef,tempinfo^.temptype,tempinfo^.location.reference);
  376. { the temp could have been used previously either because the memory location was reused or
  377. because we're in a loop. In case it's used as a function result, that doesn't matter
  378. because it will be finalized when assigned to. }
  379. if not(ti_nofini in tempinfo^.flags) then
  380. hlcg.g_finalize(current_asmdata.CurrAsmList,tempinfo^.typedef,tempinfo^.location.reference);
  381. end
  382. else if (ti_may_be_in_reg in tempinfo^.flags) then
  383. begin
  384. location_allocate_register(current_asmdata.CurrAsmList,tempinfo^.location,tempinfo^.typedef,tempinfo^.temptype = tt_persistent);
  385. end
  386. else
  387. begin
  388. location_reset_ref(tempinfo^.location,LOC_REFERENCE,def_cgsize(tempinfo^.typedef),0);
  389. tg.gethltemp(current_asmdata.CurrAsmList,tempinfo^.typedef,size,tempinfo^.temptype,tempinfo^.location.reference);
  390. end;
  391. end;
  392. include(tempinfo^.flags,ti_valid);
  393. if assigned(tempinfo^.tempinitcode) then
  394. include(tempinfo^.flags,ti_executeinitialisation);
  395. end;
  396. {*****************************************************************************
  397. TTEMPREFNODE
  398. *****************************************************************************}
  399. procedure tcgtemprefnode.pass_generate_code;
  400. begin
  401. if ti_executeinitialisation in tempinfo^.flags then
  402. begin
  403. { avoid recursion }
  404. exclude(tempinfo^.flags, ti_executeinitialisation);
  405. secondpass(tempinfo^.tempinitcode);
  406. if (ti_reference in tempinfo^.flags) then
  407. begin
  408. case tempinfo^.tempinitcode.location.loc of
  409. LOC_CREGISTER,
  410. LOC_CFPUREGISTER,
  411. LOC_CMMREGISTER,
  412. LOC_CSUBSETREG:
  413. begin
  414. { although it's ok if we need this value multiple times
  415. for reading, it's not in case of writing (because the
  416. register could change due to SSA -> storing to the saved
  417. register afterwards would be wrong). }
  418. if not(ti_readonly in tempinfo^.flags) then
  419. internalerror(2011031407);
  420. end;
  421. { in case reference contains CREGISTERS, that doesn't matter:
  422. we want to write to the location indicated by the current
  423. value of those registers, and we can save those values }
  424. end;
  425. hlcg.g_reference_loc(current_asmdata.CurrAsmList,tempinfo^.typedef,tempinfo^.tempinitcode.location,tempinfo^.location);
  426. end;
  427. end;
  428. { check if the temp is valid }
  429. if not(ti_valid in tempinfo^.flags) then
  430. internalerror(200108231);
  431. location:=tempinfo^.location;
  432. case tempinfo^.location.loc of
  433. LOC_REFERENCE:
  434. begin
  435. inc(location.reference.offset,offset);
  436. location.reference.alignment:=newalignment(location.reference.alignment,offset);
  437. { ti_valid should be excluded if it's a normal temp }
  438. end;
  439. LOC_REGISTER,
  440. LOC_FPUREGISTER,
  441. LOC_MMREGISTER :
  442. exclude(tempinfo^.flags,ti_valid);
  443. end;
  444. end;
  445. procedure tcgtemprefnode.changelocation(const ref: treference);
  446. begin
  447. { check if the temp is valid }
  448. if not(ti_valid in tempinfo^.flags) then
  449. internalerror(200306081);
  450. if (tempinfo^.location.loc<>LOC_REFERENCE) then
  451. internalerror(2004020203);
  452. if (tempinfo^.temptype = tt_persistent) then
  453. tg.ChangeTempType(current_asmdata.CurrAsmList,tempinfo^.location.reference,tt_normal);
  454. tg.ungettemp(current_asmdata.CurrAsmList,tempinfo^.location.reference);
  455. tempinfo^.location.reference := ref;
  456. tg.ChangeTempType(current_asmdata.CurrAsmList,tempinfo^.location.reference,tempinfo^.temptype);
  457. { adapt location }
  458. location.reference := ref;
  459. inc(location.reference.offset,offset);
  460. location.reference.alignment:=newalignment(location.reference.alignment,offset);
  461. end;
  462. {*****************************************************************************
  463. TTEMPDELETENODE
  464. *****************************************************************************}
  465. procedure tcgtempdeletenode.pass_generate_code;
  466. begin
  467. if ti_reference in tempinfo^.flags then
  468. begin
  469. { release_to_normal means that the temp will be freed the next
  470. time it's used. However, reference temps reference some other
  471. location that is not managed by this temp and hence cannot be
  472. freed }
  473. if release_to_normal then
  474. internalerror(2011052205);
  475. { so we only mark this temp location as "no longer valid" when
  476. it's deleted (ttempdeletenodes are also used during getcopy, so
  477. we really do need one) }
  478. exclude(tempinfo^.flags,ti_valid);
  479. exit;
  480. end;
  481. location_reset(location,LOC_VOID,OS_NO);
  482. case tempinfo^.location.loc of
  483. LOC_REFERENCE:
  484. begin
  485. if release_to_normal then
  486. tg.ChangeTempType(current_asmdata.CurrAsmList,tempinfo^.location.reference,tt_normal)
  487. else
  488. begin
  489. tg.UnGetTemp(current_asmdata.CurrAsmList,tempinfo^.location.reference);
  490. exclude(tempinfo^.flags,ti_valid);
  491. end;
  492. end;
  493. LOC_CREGISTER,
  494. LOC_REGISTER:
  495. begin
  496. if not(cs_opt_regvar in current_settings.optimizerswitches) or
  497. (pi_has_label in current_procinfo.flags) then
  498. begin
  499. { make sure the register allocator doesn't reuse the }
  500. { register e.g. in the middle of a loop }
  501. {$ifndef cpu64bitalu}
  502. if tempinfo^.location.size in [OS_64,OS_S64] then
  503. begin
  504. cg.a_reg_sync(current_asmdata.CurrAsmList,tempinfo^.location.register64.reghi);
  505. cg.a_reg_sync(current_asmdata.CurrAsmList,tempinfo^.location.register64.reglo);
  506. end
  507. else
  508. {$endif not cpu64bitalu}
  509. cg.a_reg_sync(current_asmdata.CurrAsmList,tempinfo^.location.register);
  510. end;
  511. if release_to_normal then
  512. tempinfo^.location.loc := LOC_REGISTER
  513. else
  514. exclude(tempinfo^.flags,ti_valid);
  515. end;
  516. LOC_CFPUREGISTER,
  517. LOC_FPUREGISTER:
  518. begin
  519. if not(cs_opt_regvar in current_settings.optimizerswitches) or
  520. (pi_has_label in current_procinfo.flags) then
  521. begin
  522. { make sure the register allocator doesn't reuse the }
  523. { register e.g. in the middle of a loop }
  524. cg.a_reg_sync(current_asmdata.CurrAsmList,tempinfo^.location.register);
  525. end;
  526. if release_to_normal then
  527. tempinfo^.location.loc := LOC_FPUREGISTER
  528. else
  529. exclude(tempinfo^.flags,ti_valid);
  530. end;
  531. LOC_CMMREGISTER,
  532. LOC_MMREGISTER:
  533. begin
  534. if not(cs_opt_regvar in current_settings.optimizerswitches) or
  535. (pi_has_label in current_procinfo.flags) then
  536. begin
  537. { make sure the register allocator doesn't reuse the }
  538. { register e.g. in the middle of a loop }
  539. cg.a_reg_sync(current_asmdata.CurrAsmList,tempinfo^.location.register);
  540. end;
  541. if release_to_normal then
  542. tempinfo^.location.loc := LOC_MMREGISTER
  543. else
  544. exclude(tempinfo^.flags,ti_valid);
  545. end;
  546. else
  547. internalerror(200507161);
  548. end;
  549. end;
  550. begin
  551. cnothingnode:=tcgnothingnode;
  552. casmnode:=tcgasmnode;
  553. cstatementnode:=tcgstatementnode;
  554. cblocknode:=tcgblocknode;
  555. ctempcreatenode:=tcgtempcreatenode;
  556. ctemprefnode:=tcgtemprefnode;
  557. ctempdeletenode:=tcgtempdeletenode;
  558. end.