ncgbas.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  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,
  57. cgbase,cgobj,
  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. else
  194. internalerror(201001031);
  195. end;
  196. end;
  197. end;
  198. var
  199. hp,hp2 : tai;
  200. i : longint;
  201. begin
  202. location_reset(location,LOC_VOID,OS_NO);
  203. if (nf_get_asm_position in flags) then
  204. begin
  205. { Add a marker, to be sure the list is not empty }
  206. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_Position));
  207. currenttai:=tai(current_asmdata.CurrAsmList.last);
  208. exit;
  209. end;
  210. { Allocate registers used in the assembler block }
  211. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,used_regs_int);
  212. if (po_inline in current_procinfo.procdef.procoptions) then
  213. begin
  214. hp:=tai(p_asm.first);
  215. while assigned(hp) do
  216. begin
  217. hp2:=tai(hp.getcopy);
  218. case hp2.typ of
  219. ait_label :
  220. ReLabel(tasmsymbol(tai_label(hp2).labsym));
  221. ait_const :
  222. begin
  223. if assigned(tai_const(hp2).sym) then
  224. ReLabel(tai_const(hp2).sym);
  225. if assigned(tai_const(hp2).endsym) then
  226. ReLabel(tai_const(hp2).endsym);
  227. end;
  228. ait_instruction :
  229. begin
  230. { remove cached insentry, because the new code can
  231. require an other less optimized instruction }
  232. {$ifdef i386}
  233. {$ifndef NOAG386BIN}
  234. taicpu(hp2).ResetPass1;
  235. {$endif}
  236. {$endif}
  237. { fixup the references }
  238. for i:=1 to taicpu(hp2).ops do
  239. begin
  240. ResolveRef(taicpu(hp2).oper[i-1]^);
  241. with taicpu(hp2).oper[i-1]^ do
  242. begin
  243. case typ of
  244. top_ref :
  245. begin
  246. if assigned(ref^.symbol) then
  247. ReLabel(ref^.symbol);
  248. if assigned(ref^.relsymbol) then
  249. ReLabel(ref^.relsymbol);
  250. end;
  251. end;
  252. end;
  253. end;
  254. {$ifdef x86}
  255. { can only be checked now that all local operands }
  256. { have been resolved }
  257. taicpu(hp2).CheckIfValid;
  258. {$endif x86}
  259. end;
  260. end;
  261. current_asmdata.CurrAsmList.concat(hp2);
  262. hp:=tai(hp.next);
  263. end;
  264. { restore used symbols }
  265. current_asmdata.ResetAltSymbols;
  266. end
  267. else
  268. begin
  269. hp:=tai(p_asm.first);
  270. while assigned(hp) do
  271. begin
  272. case hp.typ of
  273. ait_instruction :
  274. begin
  275. { remove cached insentry, because the new code can
  276. require an other less optimized instruction }
  277. {$ifdef i386}
  278. {$ifndef NOAG386BIN}
  279. taicpu(hp).ResetPass1;
  280. {$endif}
  281. {$endif}
  282. { fixup the references }
  283. for i:=1 to taicpu(hp).ops do
  284. ResolveRef(taicpu(hp).oper[i-1]^);
  285. {$ifdef x86}
  286. { can only be checked now that all local operands }
  287. { have been resolved }
  288. taicpu(hp).CheckIfValid;
  289. {$endif x86}
  290. end;
  291. end;
  292. hp:=tai(hp.next);
  293. end;
  294. { insert the list }
  295. current_asmdata.CurrAsmList.concatlist(p_asm);
  296. end;
  297. { Release register used in the assembler block }
  298. cg.dealloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,used_regs_int);
  299. end;
  300. {*****************************************************************************
  301. TBLOCKNODE
  302. *****************************************************************************}
  303. procedure tcgblocknode.pass_generate_code;
  304. var
  305. hp : tstatementnode;
  306. oldexitlabel : tasmlabel;
  307. oldflowcontrol : tflowcontrol;
  308. begin
  309. location_reset(location,LOC_VOID,OS_NO);
  310. { replace exitlabel? }
  311. if nf_block_with_exit in flags then
  312. begin
  313. oldexitlabel:=current_procinfo.CurrExitLabel;
  314. current_asmdata.getjumplabel(current_procinfo.CurrExitLabel);
  315. oldflowcontrol:=flowcontrol;
  316. { the nested block will not span an exit statement of the parent }
  317. exclude(flowcontrol,fc_exit);
  318. end;
  319. { do second pass on left node }
  320. if assigned(left) then
  321. begin
  322. hp:=tstatementnode(left);
  323. while assigned(hp) do
  324. begin
  325. if assigned(hp.left) then
  326. begin
  327. secondpass(hp.left);
  328. location_copy(hp.location,hp.left.location);
  329. end;
  330. location_copy(location,hp.location);
  331. hp:=tstatementnode(hp.right);
  332. end;
  333. end;
  334. { write exitlabel }
  335. if nf_block_with_exit in flags then
  336. begin
  337. cg.a_label(current_asmdata.CurrAsmList,current_procinfo.CurrExitLabel);
  338. current_procinfo.CurrExitLabel:=oldexitlabel;
  339. { the exit statements inside this block are not exit statements }
  340. { out of the parent }
  341. flowcontrol:=oldflowcontrol+(flowcontrol - [fc_exit]);
  342. end;
  343. end;
  344. {*****************************************************************************
  345. TTEMPCREATENODE
  346. *****************************************************************************}
  347. procedure tcgtempcreatenode.pass_generate_code;
  348. begin
  349. location_reset(location,LOC_VOID,OS_NO);
  350. { if we're secondpassing the same tcgtempcreatenode twice, we have a bug }
  351. if (ti_valid in tempinfo^.flags) then
  352. internalerror(200108222);
  353. { get a (persistent) temp }
  354. if (tempinfo^.typedef.needs_inittable) and
  355. not is_class(tempinfo^.typedef) then
  356. begin
  357. location_reset_ref(tempinfo^.location,LOC_REFERENCE,def_cgsize(tempinfo^.typedef),0);
  358. tg.GetTempTyped(current_asmdata.CurrAsmList,tempinfo^.typedef,tempinfo^.temptype,tempinfo^.location.reference);
  359. { the temp could have been used previously either because the memory location was reused or
  360. because we're in a loop }
  361. cg.g_finalize(current_asmdata.CurrAsmList,tempinfo^.typedef,tempinfo^.location.reference);
  362. end
  363. else if (ti_may_be_in_reg in tempinfo^.flags) then
  364. begin
  365. if tempinfo^.typedef.typ=floatdef then
  366. begin
  367. if use_vectorfpu(tempinfo^.typedef) then
  368. begin
  369. if (tempinfo^.temptype = tt_persistent) then
  370. location_reset(tempinfo^.location,LOC_CMMREGISTER,def_cgsize(tempinfo^.typedef))
  371. else
  372. location_reset(tempinfo^.location,LOC_MMREGISTER,def_cgsize(tempinfo^.typedef));
  373. tempinfo^.location.register:=cg.getmmregister(current_asmdata.CurrAsmList,tempinfo^.location.size);
  374. end
  375. else
  376. begin
  377. if (tempinfo^.temptype = tt_persistent) then
  378. location_reset(tempinfo^.location,LOC_CFPUREGISTER,def_cgsize(tempinfo^.typedef))
  379. else
  380. location_reset(tempinfo^.location,LOC_FPUREGISTER,def_cgsize(tempinfo^.typedef));
  381. tempinfo^.location.register:=cg.getfpuregister(current_asmdata.CurrAsmList,tempinfo^.location.size);
  382. end;
  383. end
  384. else
  385. begin
  386. if (tempinfo^.temptype = tt_persistent) then
  387. location_reset(tempinfo^.location,LOC_CREGISTER,def_cgsize(tempinfo^.typedef))
  388. else
  389. location_reset(tempinfo^.location,LOC_REGISTER,def_cgsize(tempinfo^.typedef));
  390. {$ifndef cpu64bitalu}
  391. if tempinfo^.location.size in [OS_64,OS_S64] then
  392. begin
  393. tempinfo^.location.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  394. tempinfo^.location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  395. end
  396. else
  397. {$endif not cpu64bitalu}
  398. tempinfo^.location.register:=cg.getintregister(current_asmdata.CurrAsmList,tempinfo^.location.size);
  399. end;
  400. end
  401. else
  402. begin
  403. location_reset_ref(tempinfo^.location,LOC_REFERENCE,def_cgsize(tempinfo^.typedef),0);
  404. tg.GetTemp(current_asmdata.CurrAsmList,size,tempinfo^.typedef.alignment,tempinfo^.temptype,tempinfo^.location.reference);
  405. end;
  406. include(tempinfo^.flags,ti_valid);
  407. if assigned(tempinfo^.tempinitcode) then
  408. include(tempinfo^.flags,ti_executeinitialisation);
  409. end;
  410. {*****************************************************************************
  411. TTEMPREFNODE
  412. *****************************************************************************}
  413. procedure tcgtemprefnode.pass_generate_code;
  414. begin
  415. if ti_executeinitialisation in tempinfo^.flags then
  416. begin
  417. { avoid recursion }
  418. exclude(tempinfo^.flags, ti_executeinitialisation);
  419. secondpass(tempinfo^.tempinitcode);
  420. end;
  421. { check if the temp is valid }
  422. if not(ti_valid in tempinfo^.flags) then
  423. internalerror(200108231);
  424. location:=tempinfo^.location;
  425. case tempinfo^.location.loc of
  426. LOC_REFERENCE:
  427. begin
  428. inc(location.reference.offset,offset);
  429. location.reference.alignment:=newalignment(location.reference.alignment,offset);
  430. { ti_valid should be excluded if it's a normal temp }
  431. end;
  432. LOC_REGISTER,
  433. LOC_FPUREGISTER,
  434. LOC_MMREGISTER :
  435. exclude(tempinfo^.flags,ti_valid);
  436. end;
  437. end;
  438. procedure tcgtemprefnode.changelocation(const ref: treference);
  439. begin
  440. { check if the temp is valid }
  441. if not(ti_valid in tempinfo^.flags) then
  442. internalerror(200306081);
  443. if (tempinfo^.location.loc<>LOC_REFERENCE) then
  444. internalerror(2004020203);
  445. if (tempinfo^.temptype = tt_persistent) then
  446. tg.ChangeTempType(current_asmdata.CurrAsmList,tempinfo^.location.reference,tt_normal);
  447. tg.ungettemp(current_asmdata.CurrAsmList,tempinfo^.location.reference);
  448. tempinfo^.location.reference := ref;
  449. tg.ChangeTempType(current_asmdata.CurrAsmList,tempinfo^.location.reference,tempinfo^.temptype);
  450. { adapt location }
  451. location.reference := ref;
  452. inc(location.reference.offset,offset);
  453. location.reference.alignment:=newalignment(location.reference.alignment,offset);
  454. end;
  455. {*****************************************************************************
  456. TTEMPDELETENODE
  457. *****************************************************************************}
  458. procedure tcgtempdeletenode.pass_generate_code;
  459. begin
  460. location_reset(location,LOC_VOID,OS_NO);
  461. case tempinfo^.location.loc of
  462. LOC_REFERENCE:
  463. begin
  464. if release_to_normal then
  465. tg.ChangeTempType(current_asmdata.CurrAsmList,tempinfo^.location.reference,tt_normal)
  466. else
  467. begin
  468. tg.UnGetTemp(current_asmdata.CurrAsmList,tempinfo^.location.reference);
  469. exclude(tempinfo^.flags,ti_valid);
  470. end;
  471. end;
  472. LOC_CREGISTER,
  473. LOC_REGISTER:
  474. begin
  475. if not(cs_opt_regvar in current_settings.optimizerswitches) or
  476. (pi_has_goto in current_procinfo.flags) then
  477. begin
  478. { make sure the register allocator doesn't reuse the }
  479. { register e.g. in the middle of a loop }
  480. {$ifndef cpu64bitalu}
  481. if tempinfo^.location.size in [OS_64,OS_S64] then
  482. begin
  483. cg.a_reg_sync(current_asmdata.CurrAsmList,tempinfo^.location.register64.reghi);
  484. cg.a_reg_sync(current_asmdata.CurrAsmList,tempinfo^.location.register64.reglo);
  485. end
  486. else
  487. {$endif not cpu64bitalu}
  488. cg.a_reg_sync(current_asmdata.CurrAsmList,tempinfo^.location.register);
  489. end;
  490. if release_to_normal then
  491. tempinfo^.location.loc := LOC_REGISTER
  492. else
  493. exclude(tempinfo^.flags,ti_valid);
  494. end;
  495. LOC_CFPUREGISTER,
  496. LOC_FPUREGISTER:
  497. begin
  498. if not(cs_opt_regvar in current_settings.optimizerswitches) or
  499. (pi_has_goto in current_procinfo.flags) then
  500. begin
  501. { make sure the register allocator doesn't reuse the }
  502. { register e.g. in the middle of a loop }
  503. cg.a_reg_sync(current_asmdata.CurrAsmList,tempinfo^.location.register);
  504. end;
  505. if release_to_normal then
  506. tempinfo^.location.loc := LOC_FPUREGISTER
  507. else
  508. exclude(tempinfo^.flags,ti_valid);
  509. end;
  510. LOC_CMMREGISTER,
  511. LOC_MMREGISTER:
  512. begin
  513. if not(cs_opt_regvar in current_settings.optimizerswitches) or
  514. (pi_has_goto in current_procinfo.flags) then
  515. begin
  516. { make sure the register allocator doesn't reuse the }
  517. { register e.g. in the middle of a loop }
  518. cg.a_reg_sync(current_asmdata.CurrAsmList,tempinfo^.location.register);
  519. end;
  520. if release_to_normal then
  521. tempinfo^.location.loc := LOC_MMREGISTER
  522. else
  523. exclude(tempinfo^.flags,ti_valid);
  524. end;
  525. else
  526. internalerror(200507161);
  527. end;
  528. end;
  529. begin
  530. cnothingnode:=tcgnothingnode;
  531. casmnode:=tcgasmnode;
  532. cstatementnode:=tcgstatementnode;
  533. cblocknode:=tcgblocknode;
  534. ctempcreatenode:=tcgtempcreatenode;
  535. ctemprefnode:=tcgtemprefnode;
  536. ctempdeletenode:=tcgtempdeletenode;
  537. end.