ncgcon.pas 27 KB

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