ncgcon.pas 25 KB

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