ncgmat.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  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. parabase,
  111. pass_2,
  112. ncon,
  113. tgobj,ncgutil,cgobj,paramgr
  114. {$ifndef cpu64bit}
  115. ,cg64f32
  116. {$endif cpu64bit}
  117. ;
  118. {*****************************************************************************
  119. TCGUNARYMINUSNODE
  120. *****************************************************************************}
  121. procedure tcgunaryminusnode.emit_float_sign_change(r: tregister; _size : tcgsize);
  122. var
  123. href,
  124. href2 : treference;
  125. begin
  126. { get a temporary memory reference to store the floating
  127. point value
  128. }
  129. tg.gettemp(exprasmlist,tcgsize2size[_size],tt_normal,href);
  130. { store the floating point value in the temporary memory area }
  131. cg.a_loadfpu_reg_ref(exprasmlist,_size,r,href);
  132. { only single and double ieee are supported, for little endian
  133. the signed bit is in the second dword }
  134. href2:=href;
  135. case _size of
  136. OS_F64 :
  137. if target_info.endian = endian_little then
  138. inc(href2.offset,4);
  139. OS_F32 :
  140. ;
  141. else
  142. internalerror(200406021);
  143. end;
  144. { flip sign-bit (bit 31/63) of single/double }
  145. cg.a_op_const_ref(exprasmlist,OP_XOR,OS_32,aint($80000000),href2);
  146. cg.a_loadfpu_ref_reg(exprasmlist,_size,href,r);
  147. tg.ungetiftemp(exprasmlist,href);
  148. end;
  149. {$ifndef cpu64bit}
  150. procedure tcgunaryminusnode.second_64bit;
  151. begin
  152. secondpass(left);
  153. { load left operator in a register }
  154. location_copy(location,left.location);
  155. location_force_reg(exprasmlist,location,OS_64,false);
  156. cg64.a_op64_loc_reg(exprasmlist,OP_NEG,
  157. location,joinreg64(location.registerlow,location.registerhigh));
  158. end;
  159. {$endif cpu64bit}
  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:=cg.getfpuregister(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:=cg.getfpuregister(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. {$ifndef cpu64bit}
  201. if is_64bit(left.resulttype.def) then
  202. second_64bit
  203. else
  204. {$endif cpu64bit}
  205. {$ifdef SUPPORT_MMX}
  206. if (cs_mmx in aktlocalswitches) and is_mmx_able_array(left.resulttype.def) then
  207. second_mmx
  208. else
  209. {$endif SUPPORT_MMX}
  210. if (left.resulttype.def.deftype=floatdef) then
  211. second_float
  212. else
  213. second_integer;
  214. end;
  215. {*****************************************************************************
  216. TCGMODDIVNODE
  217. *****************************************************************************}
  218. {$ifndef cpu64bit}
  219. procedure tcgmoddivnode.emit64_div_reg_reg(signed: boolean; denum,num:tregister64);
  220. begin
  221. { handled in pass_1 already, unless pass_1 is
  222. overriden
  223. }
  224. { should be handled in pass_1 (JM) }
  225. internalerror(200109052);
  226. end;
  227. {$endif cpu64bit}
  228. procedure tcgmoddivnode.pass_2;
  229. var
  230. hreg1 : tregister;
  231. hdenom : tregister;
  232. power : longint;
  233. hl : tasmlabel;
  234. paraloc1 : tcgpara;
  235. begin
  236. secondpass(left);
  237. if codegenerror then
  238. exit;
  239. secondpass(right);
  240. if codegenerror then
  241. exit;
  242. location_copy(location,left.location);
  243. {$ifndef cpu64bit}
  244. if is_64bit(resulttype.def) then
  245. begin
  246. { this code valid for 64-bit cpu's only ,
  247. otherwise helpers are called in pass_1
  248. }
  249. location_force_reg(exprasmlist,location,OS_64,false);
  250. location_copy(location,left.location);
  251. location_force_reg(exprasmlist,right.location,OS_64,false);
  252. emit64_div_reg_reg(is_signed(left.resulttype.def),
  253. joinreg64(right.location.registerlow,right.location.registerhigh),
  254. joinreg64(location.registerlow,location.registerhigh));
  255. end
  256. else
  257. {$endif cpu64bit}
  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 := cg.getintregister(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. paraloc1.init;
  299. paramanager.getintparaloc(pocall_default,1,paraloc1);
  300. paramanager.allocparaloc(exprasmlist,paraloc1);
  301. cg.a_param_const(exprasmlist,OS_S32,200,paraloc1);
  302. paramanager.freeparaloc(exprasmlist,paraloc1);
  303. cg.a_call_name(exprasmlist,'FPC_HANDLERROR');
  304. paraloc1.done;
  305. cg.a_label(exprasmlist,hl);
  306. if nodetype = modn then
  307. emit_mod_reg_reg(is_signed(left.resulttype.def),hdenom,hreg1)
  308. else
  309. emit_div_reg_reg(is_signed(left.resulttype.def),hdenom,hreg1);
  310. end;
  311. location_reset(location,LOC_REGISTER,OS_INT);
  312. location.register:=hreg1;
  313. end;
  314. cg.g_overflowcheck(exprasmlist,location,resulttype.def);
  315. end;
  316. {*****************************************************************************
  317. TCGSHLRSHRNODE
  318. *****************************************************************************}
  319. {$ifndef cpu64bit}
  320. procedure tcgshlshrnode.second_64bit;
  321. begin
  322. { already hanled in 1st pass }
  323. internalerror(2002081501);
  324. end;
  325. {$endif cpu64bit}
  326. procedure tcgshlshrnode.second_integer;
  327. var
  328. freescratch : boolean;
  329. op : topcg;
  330. hcountreg : tregister;
  331. begin
  332. freescratch:=false;
  333. { determine operator }
  334. case nodetype of
  335. shln: op:=OP_SHL;
  336. shrn: op:=OP_SHR;
  337. end;
  338. { load left operators in a register }
  339. location_copy(location,left.location);
  340. location_force_reg(exprasmlist,location,OS_INT,false);
  341. { shifting by a constant directly coded: }
  342. if (right.nodetype=ordconstn) then
  343. begin
  344. { l shl 32 should 0 imho, but neither TP nor Delphi do it in this way (FK)
  345. if right.value<=31 then
  346. }
  347. cg.a_op_const_reg(exprasmlist,op,location.size,
  348. tordconstnode(right).value and 31,location.register);
  349. {
  350. else
  351. emit_reg_reg(A_XOR,S_L,hregister1,
  352. hregister1);
  353. }
  354. end
  355. else
  356. begin
  357. { load right operators in a register - this
  358. is done since most target cpu which will use this
  359. node do not support a shift count in a mem. location (cec)
  360. }
  361. if right.location.loc<>LOC_REGISTER then
  362. begin
  363. hcountreg:=cg.getintregister(exprasmlist,OS_INT);
  364. freescratch := true;
  365. cg.a_load_loc_reg(exprasmlist,right.location.size,right.location,hcountreg);
  366. end
  367. else
  368. hcountreg:=right.location.register;
  369. cg.a_op_reg_reg(exprasmlist,op,OS_INT,hcountreg,location.register);
  370. if right.location.loc<>LOC_REGISTER then
  371. location_release(exprasmlist,right.location);
  372. if freescratch then
  373. cg.ungetregister(exprasmlist,hcountreg);
  374. end;
  375. end;
  376. procedure tcgshlshrnode.pass_2;
  377. begin
  378. secondpass(left);
  379. secondpass(right);
  380. {$ifndef cpu64bit}
  381. if is_64bit(left.resulttype.def) then
  382. second_64bit
  383. else
  384. {$endif cpu64bit}
  385. second_integer;
  386. end;
  387. {*****************************************************************************
  388. TCGNOTNODE
  389. *****************************************************************************}
  390. {$ifndef cpu64bit}
  391. procedure tcgnotnode.second_64bit;
  392. begin
  393. secondpass(left);
  394. location_force_reg(exprasmlist,left.location,def_cgsize(left.resulttype.def),false);
  395. location_copy(location,left.location);
  396. { perform the NOT operation }
  397. cg64.a_op64_reg_reg(exprasmlist,OP_NOT,left.location.register64,location.register64);
  398. end;
  399. {$endif cpu64bit}
  400. procedure tcgnotnode.second_integer;
  401. begin
  402. secondpass(left);
  403. location_force_reg(exprasmlist,left.location,def_cgsize(left.resulttype.def),false);
  404. location_copy(location,left.location);
  405. { perform the NOT operation }
  406. cg.a_op_reg_reg(exprasmlist,OP_NOT,location.size,location.register,location.register);
  407. end;
  408. procedure tcgnotnode.pass_2;
  409. begin
  410. if is_boolean(resulttype.def) then
  411. second_boolean
  412. {$ifdef SUPPORT_MMX}
  413. else if (cs_mmx in aktlocalswitches) and is_mmx_able_array(left.resulttype.def) then
  414. second_mmx
  415. {$endif SUPPORT_MMX}
  416. {$ifndef cpu64bit}
  417. else if is_64bit(left.resulttype.def) then
  418. second_64bit
  419. {$endif cpu64bit}
  420. else
  421. second_integer;
  422. end;
  423. begin
  424. cmoddivnode:=tcgmoddivnode;
  425. cunaryminusnode:=tcgunaryminusnode;
  426. cshlshrnode:=tcgshlshrnode;
  427. cnotnode:=tcgnotnode;
  428. end.
  429. {
  430. $Log$
  431. Revision 1.28 2004-09-21 17:25:12 peter
  432. * paraloc branch merged
  433. Revision 1.27.4.1 2004/08/31 20:43:06 peter
  434. * paraloc patch
  435. Revision 1.27 2004/06/20 08:55:29 florian
  436. * logs truncated
  437. Revision 1.26 2004/06/16 20:07:08 florian
  438. * dwarf branch merged
  439. Revision 1.25.2.4 2004/06/02 19:04:51 peter
  440. * fixed minusunary for float
  441. Revision 1.25.2.3 2004/05/31 16:39:42 peter
  442. * add ungetiftemp in a few locations
  443. Revision 1.25.2.2 2004/05/30 17:07:07 peter
  444. * fix shl shr for sparc
  445. Revision 1.25.2.1 2004/04/27 18:18:25 peter
  446. * aword -> aint
  447. }