ncgbas.pas 17 KB

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