ncgmat.pas 22 KB

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