ncgcon.pas 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. Generate assembler for constant nodes which are the same for
  5. all (most) processors
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. unit ncgcon;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. node,ncon;
  24. type
  25. tcgrealconstnode = class(trealconstnode)
  26. procedure pass_2;override;
  27. end;
  28. tcgordconstnode = class(tordconstnode)
  29. procedure pass_2;override;
  30. end;
  31. tcgpointerconstnode = class(tpointerconstnode)
  32. procedure pass_2;override;
  33. end;
  34. tcgstringconstnode = class(tstringconstnode)
  35. procedure pass_2;override;
  36. end;
  37. tcgsetconstnode = class(tsetconstnode)
  38. procedure pass_2;override;
  39. end;
  40. tcgnilnode = class(tnilnode)
  41. procedure pass_2;override;
  42. end;
  43. tcgguidconstnode = class(tguidconstnode)
  44. procedure pass_2;override;
  45. end;
  46. implementation
  47. uses
  48. globtype,widestr,systems,
  49. verbose,globals,
  50. symconst,symdef,aasmbase,aasmtai,defbase,
  51. cpuinfo,cpubase,
  52. cginfo,cgbase,tgobj,rgobj
  53. {$ifdef delphi}
  54. ,dmisc
  55. {$endif}
  56. ;
  57. {*****************************************************************************
  58. TCGREALCONSTNODE
  59. *****************************************************************************}
  60. procedure tcgrealconstnode.pass_2;
  61. { I suppose the parser/pass_1 must make sure the generated real }
  62. { constants are actually supported by the target processor? (JM) }
  63. const
  64. floattype2ait:array[tfloattype] of taitype=
  65. (ait_real_32bit,ait_real_64bit,ait_real_80bit,ait_comp_64bit,ait_comp_64bit);
  66. var
  67. hp1 : tai;
  68. lastlabel : tasmlabel;
  69. realait : taitype;
  70. begin
  71. location_reset(location,LOC_CREFERENCE,def_cgsize(resulttype.def));
  72. lastlabel:=nil;
  73. realait:=floattype2ait[tfloatdef(resulttype.def).typ];
  74. { const already used ? }
  75. if not assigned(lab_real) then
  76. begin
  77. { tries to find an old entry }
  78. hp1:=tai(Consts.first);
  79. while assigned(hp1) do
  80. begin
  81. if hp1.typ=ait_label then
  82. lastlabel:=tai_label(hp1).l
  83. else
  84. begin
  85. if (hp1.typ=realait) and (lastlabel<>nil) then
  86. begin
  87. if(
  88. ((realait=ait_real_32bit) and (tai_real_32bit(hp1).value=value_real)) or
  89. ((realait=ait_real_64bit) and (tai_real_64bit(hp1).value=value_real)) or
  90. ((realait=ait_real_80bit) and (tai_real_80bit(hp1).value=value_real)) or
  91. ((realait=ait_comp_64bit) and (tai_comp_64bit(hp1).value=value_real))
  92. ) then
  93. begin
  94. { found! }
  95. lab_real:=lastlabel;
  96. break;
  97. end;
  98. end;
  99. lastlabel:=nil;
  100. end;
  101. hp1:=tai(hp1.next);
  102. end;
  103. { :-(, we must generate a new entry }
  104. if not assigned(lab_real) then
  105. begin
  106. objectlibrary.getdatalabel(lastlabel);
  107. lab_real:=lastlabel;
  108. if (cs_create_smart in aktmoduleswitches) then
  109. Consts.concat(Tai_cut.Create);
  110. Consts.concat(Tai_label.Create(lastlabel));
  111. case realait of
  112. ait_real_32bit :
  113. Consts.concat(Tai_real_32bit.Create(value_real));
  114. ait_real_64bit :
  115. Consts.concat(Tai_real_64bit.Create(value_real));
  116. ait_real_80bit :
  117. Consts.concat(Tai_real_80bit.Create(value_real));
  118. ait_comp_64bit :
  119. Consts.concat(Tai_comp_64bit.Create(value_real));
  120. else
  121. internalerror(10120);
  122. end;
  123. end;
  124. end;
  125. location.reference.symbol:=lab_real;
  126. end;
  127. {*****************************************************************************
  128. TCGORDCONSTNODE
  129. *****************************************************************************}
  130. procedure tcgordconstnode.pass_2;
  131. begin
  132. location_reset(location,LOC_CONSTANT,def_cgsize(resulttype.def));
  133. location.valueqword:=TConstExprUInt(value);
  134. end;
  135. {*****************************************************************************
  136. TCGPOINTERCONSTNODE
  137. *****************************************************************************}
  138. procedure tcgpointerconstnode.pass_2;
  139. begin
  140. { an integer const. behaves as a memory reference }
  141. location_reset(location,LOC_CONSTANT,OS_ADDR);
  142. location.value:=AWord(value);
  143. end;
  144. {*****************************************************************************
  145. TCGSTRINGCONSTNODE
  146. *****************************************************************************}
  147. procedure tcgstringconstnode.pass_2;
  148. var
  149. hp1,hp2 : tai;
  150. l1,l2,
  151. lastlabel : tasmlabel;
  152. lastlabelhp : tai;
  153. pc : pchar;
  154. same_string : boolean;
  155. l,j,
  156. i,mylength : longint;
  157. begin
  158. { for empty ansistrings we could return a constant 0 }
  159. if (st_type in [st_ansistring,st_widestring]) and
  160. (len=0) then
  161. begin
  162. location_reset(location,LOC_CONSTANT,OS_ADDR);
  163. location.value:=0;
  164. exit;
  165. end;
  166. { return a constant reference in memory }
  167. location_reset(location,LOC_CREFERENCE,def_cgsize(resulttype.def));
  168. { const already used ? }
  169. lastlabel:=nil;
  170. lastlabelhp:=nil;
  171. if not assigned(lab_str) then
  172. begin
  173. if is_shortstring(resulttype.def) then
  174. mylength:=len+2
  175. else
  176. mylength:=len+1;
  177. { widestrings can't be reused yet }
  178. if not(is_widestring(resulttype.def)) then
  179. begin
  180. { tries to found an old entry }
  181. hp1:=tai(Consts.first);
  182. while assigned(hp1) do
  183. begin
  184. if hp1.typ=ait_label then
  185. begin
  186. lastlabel:=tai_label(hp1).l;
  187. lastlabelhp:=hp1;
  188. end
  189. else
  190. begin
  191. { when changing that code, be careful that }
  192. { you don't use typed consts, which are }
  193. { are also written to consts }
  194. { currently, this is no problem, because }
  195. { typed consts have no leading length or }
  196. { they have no trailing zero }
  197. if (hp1.typ=ait_string) and (lastlabel<>nil) and
  198. (tai_string(hp1).len=mylength) then
  199. begin
  200. same_string:=true;
  201. { if shortstring then check the length byte first and
  202. set the start index to 1 }
  203. case st_type of
  204. st_shortstring:
  205. begin
  206. if len=ord(tai_string(hp1).str[0]) then
  207. j:=1
  208. else
  209. same_string:=false;
  210. end;
  211. st_ansistring,
  212. st_widestring :
  213. begin
  214. { before the string the following sequence must be found:
  215. <label>
  216. constsymbol <datalabel>
  217. const32 <len>
  218. const32 <len>
  219. const32 -1
  220. we must then return <label> to reuse
  221. }
  222. hp2:=tai(lastlabelhp.previous);
  223. if assigned(hp2) and
  224. (hp2.typ=ait_const_32bit) and
  225. (tai_const(hp2).value=-1) and
  226. assigned(hp2.previous) and
  227. (tai(hp2.previous).typ=ait_const_32bit) and
  228. (tai_const(hp2.previous).value=len) and
  229. assigned(hp2.previous.previous) and
  230. (tai(hp2.previous.previous).typ=ait_const_32bit) and
  231. (tai_const(hp2.previous.previous).value=len) and
  232. assigned(hp2.previous.previous.previous) and
  233. (tai(hp2.previous.previous.previous).typ=ait_const_symbol) and
  234. assigned(hp2.previous.previous.previous.previous) and
  235. (tai(hp2.previous.previous.previous.previous).typ=ait_label) then
  236. begin
  237. lastlabel:=tai_label(hp2.previous.previous.previous.previous).l;
  238. j:=0;
  239. end
  240. else
  241. same_string:=false;
  242. end;
  243. else
  244. same_string:=false;
  245. end;
  246. { don't check if the length byte was already wrong }
  247. if same_string then
  248. begin
  249. for i:=0 to len do
  250. begin
  251. if tai_string(hp1).str[j]<>value_str[i] then
  252. begin
  253. same_string:=false;
  254. break;
  255. end;
  256. inc(j);
  257. end;
  258. end;
  259. { found ? }
  260. if same_string then
  261. begin
  262. lab_str:=lastlabel;
  263. break;
  264. end;
  265. end;
  266. lastlabel:=nil;
  267. end;
  268. hp1:=tai(hp1.next);
  269. end;
  270. end;
  271. { :-(, we must generate a new entry }
  272. if not assigned(lab_str) then
  273. begin
  274. objectlibrary.getdatalabel(lastlabel);
  275. lab_str:=lastlabel;
  276. if (cs_create_smart in aktmoduleswitches) then
  277. Consts.concat(Tai_cut.Create);
  278. Consts.concat(Tai_label.Create(lastlabel));
  279. { generate an ansi string ? }
  280. case st_type of
  281. st_ansistring:
  282. begin
  283. { an empty ansi string is nil! }
  284. if len=0 then
  285. Consts.concat(Tai_const.Create_32bit(0))
  286. else
  287. begin
  288. objectlibrary.getdatalabel(l1);
  289. objectlibrary.getdatalabel(l2);
  290. Consts.concat(Tai_label.Create(l2));
  291. Consts.concat(Tai_const_symbol.Create(l1));
  292. Consts.concat(Tai_const.Create_32bit(len));
  293. Consts.concat(Tai_const.Create_32bit(len));
  294. Consts.concat(Tai_const.Create_32bit(-1));
  295. Consts.concat(Tai_label.Create(l1));
  296. getmem(pc,len+2);
  297. move(value_str^,pc^,len);
  298. pc[len]:=#0;
  299. { to overcome this problem we set the length explicitly }
  300. { with the ending null char }
  301. Consts.concat(Tai_string.Create_length_pchar(pc,len+1));
  302. { return the offset of the real string }
  303. lab_str:=l2;
  304. end;
  305. end;
  306. st_widestring:
  307. begin
  308. { an empty wide string is nil! }
  309. if len=0 then
  310. Consts.concat(Tai_const.Create_32bit(0))
  311. else
  312. begin
  313. objectlibrary.getdatalabel(l1);
  314. objectlibrary.getdatalabel(l2);
  315. Consts.concat(Tai_label.Create(l2));
  316. Consts.concat(Tai_const_symbol.Create(l1));
  317. { we use always UTF-16 coding for constants }
  318. { at least for now }
  319. { Consts.concat(Tai_const.Create_8bit(2)); }
  320. Consts.concat(Tai_const.Create_32bit(len));
  321. Consts.concat(Tai_const.Create_32bit(len));
  322. Consts.concat(Tai_const.Create_32bit(-1));
  323. Consts.concat(Tai_label.Create(l1));
  324. for i:=0 to len-1 do
  325. Consts.concat(Tai_const.Create_16bit(pcompilerwidestring(value_str)^.data[i]));
  326. { return the offset of the real string }
  327. lab_str:=l2;
  328. end;
  329. end;
  330. st_shortstring:
  331. begin
  332. { truncate strings larger than 255 chars }
  333. if len>255 then
  334. l:=255
  335. else
  336. l:=len;
  337. { also length and terminating zero }
  338. getmem(pc,l+3);
  339. move(value_str^,pc[1],l+1);
  340. pc[0]:=chr(l);
  341. { to overcome this problem we set the length explicitly }
  342. { with the ending null char }
  343. pc[l+1]:=#0;
  344. Consts.concat(Tai_string.Create_length_pchar(pc,l+2));
  345. end;
  346. end;
  347. end;
  348. end;
  349. location.reference.symbol:=lab_str;
  350. end;
  351. {*****************************************************************************
  352. TCGSETCONSTNODE
  353. *****************************************************************************}
  354. procedure tcgsetconstnode.pass_2;
  355. var
  356. hp1 : tai;
  357. lastlabel : tasmlabel;
  358. i : longint;
  359. neededtyp : taitype;
  360. type
  361. setbytes=array[0..31] of byte;
  362. Psetbytes=^setbytes;
  363. begin
  364. { small sets are loaded as constants }
  365. if tsetdef(resulttype.def).settype=smallset then
  366. begin
  367. location_reset(location,LOC_CONSTANT,OS_32);
  368. location.value:=PAWord(value_set)^;
  369. exit;
  370. end;
  371. location_reset(location,LOC_CREFERENCE,OS_NO);
  372. neededtyp:=ait_const_8bit;
  373. lastlabel:=nil;
  374. { const already used ? }
  375. if not assigned(lab_set) then
  376. begin
  377. { tries to found an old entry }
  378. hp1:=tai(Consts.first);
  379. while assigned(hp1) do
  380. begin
  381. if hp1.typ=ait_label then
  382. lastlabel:=tai_label(hp1).l
  383. else
  384. begin
  385. if (lastlabel<>nil) and (hp1.typ=neededtyp) then
  386. begin
  387. if (hp1.typ=ait_const_8bit) then
  388. begin
  389. { compare normal set }
  390. i:=0;
  391. while assigned(hp1) and (i<32) do
  392. begin
  393. {$ifdef oldset}
  394. if tai_const(hp1).value<>value_set^[i] then
  395. {$else}
  396. if tai_const(hp1).value<>Psetbytes(value_set)^[i] then
  397. {$endif}
  398. break;
  399. inc(i);
  400. hp1:=tai(hp1.next);
  401. end;
  402. if i=32 then
  403. begin
  404. { found! }
  405. lab_set:=lastlabel;
  406. break;
  407. end;
  408. { leave when the end of consts is reached, so no
  409. hp1.next is done }
  410. if not assigned(hp1) then
  411. break;
  412. end
  413. else
  414. begin
  415. { compare small set }
  416. if plongint(value_set)^=tai_const(hp1).value then
  417. begin
  418. { found! }
  419. lab_set:=lastlabel;
  420. break;
  421. end;
  422. end;
  423. end;
  424. lastlabel:=nil;
  425. end;
  426. hp1:=tai(hp1.next);
  427. end;
  428. { :-(, we must generate a new entry }
  429. if not assigned(lab_set) then
  430. begin
  431. objectlibrary.getdatalabel(lastlabel);
  432. lab_set:=lastlabel;
  433. if (cs_create_smart in aktmoduleswitches) then
  434. Consts.concat(Tai_cut.Create);
  435. Consts.concat(Tai_label.Create(lastlabel));
  436. if tsetdef(resulttype.def).settype=smallset then
  437. begin
  438. move(value_set^,i,sizeof(longint));
  439. Consts.concat(Tai_const.Create_32bit(i));
  440. end
  441. else
  442. begin
  443. for i:=0 to 31 do
  444. Consts.concat(Tai_const.Create_8bit(Psetbytes(value_set)^[i]));
  445. end;
  446. end;
  447. end;
  448. location.reference.symbol:=lab_set;
  449. end;
  450. {*****************************************************************************
  451. TCGNILNODE
  452. *****************************************************************************}
  453. procedure tcgnilnode.pass_2;
  454. begin
  455. location_reset(location,LOC_CONSTANT,OS_ADDR);
  456. location.value:=0;
  457. end;
  458. {*****************************************************************************
  459. TCGPOINTERCONSTNODE
  460. *****************************************************************************}
  461. procedure tcgguidconstnode.pass_2;
  462. var
  463. tmplabel : TAsmLabel;
  464. i : integer;
  465. begin
  466. location_reset(location,LOC_CREFERENCE,OS_NO);
  467. { label for GUID }
  468. objectlibrary.getdatalabel(tmplabel);
  469. consts.concat(Tai_label.Create(tmplabel));
  470. consts.concat(Tai_const.Create_32bit(value.D1));
  471. consts.concat(Tai_const.Create_16bit(value.D2));
  472. consts.concat(Tai_const.Create_16bit(value.D3));
  473. for i:=Low(value.D4) to High(value.D4) do
  474. consts.concat(Tai_const.Create_8bit(value.D4[i]));
  475. location.reference.symbol:=tmplabel;
  476. end;
  477. begin
  478. crealconstnode:=tcgrealconstnode;
  479. cordconstnode:=tcgordconstnode;
  480. cpointerconstnode:=tcgpointerconstnode;
  481. cstringconstnode:=tcgstringconstnode;
  482. csetconstnode:=tcgsetconstnode;
  483. cnilnode:=tcgnilnode;
  484. cguidconstnode:=tcgguidconstnode;
  485. end.
  486. {
  487. $Log$
  488. Revision 1.21 2002-10-06 21:01:50 peter
  489. * use tconstexpruint instead of qword
  490. Revision 1.20 2002/10/05 12:43:25 carl
  491. * fixes for Delphi 6 compilation
  492. (warning : Some features do not work under Delphi)
  493. Revision 1.19 2002/08/18 20:06:23 peter
  494. * inlining is now also allowed in interface
  495. * renamed write/load to ppuwrite/ppuload
  496. * tnode storing in ppu
  497. * nld,ncon,nbas are already updated for storing in ppu
  498. Revision 1.18 2002/08/11 14:32:26 peter
  499. * renamed current_library to objectlibrary
  500. Revision 1.17 2002/08/11 13:24:11 peter
  501. * saving of asmsymbols in ppu supported
  502. * asmsymbollist global is removed and moved into a new class
  503. tasmlibrarydata that will hold the info of a .a file which
  504. corresponds with a single module. Added librarydata to tmodule
  505. to keep the library info stored for the module. In the future the
  506. objectfiles will also be stored to the tasmlibrarydata class
  507. * all getlabel/newasmsymbol and friends are moved to the new class
  508. Revision 1.16 2002/08/10 17:15:06 jonas
  509. * endianess fix
  510. Revision 1.15 2002/07/23 12:34:30 daniel
  511. * Readded old set code. To use it define 'oldset'. Activated by default
  512. for ppc.
  513. Revision 1.14 2002/07/22 11:48:04 daniel
  514. * Sets are now internally sets.
  515. Revision 1.13 2002/07/20 11:57:53 florian
  516. * types.pas renamed to defbase.pas because D6 contains a types
  517. unit so this would conflicts if D6 programms are compiled
  518. + Willamette/SSE2 instructions to assembler added
  519. Revision 1.12 2002/07/01 18:46:22 peter
  520. * internal linker
  521. * reorganized aasm layer
  522. Revision 1.11 2002/07/01 16:23:53 peter
  523. * cg64 patch
  524. * basics for currency
  525. * asnode updates for class and interface (not finished)
  526. Revision 1.10 2002/05/18 13:34:09 peter
  527. * readded missing revisions
  528. Revision 1.9 2002/05/16 19:46:37 carl
  529. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  530. + try to fix temp allocation (still in ifdef)
  531. + generic constructor calls
  532. + start of tassembler / tmodulebase class cleanup
  533. Revision 1.7 2002/04/04 19:05:57 peter
  534. * removed unused units
  535. * use tlocation.size in cg.a_*loc*() routines
  536. Revision 1.6 2002/04/02 17:11:28 peter
  537. * tlocation,treference update
  538. * LOC_CONSTANT added for better constant handling
  539. * secondadd splitted in multiple routines
  540. * location_force_reg added for loading a location to a register
  541. of a specified size
  542. * secondassignment parses now first the right and then the left node
  543. (this is compatible with Kylix). This saves a lot of push/pop especially
  544. with string operations
  545. * adapted some routines to use the new cg methods
  546. Revision 1.5 2002/03/31 20:26:34 jonas
  547. + a_loadfpu_* and a_loadmm_* methods in tcg
  548. * register allocation is now handled by a class and is mostly processor
  549. independent (+rgobj.pas and i386/rgcpu.pas)
  550. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  551. * some small improvements and fixes to the optimizer
  552. * some register allocation fixes
  553. * some fpuvaroffset fixes in the unary minus node
  554. * push/popusedregisters is now called rg.save/restoreusedregisters and
  555. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  556. also better optimizable)
  557. * fixed and optimized register saving/restoring for new/dispose nodes
  558. * LOC_FPU locations now also require their "register" field to be set to
  559. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  560. - list field removed of the tnode class because it's not used currently
  561. and can cause hard-to-find bugs
  562. Revision 1.4 2002/02/26 09:12:39 jonas
  563. * fixed problem when compiling the compiler with Delphi (reported by
  564. "Luc Langlois" <[email protected]>) (lo/hi don't work as in FPC
  565. when used with int64's under Delphi)
  566. }