ncgbas.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. {
  2. $Id$
  3. Copyright (c) 2000-2002 by Florian Klaempfl
  4. This unit implements some basic nodes
  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 ncgbas;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. cpubase,cgutils,
  23. node,nbas;
  24. type
  25. tcgnothingnode = class(tnothingnode)
  26. procedure pass_2;override;
  27. end;
  28. tcgasmnode = class(tasmnode)
  29. procedure pass_2;override;
  30. end;
  31. tcgstatementnode = class(tstatementnode)
  32. procedure pass_2;override;
  33. end;
  34. tcgblocknode = class(tblocknode)
  35. procedure pass_2;override;
  36. end;
  37. tcgtempcreatenode = class(ttempcreatenode)
  38. procedure pass_2;override;
  39. end;
  40. tcgtemprefnode = class(ttemprefnode)
  41. procedure pass_2;override;
  42. { Changes the location of this temp to ref. Useful when assigning }
  43. { another temp to this one. The current location will be freed. }
  44. { Can only be called in pass 2 (since earlier, the temp location }
  45. { isn't known yet) }
  46. procedure changelocation(const ref: treference);
  47. end;
  48. tcgtempdeletenode = class(ttempdeletenode)
  49. procedure pass_2;override;
  50. end;
  51. implementation
  52. uses
  53. globtype,systems,
  54. cutils,verbose,
  55. aasmbase,aasmtai,aasmcpu,symsym,symconst,
  56. defutil,
  57. nflw,pass_2,
  58. cgbase,cgobj,
  59. procinfo,
  60. tgobj
  61. ;
  62. {*****************************************************************************
  63. TNOTHING
  64. *****************************************************************************}
  65. procedure tcgnothingnode.pass_2;
  66. begin
  67. location_reset(location,LOC_VOID,OS_NO);
  68. { avoid an abstract rte }
  69. end;
  70. {*****************************************************************************
  71. TSTATEMENTNODE
  72. *****************************************************************************}
  73. procedure tcgstatementnode.pass_2;
  74. var
  75. hp : tstatementnode;
  76. begin
  77. location_reset(location,LOC_VOID,OS_NO);
  78. hp:=self;
  79. while assigned(hp) do
  80. begin
  81. if assigned(hp.left) then
  82. begin
  83. secondpass(hp.left);
  84. { Compiler inserted blocks can return values }
  85. location_copy(hp.location,hp.left.location);
  86. end;
  87. hp:=tstatementnode(hp.right);
  88. end;
  89. end;
  90. {*****************************************************************************
  91. TASMNODE
  92. *****************************************************************************}
  93. procedure tcgasmnode.pass_2;
  94. procedure ReLabel(var p:tasmsymbol);
  95. begin
  96. { Only relabel local tasmlabels }
  97. if (p.defbind = AB_LOCAL) and
  98. (p is tasmlabel) then
  99. begin
  100. if not assigned(p.altsymbol) then
  101. objectlibrary.GenerateAltSymbol(p);
  102. p:=p.altsymbol;
  103. p.increfs;
  104. end;
  105. end;
  106. procedure ResolveRef(var op:toper);
  107. var
  108. sym : tabstractnormalvarsym;
  109. {$ifdef x86}
  110. scale : byte;
  111. {$endif x86}
  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. sym:=tabstractnormalvarsym(pointer(op.localoper^.localsym));
  125. dispose(op.localoper);
  126. case sym.localloc.loc of
  127. LOC_REFERENCE :
  128. begin
  129. if getoffset then
  130. begin
  131. if indexreg=NR_NO then
  132. begin
  133. op.typ:=top_const;
  134. op.val:=sym.localloc.reference.offset+sofs;
  135. end
  136. else
  137. begin
  138. op.typ:=top_ref;
  139. new(op.ref);
  140. reference_reset_base(op.ref^,indexreg,sym.localloc.reference.offset+sofs);
  141. end;
  142. end
  143. else
  144. begin
  145. op.typ:=top_ref;
  146. new(op.ref);
  147. reference_reset_base(op.ref^,sym.localloc.reference.base,sym.localloc.reference.offset+sofs);
  148. op.ref^.index:=indexreg;
  149. {$ifdef x86}
  150. op.ref^.scalefactor:=scale;
  151. {$endif x86}
  152. end;
  153. end;
  154. LOC_REGISTER :
  155. begin
  156. if getoffset then
  157. Message(asmr_e_invalid_reference_syntax);
  158. { Subscribed access }
  159. if sofs<>0 then
  160. begin
  161. op.typ:=top_ref;
  162. new(op.ref);
  163. reference_reset_base(op.ref^,sym.localloc.register,sofs);
  164. end
  165. else
  166. begin
  167. op.typ:=top_reg;
  168. op.reg:=sym.localloc.register;
  169. end;
  170. end;
  171. end;
  172. end;
  173. end;
  174. var
  175. hp,hp2 : tai;
  176. i : longint;
  177. skipnode : boolean;
  178. begin
  179. location_reset(location,LOC_VOID,OS_NO);
  180. if (nf_get_asm_position in flags) then
  181. begin
  182. { Add a marker, to be sure the list is not empty }
  183. exprasmlist.concat(tai_marker.create(marker_position));
  184. currenttai:=tai(exprasmlist.last);
  185. exit;
  186. end;
  187. { Allocate registers used in the assembler block }
  188. cg.alloccpuregisters(exprasmlist,R_INTREGISTER,used_regs_int);
  189. if (current_procinfo.procdef.proccalloption=pocall_inline) then
  190. begin
  191. objectlibrary.CreateUsedAsmSymbolList;
  192. hp:=tai(p_asm.first);
  193. while assigned(hp) do
  194. begin
  195. hp2:=tai(hp.getcopy);
  196. skipnode:=false;
  197. case hp2.typ of
  198. ait_label :
  199. ReLabel(tasmsymbol(tai_label(hp2).l));
  200. ait_const_64bit,
  201. ait_const_32bit,
  202. ait_const_16bit,
  203. ait_const_8bit,
  204. ait_const_rva_symbol,
  205. ait_const_indirect_symbol :
  206. begin
  207. if assigned(tai_const(hp2).sym) then
  208. ReLabel(tai_const(hp2).sym);
  209. if assigned(tai_const(hp2).endsym) then
  210. ReLabel(tai_const(hp2).endsym);
  211. end;
  212. ait_instruction :
  213. begin
  214. { remove cached insentry, because the new code can
  215. require an other less optimized instruction }
  216. {$ifdef i386}
  217. {$ifndef NOAG386BIN}
  218. taicpu(hp2).ResetPass1;
  219. {$endif}
  220. {$endif}
  221. { fixup the references }
  222. for i:=1 to taicpu(hp2).ops do
  223. begin
  224. ResolveRef(taicpu(hp2).oper[i-1]^);
  225. with taicpu(hp2).oper[i-1]^ do
  226. begin
  227. case typ of
  228. top_ref :
  229. begin
  230. if assigned(ref^.symbol) then
  231. ReLabel(ref^.symbol);
  232. if assigned(ref^.relsymbol) then
  233. ReLabel(ref^.relsymbol);
  234. end;
  235. end;
  236. end;
  237. end;
  238. end;
  239. ait_marker :
  240. begin
  241. { it's not an assembler block anymore }
  242. if (tai_marker(hp2).kind in [AsmBlockStart, AsmBlockEnd]) then
  243. skipnode:=true;
  244. end;
  245. end;
  246. if not skipnode then
  247. exprasmList.concat(hp2)
  248. else
  249. hp2.free;
  250. hp:=tai(hp.next);
  251. end;
  252. { restore used symbols }
  253. objectlibrary.UsedAsmSymbolListResetAltSym;
  254. objectlibrary.DestroyUsedAsmSymbolList;
  255. end
  256. else
  257. begin
  258. hp:=tai(p_asm.first);
  259. while assigned(hp) do
  260. begin
  261. case hp.typ of
  262. ait_instruction :
  263. begin
  264. { remove cached insentry, because the new code can
  265. require an other less optimized instruction }
  266. {$ifdef i386}
  267. {$ifndef NOAG386BIN}
  268. taicpu(hp).ResetPass1;
  269. {$endif}
  270. {$endif}
  271. { fixup the references }
  272. for i:=1 to taicpu(hp).ops do
  273. ResolveRef(taicpu(hp).oper[i-1]^);
  274. end;
  275. end;
  276. hp:=tai(hp.next);
  277. end;
  278. { insert the list }
  279. exprasmList.concatlist(p_asm);
  280. end;
  281. { Release register used in the assembler block }
  282. cg.dealloccpuregisters(exprasmlist,R_INTREGISTER,used_regs_int);
  283. end;
  284. {*****************************************************************************
  285. TBLOCKNODE
  286. *****************************************************************************}
  287. procedure tcgblocknode.pass_2;
  288. var
  289. hp : tstatementnode;
  290. oldexitlabel : tasmlabel;
  291. begin
  292. location_reset(location,LOC_VOID,OS_NO);
  293. { replace exitlabel? }
  294. if nf_block_with_exit in flags then
  295. begin
  296. oldexitlabel:=current_procinfo.aktexitlabel;
  297. objectlibrary.getlabel(current_procinfo.aktexitlabel);
  298. end;
  299. { do second pass on left node }
  300. if assigned(left) then
  301. begin
  302. hp:=tstatementnode(left);
  303. while assigned(hp) do
  304. begin
  305. if assigned(hp.left) then
  306. begin
  307. secondpass(hp.left);
  308. location_copy(hp.location,hp.left.location);
  309. end;
  310. location_copy(location,hp.location);
  311. hp:=tstatementnode(hp.right);
  312. end;
  313. end;
  314. { write exitlabel }
  315. if nf_block_with_exit in flags then
  316. begin
  317. cg.a_label(exprasmlist,current_procinfo.aktexitlabel);
  318. current_procinfo.aktexitlabel:=oldexitlabel;
  319. end;
  320. end;
  321. {*****************************************************************************
  322. TTEMPCREATENODE
  323. *****************************************************************************}
  324. procedure tcgtempcreatenode.pass_2;
  325. begin
  326. location_reset(location,LOC_VOID,OS_NO);
  327. { if we're secondpassing the same tcgtempcreatenode twice, we have a bug }
  328. if tempinfo^.valid then
  329. internalerror(200108222);
  330. { get a (persistent) temp }
  331. if tempinfo^.restype.def.needs_inittable then
  332. begin
  333. location_reset(tempinfo^.location,LOC_REFERENCE,def_cgsize(tempinfo^.restype.def));
  334. tg.GetTempTyped(exprasmlist,tempinfo^.restype.def,tempinfo^.temptype,tempinfo^.location.reference);
  335. end
  336. else if tempinfo^.may_be_in_reg then
  337. begin
  338. if tempinfo^.restype.def.deftype=floatdef then
  339. begin
  340. if (tempinfo^.temptype = tt_persistent) then
  341. location_reset(tempinfo^.location,LOC_CFPUREGISTER,def_cgsize(tempinfo^.restype.def))
  342. else
  343. location_reset(tempinfo^.location,LOC_FPUREGISTER,def_cgsize(tempinfo^.restype.def));
  344. tempinfo^.location.register:=cg.getfpuregister(exprasmlist,tempinfo^.location.size);
  345. end
  346. else
  347. begin
  348. if (tempinfo^.temptype = tt_persistent) then
  349. location_reset(tempinfo^.location,LOC_CREGISTER,def_cgsize(tempinfo^.restype.def))
  350. else
  351. location_reset(tempinfo^.location,LOC_REGISTER,def_cgsize(tempinfo^.restype.def));
  352. {$ifndef cpu64bit}
  353. if tempinfo^.location.size in [OS_64,OS_S64] then
  354. begin
  355. tempinfo^.location.register64.reglo:=cg.getintregister(exprasmlist,OS_32);
  356. tempinfo^.location.register64.reghi:=cg.getintregister(exprasmlist,OS_32);
  357. end
  358. else
  359. {$endif cpu64bit}
  360. tempinfo^.location.register:=cg.getintregister(exprasmlist,tempinfo^.location.size);
  361. end;
  362. end
  363. else
  364. begin
  365. location_reset(tempinfo^.location,LOC_REFERENCE,def_cgsize(tempinfo^.restype.def));
  366. tg.GetTemp(exprasmlist,size,tempinfo^.temptype,tempinfo^.location.reference);
  367. end;
  368. tempinfo^.valid := true;
  369. end;
  370. {*****************************************************************************
  371. TTEMPREFNODE
  372. *****************************************************************************}
  373. procedure tcgtemprefnode.pass_2;
  374. begin
  375. { check if the temp is valid }
  376. if not tempinfo^.valid then
  377. internalerror(200108231);
  378. location:=tempinfo^.location;
  379. if tempinfo^.location.loc=LOC_REFERENCE then
  380. inc(location.reference.offset,offset);
  381. end;
  382. procedure tcgtemprefnode.changelocation(const ref: treference);
  383. begin
  384. { check if the temp is valid }
  385. if not tempinfo^.valid then
  386. internalerror(200306081);
  387. if (tempinfo^.location.loc<>LOC_REFERENCE) then
  388. internalerror(2004020203);
  389. if (tempinfo^.temptype = tt_persistent) then
  390. tg.ChangeTempType(exprasmlist,tempinfo^.location.reference,tt_normal);
  391. tg.ungettemp(exprasmlist,tempinfo^.location.reference);
  392. tempinfo^.location.reference := ref;
  393. tg.ChangeTempType(exprasmlist,tempinfo^.location.reference,tempinfo^.temptype);
  394. { adapt location }
  395. location.reference := ref;
  396. inc(location.reference.offset,offset);
  397. end;
  398. {*****************************************************************************
  399. TTEMPDELETENODE
  400. *****************************************************************************}
  401. procedure tcgtempdeletenode.pass_2;
  402. begin
  403. location_reset(location,LOC_VOID,OS_NO);
  404. case tempinfo^.location.loc of
  405. LOC_REFERENCE:
  406. begin
  407. if release_to_normal then
  408. tg.ChangeTempType(exprasmlist,tempinfo^.location.reference,tt_normal)
  409. else
  410. tg.UnGetTemp(exprasmlist,tempinfo^.location.reference);
  411. end;
  412. LOC_CREGISTER,
  413. LOC_REGISTER:
  414. begin
  415. { make sure the register allocator doesn't reuse the }
  416. { register e.g. in the middle of a loop }
  417. {$ifndef cpu64bit}
  418. if tempinfo^.location.size in [OS_64,OS_S64] then
  419. begin
  420. cg.a_reg_sync(exprasmlist,tempinfo^.location.register64.reghi);
  421. cg.a_reg_sync(exprasmlist,tempinfo^.location.register64.reglo);
  422. end
  423. else
  424. {$endif cpu64bit}
  425. cg.a_reg_sync(exprasmlist,tempinfo^.location.register);
  426. if release_to_normal then
  427. tempinfo^.location.loc := LOC_REGISTER;
  428. end;
  429. end;
  430. end;
  431. begin
  432. cnothingnode:=tcgnothingnode;
  433. casmnode:=tcgasmnode;
  434. cstatementnode:=tcgstatementnode;
  435. cblocknode:=tcgblocknode;
  436. ctempcreatenode:=tcgtempcreatenode;
  437. ctemprefnode:=tcgtemprefnode;
  438. ctempdeletenode:=tcgtempdeletenode;
  439. end.
  440. {
  441. $Log$
  442. Revision 1.74 2004-12-12 12:56:18 peter
  443. * compile fixes for x86_64
  444. Revision 1.73 2004/12/03 16:04:47 peter
  445. * use tlocation for tempnodes
  446. Revision 1.72 2004/12/02 19:26:15 peter
  447. * disable pass2inline
  448. Revision 1.71 2004/11/11 19:31:33 peter
  449. * fixed compile of powerpc,sparc,arm
  450. Revision 1.70 2004/11/08 22:09:59 peter
  451. * tvarsym splitted
  452. Revision 1.69 2004/10/31 21:45:03 peter
  453. * generic tlocation
  454. * move tlocation to cgutils
  455. Revision 1.68 2004/09/26 17:45:30 peter
  456. * simple regvar support, not yet finished
  457. Revision 1.67 2004/09/25 14:23:54 peter
  458. * ungetregister is now only used for cpuregisters, renamed to
  459. ungetcpuregister
  460. * renamed (get|unget)explicitregister(s) to ..cpuregister
  461. * removed location-release/reference_release
  462. Revision 1.66 2004/09/21 17:25:12 peter
  463. * paraloc branch merged
  464. Revision 1.65.4.1 2004/08/31 20:43:06 peter
  465. * paraloc patch
  466. Revision 1.65 2004/07/16 19:45:15 jonas
  467. + temps can now also hold fpu values in registers (take care with use,
  468. bacause of the x86 fpu stack)
  469. * fpu parameters to node-inlined procedures can now also be put in
  470. a register
  471. Revision 1.64 2004/06/20 08:55:29 florian
  472. * logs truncated
  473. Revision 1.63 2004/06/16 20:07:08 florian
  474. * dwarf branch merged
  475. Revision 1.62 2004/05/23 18:28:41 peter
  476. * methodpointer is loaded into a temp when it was a calln
  477. Revision 1.61 2004/05/23 15:06:20 peter
  478. * implicit_finally flag must be set in pass1
  479. * add check whether the implicit frame is generated when expected
  480. Revision 1.60.2.3 2004/04/27 18:18:25 peter
  481. * aword -> aint
  482. Revision 1.60.2.2 2004/04/12 19:34:45 peter
  483. * basic framework for dwarf CFI
  484. }