ncgmat.pas 21 KB

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