ncgmat.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. Generate generic mathematical nodes
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit ncgmat;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. node,nmat,cpubase,cgbase;
  23. type
  24. tcgunaryminusnode = class(tunaryminusnode)
  25. protected
  26. { This routine is called to change the sign of the
  27. floating point value in the floating point
  28. register r.
  29. This routine should be overriden, since
  30. the generic version is not optimal at all. The
  31. generic version assumes that floating
  32. point values are stored in the register
  33. in IEEE-754 format.
  34. }
  35. procedure emit_float_sign_change(r: tregister; _size : tcgsize);virtual;
  36. {$ifdef SUPPORT_MMX}
  37. procedure second_mmx;virtual;abstract;
  38. {$endif SUPPORT_MMX}
  39. {$ifndef cpu64bit}
  40. procedure second_64bit;virtual;
  41. {$endif cpu64bit}
  42. procedure second_integer;virtual;
  43. procedure second_float;virtual;
  44. public
  45. procedure pass_2;override;
  46. end;
  47. tcgmoddivnode = class(tmoddivnode)
  48. procedure pass_2;override;
  49. protected
  50. { This routine must do an actual 32-bit division, be it
  51. signed or unsigned. The result must set into the the
  52. @var(num) register.
  53. @param(signed Indicates if the division must be signed)
  54. @param(denum Register containing the denominator
  55. @param(num Register containing the numerator, will also receive result)
  56. The actual optimizations regarding shifts have already
  57. been done and emitted, so this should really a do a divide.
  58. }
  59. procedure emit_div_reg_reg(signed: boolean;denum,num : tregister);virtual;abstract;
  60. { This routine must do an actual 32-bit modulo, be it
  61. signed or unsigned. The result must set into the the
  62. @var(num) register.
  63. @param(signed Indicates if the modulo must be signed)
  64. @param(denum Register containing the denominator
  65. @param(num Register containing the numerator, will also receive result)
  66. The actual optimizations regarding shifts have already
  67. been done and emitted, so this should really a do a modulo.
  68. }
  69. procedure emit_mod_reg_reg(signed: boolean;denum,num : tregister);virtual;abstract;
  70. {$ifndef cpu64bit}
  71. { This routine must do an actual 64-bit division, be it
  72. signed or unsigned. The result must set into the the
  73. @var(num) register.
  74. @param(signed Indicates if the division must be signed)
  75. @param(denum Register containing the denominator
  76. @param(num Register containing the numerator, will also receive result)
  77. The actual optimizations regarding shifts have already
  78. been done and emitted, so this should really a do a divide.
  79. Currently, this routine should only be implemented on
  80. 64-bit systems, otherwise a helper is called in 1st pass.
  81. }
  82. procedure emit64_div_reg_reg(signed: boolean;denum,num : tregister64);virtual;
  83. {$endif cpu64bit}
  84. end;
  85. tcgshlshrnode = class(tshlshrnode)
  86. {$ifndef cpu64bit}
  87. procedure second_64bit;virtual;
  88. {$endif cpu64bit}
  89. procedure second_integer;virtual;
  90. procedure pass_2;override;
  91. end;
  92. tcgnotnode = class(tnotnode)
  93. protected
  94. procedure second_boolean;virtual;abstract;
  95. {$ifdef SUPPORT_MMX}
  96. procedure second_mmx;virtual;abstract;
  97. {$endif SUPPORT_MMX}
  98. {$ifndef cpu64bit}
  99. procedure second_64bit;virtual;
  100. {$endif cpu64bit}
  101. procedure second_integer;virtual;
  102. public
  103. procedure pass_2;override;
  104. end;
  105. implementation
  106. uses
  107. globtype,systems,
  108. cutils,verbose,globals,
  109. symconst,aasmbase,aasmtai,aasmcpu,defutil,
  110. pass_2,
  111. ncon,
  112. tgobj,ncgutil,cgobj,paramgr
  113. {$ifndef cpu64bit}
  114. ,cg64f32
  115. {$endif cpu64bit}
  116. ;
  117. {*****************************************************************************
  118. TCGUNARYMINUSNODE
  119. *****************************************************************************}
  120. procedure tcgunaryminusnode.emit_float_sign_change(r: tregister; _size : tcgsize);
  121. var
  122. href,
  123. href2 : treference;
  124. begin
  125. { get a temporary memory reference to store the floating
  126. point value
  127. }
  128. tg.gettemp(exprasmlist,tcgsize2size[_size],tt_normal,href);
  129. { store the floating point value in the temporary memory area }
  130. cg.a_loadfpu_reg_ref(exprasmlist,_size,r,href);
  131. { only single and double ieee are supported, for little endian
  132. the signed bit is in the second dword }
  133. href2:=href;
  134. case _size of
  135. OS_F64 :
  136. if target_info.endian = endian_little then
  137. inc(href2.offset,4);
  138. OS_F32 :
  139. ;
  140. else
  141. internalerror(200406021);
  142. end;
  143. { flip sign-bit (bit 31/63) of single/double }
  144. cg.a_op_const_ref(exprasmlist,OP_XOR,OS_32,aint($80000000),href2);
  145. cg.a_loadfpu_ref_reg(exprasmlist,_size,href,r);
  146. tg.ungetiftemp(exprasmlist,href);
  147. end;
  148. {$ifndef cpu64bit}
  149. procedure tcgunaryminusnode.second_64bit;
  150. begin
  151. secondpass(left);
  152. { load left operator in a register }
  153. location_copy(location,left.location);
  154. location_force_reg(exprasmlist,location,OS_64,false);
  155. cg64.a_op64_loc_reg(exprasmlist,OP_NEG,
  156. location,joinreg64(location.registerlow,location.registerhigh));
  157. end;
  158. {$endif cpu64bit}
  159. procedure tcgunaryminusnode.second_float;
  160. begin
  161. secondpass(left);
  162. location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
  163. case left.location.loc of
  164. LOC_REFERENCE,
  165. LOC_CREFERENCE :
  166. begin
  167. reference_release(exprasmlist,left.location.reference);
  168. location.register:=cg.getfpuregister(exprasmlist,location.size);
  169. cg.a_loadfpu_ref_reg(exprasmlist,
  170. def_cgsize(left.resulttype.def),
  171. left.location.reference,location.register);
  172. emit_float_sign_change(location.register,def_cgsize(left.resulttype.def));
  173. end;
  174. LOC_FPUREGISTER:
  175. begin
  176. location.register:=left.location.register;
  177. emit_float_sign_change(location.register,def_cgsize(left.resulttype.def));
  178. end;
  179. LOC_CFPUREGISTER:
  180. begin
  181. location.register:=cg.getfpuregister(exprasmlist,location.size);
  182. cg.a_loadfpu_reg_reg(exprasmlist,left.location.size,left.location.register,location.register);
  183. emit_float_sign_change(location.register,def_cgsize(left.resulttype.def));
  184. end;
  185. else
  186. internalerror(200306021);
  187. end;
  188. end;
  189. procedure tcgunaryminusnode.second_integer;
  190. begin
  191. secondpass(left);
  192. { load left operator in a register }
  193. location_copy(location,left.location);
  194. location_force_reg(exprasmlist,location,OS_INT,false);
  195. cg.a_op_reg_reg(exprasmlist,OP_NEG,OS_INT,location.register,location.register);
  196. end;
  197. procedure tcgunaryminusnode.pass_2;
  198. begin
  199. {$ifndef cpu64bit}
  200. if is_64bit(left.resulttype.def) then
  201. second_64bit
  202. else
  203. {$endif cpu64bit}
  204. {$ifdef SUPPORT_MMX}
  205. if (cs_mmx in aktlocalswitches) and is_mmx_able_array(left.resulttype.def) then
  206. second_mmx
  207. else
  208. {$endif SUPPORT_MMX}
  209. if (left.resulttype.def.deftype=floatdef) then
  210. second_float
  211. else
  212. second_integer;
  213. end;
  214. {*****************************************************************************
  215. TCGMODDIVNODE
  216. *****************************************************************************}
  217. {$ifndef cpu64bit}
  218. procedure tcgmoddivnode.emit64_div_reg_reg(signed: boolean; denum,num:tregister64);
  219. begin
  220. { handled in pass_1 already, unless pass_1 is
  221. overriden
  222. }
  223. { should be handled in pass_1 (JM) }
  224. internalerror(200109052);
  225. end;
  226. {$endif cpu64bit}
  227. procedure tcgmoddivnode.pass_2;
  228. var
  229. hreg1 : tregister;
  230. hdenom : tregister;
  231. power : longint;
  232. hl : tasmlabel;
  233. paraloc1 : tparalocation;
  234. begin
  235. secondpass(left);
  236. if codegenerror then
  237. exit;
  238. secondpass(right);
  239. if codegenerror then
  240. exit;
  241. location_copy(location,left.location);
  242. {$ifndef cpu64bit}
  243. if is_64bit(resulttype.def) then
  244. begin
  245. { this code valid for 64-bit cpu's only ,
  246. otherwise helpers are called in pass_1
  247. }
  248. location_force_reg(exprasmlist,location,OS_64,false);
  249. location_copy(location,left.location);
  250. location_force_reg(exprasmlist,right.location,OS_64,false);
  251. emit64_div_reg_reg(is_signed(left.resulttype.def),
  252. joinreg64(right.location.registerlow,right.location.registerhigh),
  253. joinreg64(location.registerlow,location.registerhigh));
  254. end
  255. else
  256. {$endif cpu64bit}
  257. begin
  258. { put numerator in register }
  259. location_force_reg(exprasmlist,left.location,OS_INT,false);
  260. hreg1:=left.location.register;
  261. if (nodetype=divn) and
  262. (right.nodetype=ordconstn) and
  263. ispowerof2(tordconstnode(right).value,power) then
  264. Begin
  265. { for signed numbers, the numerator must be adjusted before the
  266. shift instruction, but not wih unsigned numbers! Otherwise,
  267. "Cardinal($ffffffff) div 16" overflows! (JM) }
  268. If is_signed(left.resulttype.def) Then
  269. Begin
  270. objectlibrary.getlabel(hl);
  271. cg.a_cmp_const_reg_label(exprasmlist,OS_INT,OC_GT,0,hreg1,hl);
  272. if power=1 then
  273. cg.a_op_const_reg(exprasmlist,OP_ADD,OS_INT,1,hreg1)
  274. else
  275. cg.a_op_const_reg(exprasmlist,OP_ADD,OS_INT,tordconstnode(right).value-1,hreg1);
  276. cg.a_label(exprasmlist,hl);
  277. cg.a_op_const_reg(exprasmlist,OP_SAR,OS_INT,power,hreg1);
  278. End
  279. Else { not signed }
  280. cg.a_op_const_reg(exprasmlist,OP_SHR,OS_INT,power,hreg1);
  281. End
  282. else
  283. begin
  284. { bring denominator to hdenom }
  285. { hdenom is always free, it's }
  286. { only used for temporary }
  287. { purposes }
  288. hdenom := cg.getintregister(exprasmlist,OS_INT);
  289. if right.location.loc<>LOC_CREGISTER then
  290. location_release(exprasmlist,right.location);
  291. cg.a_load_loc_reg(exprasmlist,right.location.size,right.location,hdenom);
  292. { verify if the divisor is zero, if so return an error
  293. immediately
  294. }
  295. objectlibrary.getlabel(hl);
  296. cg.a_cmp_const_reg_label(exprasmlist,OS_INT,OC_NE,0,hdenom,hl);
  297. paraloc1:=paramanager.getintparaloc(pocall_default,1);
  298. paramanager.allocparaloc(exprasmlist,paraloc1);
  299. cg.a_param_const(exprasmlist,OS_S32,200,paraloc1);
  300. paramanager.freeparaloc(exprasmlist,paraloc1);
  301. cg.a_call_name(exprasmlist,'FPC_HANDLERROR');
  302. cg.a_label(exprasmlist,hl);
  303. if nodetype = modn then
  304. emit_mod_reg_reg(is_signed(left.resulttype.def),hdenom,hreg1)
  305. else
  306. emit_div_reg_reg(is_signed(left.resulttype.def),hdenom,hreg1);
  307. end;
  308. location_reset(location,LOC_REGISTER,OS_INT);
  309. location.register:=hreg1;
  310. end;
  311. cg.g_overflowcheck(exprasmlist,location,resulttype.def);
  312. end;
  313. {*****************************************************************************
  314. TCGSHLRSHRNODE
  315. *****************************************************************************}
  316. {$ifndef cpu64bit}
  317. procedure tcgshlshrnode.second_64bit;
  318. begin
  319. { already hanled in 1st pass }
  320. internalerror(2002081501);
  321. end;
  322. {$endif cpu64bit}
  323. procedure tcgshlshrnode.second_integer;
  324. var
  325. freescratch : boolean;
  326. op : topcg;
  327. hcountreg : tregister;
  328. begin
  329. freescratch:=false;
  330. { determine operator }
  331. case nodetype of
  332. shln: op:=OP_SHL;
  333. shrn: op:=OP_SHR;
  334. end;
  335. { load left operators in a register }
  336. location_copy(location,left.location);
  337. location_force_reg(exprasmlist,location,OS_INT,false);
  338. { shifting by a constant directly coded: }
  339. if (right.nodetype=ordconstn) then
  340. begin
  341. { l shl 32 should 0 imho, but neither TP nor Delphi do it in this way (FK)
  342. if right.value<=31 then
  343. }
  344. cg.a_op_const_reg(exprasmlist,op,location.size,
  345. tordconstnode(right).value and 31,location.register);
  346. {
  347. else
  348. emit_reg_reg(A_XOR,S_L,hregister1,
  349. hregister1);
  350. }
  351. end
  352. else
  353. begin
  354. { load right operators in a register - this
  355. is done since most target cpu which will use this
  356. node do not support a shift count in a mem. location (cec)
  357. }
  358. if right.location.loc<>LOC_REGISTER then
  359. begin
  360. hcountreg:=cg.getintregister(exprasmlist,OS_INT);
  361. freescratch := true;
  362. cg.a_load_loc_reg(exprasmlist,right.location.size,right.location,hcountreg);
  363. end
  364. else
  365. hcountreg:=right.location.register;
  366. cg.a_op_reg_reg(exprasmlist,op,OS_INT,hcountreg,location.register);
  367. if right.location.loc<>LOC_REGISTER then
  368. location_release(exprasmlist,right.location);
  369. if freescratch then
  370. cg.ungetregister(exprasmlist,hcountreg);
  371. end;
  372. end;
  373. procedure tcgshlshrnode.pass_2;
  374. begin
  375. secondpass(left);
  376. secondpass(right);
  377. {$ifndef cpu64bit}
  378. if is_64bit(left.resulttype.def) then
  379. second_64bit
  380. else
  381. {$endif cpu64bit}
  382. second_integer;
  383. end;
  384. {*****************************************************************************
  385. TCGNOTNODE
  386. *****************************************************************************}
  387. {$ifndef cpu64bit}
  388. procedure tcgnotnode.second_64bit;
  389. begin
  390. secondpass(left);
  391. location_force_reg(exprasmlist,left.location,def_cgsize(left.resulttype.def),false);
  392. location_copy(location,left.location);
  393. { perform the NOT operation }
  394. cg64.a_op64_reg_reg(exprasmlist,OP_NOT,left.location.register64,location.register64);
  395. end;
  396. {$endif cpu64bit}
  397. procedure tcgnotnode.second_integer;
  398. begin
  399. secondpass(left);
  400. location_force_reg(exprasmlist,left.location,def_cgsize(left.resulttype.def),false);
  401. location_copy(location,left.location);
  402. { perform the NOT operation }
  403. cg.a_op_reg_reg(exprasmlist,OP_NOT,location.size,location.register,location.register);
  404. end;
  405. procedure tcgnotnode.pass_2;
  406. begin
  407. if is_boolean(resulttype.def) then
  408. second_boolean
  409. {$ifdef SUPPORT_MMX}
  410. else if (cs_mmx in aktlocalswitches) and is_mmx_able_array(left.resulttype.def) then
  411. second_mmx
  412. {$endif SUPPORT_MMX}
  413. {$ifndef cpu64bit}
  414. else if is_64bit(left.resulttype.def) then
  415. second_64bit
  416. {$endif cpu64bit}
  417. else
  418. second_integer;
  419. end;
  420. begin
  421. cmoddivnode:=tcgmoddivnode;
  422. cunaryminusnode:=tcgunaryminusnode;
  423. cshlshrnode:=tcgshlshrnode;
  424. cnotnode:=tcgnotnode;
  425. end.
  426. {
  427. $Log$
  428. Revision 1.26 2004-06-16 20:07:08 florian
  429. * dwarf branch merged
  430. Revision 1.25.2.4 2004/06/02 19:04:51 peter
  431. * fixed minusunary for float
  432. Revision 1.25.2.3 2004/05/31 16:39:42 peter
  433. * add ungetiftemp in a few locations
  434. Revision 1.25.2.2 2004/05/30 17:07:07 peter
  435. * fix shl shr for sparc
  436. Revision 1.25.2.1 2004/04/27 18:18:25 peter
  437. * aword -> aint
  438. Revision 1.25 2004/01/23 15:12:49 florian
  439. * fixed generic shl/shr operations
  440. + added register allocation hook calls for arm specific operand types:
  441. register set and shifter op
  442. Revision 1.24 2004/01/20 12:59:37 florian
  443. * common addnode code for x86-64 and i386
  444. Revision 1.23 2003/12/06 01:15:22 florian
  445. * reverted Peter's alloctemp patch; hopefully properly
  446. Revision 1.22 2003/12/03 23:13:20 peter
  447. * delayed paraloc allocation, a_param_*() gets extra parameter
  448. if it needs to allocate temp or real paralocation
  449. * optimized/simplified int-real loading
  450. Revision 1.21 2003/10/10 17:48:13 peter
  451. * old trgobj moved to x86/rgcpu and renamed to trgx86fpu
  452. * tregisteralloctor renamed to trgobj
  453. * removed rgobj from a lot of units
  454. * moved location_* and reference_* to cgobj
  455. * first things for mmx register allocation
  456. Revision 1.20 2003/10/09 21:31:37 daniel
  457. * Register allocator splitted, ans abstract now
  458. Revision 1.19 2003/10/01 20:34:48 peter
  459. * procinfo unit contains tprocinfo
  460. * cginfo renamed to cgbase
  461. * moved cgmessage to verbose
  462. * fixed ppc and sparc compiles
  463. Revision 1.18 2003/09/10 08:31:47 marco
  464. * Patch from Peter for paraloc
  465. Revision 1.17 2003/09/03 15:55:00 peter
  466. * NEWRA branch merged
  467. Revision 1.16 2003/09/03 11:18:37 florian
  468. * fixed arm concatcopy
  469. + arm support in the common compiler sources added
  470. * moved some generic cg code around
  471. + tfputype added
  472. * ...
  473. Revision 1.15.2.2 2003/08/31 15:46:26 peter
  474. * more updates for tregister
  475. Revision 1.15.2.1 2003/08/31 13:50:15 daniel
  476. * Remove sorting and use pregenerated indexes
  477. * Some work on making things compile
  478. Revision 1.15 2003/07/02 22:18:04 peter
  479. * paraloc splitted in callerparaloc,calleeparaloc
  480. * sparc calling convention updates
  481. Revision 1.14 2003/06/07 18:57:04 jonas
  482. + added freeintparaloc
  483. * ppc get/freeintparaloc now check whether the parameter regs are
  484. properly allocated/deallocated (and get an extra list para)
  485. * ppc a_call_* now internalerrors if pi_do_call is not yet set
  486. * fixed lot of missing pi_do_call's
  487. Revision 1.13 2003/06/03 21:11:09 peter
  488. * cg.a_load_* get a from and to size specifier
  489. * makeregsize only accepts newregister
  490. * i386 uses generic tcgnotnode,tcgunaryminus
  491. Revision 1.12 2003/06/01 21:38:06 peter
  492. * getregisterfpu size parameter added
  493. * op_const_reg size parameter added
  494. * sparc updates
  495. Revision 1.11 2003/05/30 23:49:18 jonas
  496. * a_load_loc_reg now has an extra size parameter for the destination
  497. register (properly fixes what I worked around in revision 1.106 of
  498. ncgutil.pas)
  499. Revision 1.10 2003/05/23 14:27:35 peter
  500. * remove some unit dependencies
  501. * current_procinfo changes to store more info
  502. Revision 1.9 2003/04/23 20:16:04 peter
  503. + added currency support based on int64
  504. + is_64bit for use in cg units instead of is_64bitint
  505. * removed cgmessage from n386add, replace with internalerrors
  506. Revision 1.8 2003/04/22 10:09:35 daniel
  507. + Implemented the actual register allocator
  508. + Scratch registers unavailable when new register allocator used
  509. + maybe_save/maybe_restore unavailable when new register allocator used
  510. Revision 1.7 2003/03/28 19:16:56 peter
  511. * generic constructor working for i386
  512. * remove fixed self register
  513. * esi added as address register for i386
  514. Revision 1.6 2003/02/19 22:00:14 daniel
  515. * Code generator converted to new register notation
  516. - Horribily outdated todo.txt removed
  517. Revision 1.5 2002/11/25 17:43:18 peter
  518. * splitted defbase in defutil,symutil,defcmp
  519. * merged isconvertable and is_equal into compare_defs(_ext)
  520. * made operator search faster by walking the list only once
  521. Revision 1.4 2002/09/17 18:54:02 jonas
  522. * a_load_reg_reg() now has two size parameters: source and dest. This
  523. allows some optimizations on architectures that don't encode the
  524. register size in the register name.
  525. Revision 1.3 2002/08/23 16:14:48 peter
  526. * tempgen cleanup
  527. * tt_noreuse temp type added that will be used in genentrycode
  528. Revision 1.2 2002/08/15 15:15:55 carl
  529. * jmpbuf size allocation for exceptions is now cpu specific (as it should)
  530. * more generic nodes for maths
  531. * several fixes for better m68k support
  532. Revision 1.1 2002/08/14 19:26:55 carl
  533. + generic int_to_real type conversion
  534. + generic unaryminus node
  535. }