ncgbas.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  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_2;override;
  26. end;
  27. tcgasmnode = class(tasmnode)
  28. procedure pass_2;override;
  29. end;
  30. tcgstatementnode = class(tstatementnode)
  31. procedure pass_2;override;
  32. end;
  33. tcgblocknode = class(tblocknode)
  34. procedure pass_2;override;
  35. end;
  36. tcgtempcreatenode = class(ttempcreatenode)
  37. procedure pass_2;override;
  38. end;
  39. tcgtemprefnode = class(ttemprefnode)
  40. procedure pass_2;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_2;override;
  49. end;
  50. implementation
  51. uses
  52. globtype,systems,
  53. cutils,verbose,
  54. aasmbase,aasmtai,aasmcpu,symsym,symconst,
  55. defutil,
  56. nflw,pass_2,
  57. cgbase,cgobj,
  58. procinfo,
  59. tgobj
  60. ;
  61. {*****************************************************************************
  62. TNOTHING
  63. *****************************************************************************}
  64. procedure tcgnothingnode.pass_2;
  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_2;
  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_2;
  93. procedure ReLabel(var p:tasmsymbol);
  94. begin
  95. { Only relabel local tasmlabels }
  96. if (p.defbind = AB_LOCAL) and
  97. (p is tasmlabel) then
  98. begin
  99. if not assigned(p.altsymbol) then
  100. objectlibrary.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. 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 forceref or
  161. (sofs<>0) then
  162. begin
  163. op.typ:=top_ref;
  164. new(op.ref);
  165. reference_reset_base(op.ref^,sym.localloc.register,sofs);
  166. op.ref^.index:=indexreg;
  167. {$ifdef x86}
  168. op.ref^.scalefactor:=scale;
  169. {$endif x86}
  170. end
  171. else
  172. begin
  173. op.typ:=top_reg;
  174. op.reg:=sym.localloc.register;
  175. end;
  176. end;
  177. end;
  178. end;
  179. end;
  180. var
  181. hp,hp2 : tai;
  182. i : longint;
  183. skipnode : boolean;
  184. begin
  185. location_reset(location,LOC_VOID,OS_NO);
  186. if (nf_get_asm_position in flags) then
  187. begin
  188. { Add a marker, to be sure the list is not empty }
  189. exprasmlist.concat(tai_marker.create(marker_position));
  190. currenttai:=tai(exprasmlist.last);
  191. exit;
  192. end;
  193. { Allocate registers used in the assembler block }
  194. cg.alloccpuregisters(exprasmlist,R_INTREGISTER,used_regs_int);
  195. if (po_inline in current_procinfo.procdef.procoptions) then
  196. begin
  197. objectlibrary.CreateUsedAsmSymbolList;
  198. hp:=tai(p_asm.first);
  199. while assigned(hp) do
  200. begin
  201. hp2:=tai(hp.getcopy);
  202. skipnode:=false;
  203. case hp2.typ of
  204. ait_label :
  205. ReLabel(tasmsymbol(tai_label(hp2).l));
  206. ait_const_64bit,
  207. ait_const_32bit,
  208. ait_const_16bit,
  209. ait_const_8bit,
  210. ait_const_rva_symbol,
  211. ait_const_indirect_symbol :
  212. begin
  213. if assigned(tai_const(hp2).sym) then
  214. ReLabel(tai_const(hp2).sym);
  215. if assigned(tai_const(hp2).endsym) then
  216. ReLabel(tai_const(hp2).endsym);
  217. end;
  218. ait_instruction :
  219. begin
  220. { remove cached insentry, because the new code can
  221. require an other less optimized instruction }
  222. {$ifdef i386}
  223. {$ifndef NOAG386BIN}
  224. taicpu(hp2).ResetPass1;
  225. {$endif}
  226. {$endif}
  227. { fixup the references }
  228. for i:=1 to taicpu(hp2).ops do
  229. begin
  230. ResolveRef(taicpu(hp2).oper[i-1]^);
  231. with taicpu(hp2).oper[i-1]^ do
  232. begin
  233. case typ of
  234. top_ref :
  235. begin
  236. if assigned(ref^.symbol) then
  237. ReLabel(ref^.symbol);
  238. if assigned(ref^.relsymbol) then
  239. ReLabel(ref^.relsymbol);
  240. end;
  241. end;
  242. end;
  243. end;
  244. end;
  245. ait_marker :
  246. begin
  247. { it's not an assembler block anymore }
  248. if (tai_marker(hp2).kind in [AsmBlockStart, AsmBlockEnd]) then
  249. skipnode:=true;
  250. end;
  251. end;
  252. if not skipnode then
  253. exprasmList.concat(hp2)
  254. else
  255. hp2.free;
  256. hp:=tai(hp.next);
  257. end;
  258. { restore used symbols }
  259. objectlibrary.UsedAsmSymbolListResetAltSym;
  260. objectlibrary.DestroyUsedAsmSymbolList;
  261. end
  262. else
  263. begin
  264. hp:=tai(p_asm.first);
  265. while assigned(hp) do
  266. begin
  267. case hp.typ of
  268. ait_instruction :
  269. begin
  270. { remove cached insentry, because the new code can
  271. require an other less optimized instruction }
  272. {$ifdef i386}
  273. {$ifndef NOAG386BIN}
  274. taicpu(hp).ResetPass1;
  275. {$endif}
  276. {$endif}
  277. { fixup the references }
  278. for i:=1 to taicpu(hp).ops do
  279. ResolveRef(taicpu(hp).oper[i-1]^);
  280. end;
  281. end;
  282. hp:=tai(hp.next);
  283. end;
  284. { insert the list }
  285. exprasmList.concatlist(p_asm);
  286. end;
  287. { Release register used in the assembler block }
  288. cg.dealloccpuregisters(exprasmlist,R_INTREGISTER,used_regs_int);
  289. end;
  290. {*****************************************************************************
  291. TBLOCKNODE
  292. *****************************************************************************}
  293. procedure tcgblocknode.pass_2;
  294. var
  295. hp : tstatementnode;
  296. oldexitlabel : tasmlabel;
  297. begin
  298. location_reset(location,LOC_VOID,OS_NO);
  299. { replace exitlabel? }
  300. if nf_block_with_exit in flags then
  301. begin
  302. oldexitlabel:=current_procinfo.aktexitlabel;
  303. objectlibrary.getlabel(current_procinfo.aktexitlabel);
  304. end;
  305. { do second pass on left node }
  306. if assigned(left) then
  307. begin
  308. hp:=tstatementnode(left);
  309. while assigned(hp) do
  310. begin
  311. if assigned(hp.left) then
  312. begin
  313. secondpass(hp.left);
  314. location_copy(hp.location,hp.left.location);
  315. end;
  316. location_copy(location,hp.location);
  317. hp:=tstatementnode(hp.right);
  318. end;
  319. end;
  320. { write exitlabel }
  321. if nf_block_with_exit in flags then
  322. begin
  323. cg.a_label(exprasmlist,current_procinfo.aktexitlabel);
  324. current_procinfo.aktexitlabel:=oldexitlabel;
  325. end;
  326. end;
  327. {*****************************************************************************
  328. TTEMPCREATENODE
  329. *****************************************************************************}
  330. procedure tcgtempcreatenode.pass_2;
  331. begin
  332. location_reset(location,LOC_VOID,OS_NO);
  333. { if we're secondpassing the same tcgtempcreatenode twice, we have a bug }
  334. if tempinfo^.valid then
  335. internalerror(200108222);
  336. { get a (persistent) temp }
  337. if tempinfo^.restype.def.needs_inittable then
  338. begin
  339. location_reset(tempinfo^.location,LOC_REFERENCE,def_cgsize(tempinfo^.restype.def));
  340. tg.GetTempTyped(exprasmlist,tempinfo^.restype.def,tempinfo^.temptype,tempinfo^.location.reference);
  341. end
  342. else if tempinfo^.may_be_in_reg then
  343. begin
  344. if tempinfo^.restype.def.deftype=floatdef then
  345. begin
  346. if (tempinfo^.temptype = tt_persistent) then
  347. location_reset(tempinfo^.location,LOC_CFPUREGISTER,def_cgsize(tempinfo^.restype.def))
  348. else
  349. location_reset(tempinfo^.location,LOC_FPUREGISTER,def_cgsize(tempinfo^.restype.def));
  350. tempinfo^.location.register:=cg.getfpuregister(exprasmlist,tempinfo^.location.size);
  351. end
  352. else
  353. begin
  354. if (tempinfo^.temptype = tt_persistent) then
  355. location_reset(tempinfo^.location,LOC_CREGISTER,def_cgsize(tempinfo^.restype.def))
  356. else
  357. location_reset(tempinfo^.location,LOC_REGISTER,def_cgsize(tempinfo^.restype.def));
  358. {$ifndef cpu64bit}
  359. if tempinfo^.location.size in [OS_64,OS_S64] then
  360. begin
  361. tempinfo^.location.register64.reglo:=cg.getintregister(exprasmlist,OS_32);
  362. tempinfo^.location.register64.reghi:=cg.getintregister(exprasmlist,OS_32);
  363. end
  364. else
  365. {$endif cpu64bit}
  366. tempinfo^.location.register:=cg.getintregister(exprasmlist,tempinfo^.location.size);
  367. end;
  368. end
  369. else
  370. begin
  371. location_reset(tempinfo^.location,LOC_REFERENCE,def_cgsize(tempinfo^.restype.def));
  372. tg.GetTemp(exprasmlist,size,tempinfo^.temptype,tempinfo^.location.reference);
  373. end;
  374. tempinfo^.valid := true;
  375. end;
  376. {*****************************************************************************
  377. TTEMPREFNODE
  378. *****************************************************************************}
  379. procedure tcgtemprefnode.pass_2;
  380. begin
  381. { check if the temp is valid }
  382. if not tempinfo^.valid then
  383. internalerror(200108231);
  384. location:=tempinfo^.location;
  385. if tempinfo^.location.loc=LOC_REFERENCE then
  386. inc(location.reference.offset,offset);
  387. end;
  388. procedure tcgtemprefnode.changelocation(const ref: treference);
  389. begin
  390. { check if the temp is valid }
  391. if not tempinfo^.valid then
  392. internalerror(200306081);
  393. if (tempinfo^.location.loc<>LOC_REFERENCE) then
  394. internalerror(2004020203);
  395. if (tempinfo^.temptype = tt_persistent) then
  396. tg.ChangeTempType(exprasmlist,tempinfo^.location.reference,tt_normal);
  397. tg.ungettemp(exprasmlist,tempinfo^.location.reference);
  398. tempinfo^.location.reference := ref;
  399. tg.ChangeTempType(exprasmlist,tempinfo^.location.reference,tempinfo^.temptype);
  400. { adapt location }
  401. location.reference := ref;
  402. inc(location.reference.offset,offset);
  403. end;
  404. {*****************************************************************************
  405. TTEMPDELETENODE
  406. *****************************************************************************}
  407. procedure tcgtempdeletenode.pass_2;
  408. begin
  409. location_reset(location,LOC_VOID,OS_NO);
  410. case tempinfo^.location.loc of
  411. LOC_REFERENCE:
  412. begin
  413. if release_to_normal then
  414. tg.ChangeTempType(exprasmlist,tempinfo^.location.reference,tt_normal)
  415. else
  416. tg.UnGetTemp(exprasmlist,tempinfo^.location.reference);
  417. end;
  418. LOC_CREGISTER,
  419. LOC_REGISTER:
  420. begin
  421. { make sure the register allocator doesn't reuse the }
  422. { register e.g. in the middle of a loop }
  423. {$ifndef cpu64bit}
  424. if tempinfo^.location.size in [OS_64,OS_S64] then
  425. begin
  426. cg.a_reg_sync(exprasmlist,tempinfo^.location.register64.reghi);
  427. cg.a_reg_sync(exprasmlist,tempinfo^.location.register64.reglo);
  428. end
  429. else
  430. {$endif cpu64bit}
  431. cg.a_reg_sync(exprasmlist,tempinfo^.location.register);
  432. if release_to_normal then
  433. tempinfo^.location.loc := LOC_REGISTER;
  434. end;
  435. LOC_CFPUREGISTER,
  436. LOC_FPUREGISTER:
  437. begin
  438. { make sure the register allocator doesn't reuse the }
  439. { register e.g. in the middle of a loop }
  440. cg.a_reg_sync(exprasmlist,tempinfo^.location.register);
  441. if release_to_normal then
  442. tempinfo^.location.loc := LOC_FPUREGISTER;
  443. end;
  444. else
  445. internalerror(200507161);
  446. end;
  447. end;
  448. begin
  449. cnothingnode:=tcgnothingnode;
  450. casmnode:=tcgasmnode;
  451. cstatementnode:=tcgstatementnode;
  452. cblocknode:=tcgblocknode;
  453. ctempcreatenode:=tcgtempcreatenode;
  454. ctemprefnode:=tcgtemprefnode;
  455. ctempdeletenode:=tcgtempdeletenode;
  456. end.