ncgcon.pas 25 KB

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