ncgmat.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Generate generic mathematical nodes
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit ncgmat;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. node,nmat,cpubase,cgbase;
  22. type
  23. tcgunaryminusnode = class(tunaryminusnode)
  24. protected
  25. { This routine is called to change the sign of the
  26. floating point value in the floating point
  27. register r.
  28. This routine should be overriden, since
  29. the generic version is not optimal at all. The
  30. generic version assumes that floating
  31. point values are stored in the register
  32. in IEEE-754 format.
  33. }
  34. procedure emit_float_sign_change(r: tregister; _size : tcgsize);virtual;
  35. {$ifdef SUPPORT_MMX}
  36. procedure second_mmx;virtual;abstract;
  37. {$endif SUPPORT_MMX}
  38. {$ifndef cpu64bit}
  39. procedure second_64bit;virtual;
  40. {$endif cpu64bit}
  41. procedure second_integer;virtual;
  42. procedure second_float;virtual;
  43. public
  44. procedure pass_2;override;
  45. end;
  46. tcgmoddivnode = class(tmoddivnode)
  47. procedure pass_2;override;
  48. protected
  49. { This routine must do an actual 32-bit division, be it
  50. signed or unsigned. The result must set into the the
  51. @var(num) register.
  52. @param(signed Indicates if the division must be signed)
  53. @param(denum Register containing the denominator
  54. @param(num Register containing the numerator, will also receive result)
  55. The actual optimizations regarding shifts have already
  56. been done and emitted, so this should really a do a divide.
  57. }
  58. procedure emit_div_reg_reg(signed: boolean;denum,num : tregister);virtual;abstract;
  59. { This routine must do an actual 32-bit modulo, be it
  60. signed or unsigned. The result must set into the the
  61. @var(num) register.
  62. @param(signed Indicates if the modulo must be signed)
  63. @param(denum Register containing the denominator
  64. @param(num Register containing the numerator, will also receive result)
  65. The actual optimizations regarding shifts have already
  66. been done and emitted, so this should really a do a modulo.
  67. }
  68. procedure emit_mod_reg_reg(signed: boolean;denum,num : tregister);virtual;abstract;
  69. {$ifndef cpu64bit}
  70. { This routine must do an actual 64-bit division, be it
  71. signed or unsigned. The result must set into the the
  72. @var(num) register.
  73. @param(signed Indicates if the division must be signed)
  74. @param(denum Register containing the denominator
  75. @param(num Register containing the numerator, will also receive result)
  76. The actual optimizations regarding shifts have already
  77. been done and emitted, so this should really a do a divide.
  78. Currently, this routine should only be implemented on
  79. 64-bit systems, otherwise a helper is called in 1st pass.
  80. }
  81. procedure emit64_div_reg_reg(signed: boolean;denum,num : tregister64);virtual;
  82. {$endif cpu64bit}
  83. end;
  84. tcgshlshrnode = class(tshlshrnode)
  85. {$ifndef cpu64bit}
  86. procedure second_64bit;virtual;
  87. {$endif cpu64bit}
  88. procedure second_integer;virtual;
  89. procedure pass_2;override;
  90. end;
  91. tcgnotnode = class(tnotnode)
  92. protected
  93. procedure second_boolean;virtual;abstract;
  94. {$ifdef SUPPORT_MMX}
  95. procedure second_mmx;virtual;abstract;
  96. {$endif SUPPORT_MMX}
  97. {$ifndef cpu64bit}
  98. procedure second_64bit;virtual;
  99. {$endif cpu64bit}
  100. procedure second_integer;virtual;
  101. public
  102. procedure pass_2;override;
  103. end;
  104. implementation
  105. uses
  106. globtype,systems,
  107. cutils,verbose,globals,
  108. symconst,aasmbase,aasmtai,aasmcpu,defutil,
  109. parabase,
  110. pass_2,
  111. ncon,
  112. tgobj,ncgutil,cgobj,cgutils,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,OS_64,
  156. location,joinreg64(location.register64.reglo,location.register64.reghi));
  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. location.register:=cg.getfpuregister(exprasmlist,location.size);
  168. cg.a_loadfpu_ref_reg(exprasmlist,
  169. def_cgsize(left.resulttype.def),
  170. left.location.reference,location.register);
  171. emit_float_sign_change(location.register,def_cgsize(left.resulttype.def));
  172. end;
  173. LOC_FPUREGISTER:
  174. begin
  175. location.register:=left.location.register;
  176. emit_float_sign_change(location.register,def_cgsize(left.resulttype.def));
  177. end;
  178. LOC_CFPUREGISTER:
  179. begin
  180. location.register:=cg.getfpuregister(exprasmlist,location.size);
  181. cg.a_loadfpu_reg_reg(exprasmlist,left.location.size,left.location.register,location.register);
  182. emit_float_sign_change(location.register,def_cgsize(left.resulttype.def));
  183. end;
  184. else
  185. internalerror(200306021);
  186. end;
  187. end;
  188. procedure tcgunaryminusnode.second_integer;
  189. begin
  190. secondpass(left);
  191. { load left operator in a register }
  192. location_copy(location,left.location);
  193. location_force_reg(exprasmlist,location,OS_SINT,false);
  194. cg.a_op_reg_reg(exprasmlist,OP_NEG,OS_SINT,location.register,location.register);
  195. end;
  196. procedure tcgunaryminusnode.pass_2;
  197. begin
  198. {$ifndef cpu64bit}
  199. if is_64bit(left.resulttype.def) then
  200. second_64bit
  201. else
  202. {$endif cpu64bit}
  203. {$ifdef SUPPORT_MMX}
  204. if (cs_mmx in aktlocalswitches) and is_mmx_able_array(left.resulttype.def) then
  205. second_mmx
  206. else
  207. {$endif SUPPORT_MMX}
  208. if (left.resulttype.def.deftype=floatdef) then
  209. second_float
  210. else
  211. second_integer;
  212. end;
  213. {*****************************************************************************
  214. TCGMODDIVNODE
  215. *****************************************************************************}
  216. {$ifndef cpu64bit}
  217. procedure tcgmoddivnode.emit64_div_reg_reg(signed: boolean; denum,num:tregister64);
  218. begin
  219. { handled in pass_1 already, unless pass_1 is
  220. overriden
  221. }
  222. { should be handled in pass_1 (JM) }
  223. internalerror(200109052);
  224. end;
  225. {$endif cpu64bit}
  226. procedure tcgmoddivnode.pass_2;
  227. var
  228. hreg1 : tregister;
  229. hdenom : tregister;
  230. power : longint;
  231. hl : tasmlabel;
  232. paraloc1 : tcgpara;
  233. begin
  234. secondpass(left);
  235. if codegenerror then
  236. exit;
  237. secondpass(right);
  238. if codegenerror then
  239. exit;
  240. location_copy(location,left.location);
  241. {$ifndef cpu64bit}
  242. if is_64bit(resulttype.def) then
  243. begin
  244. { this code valid for 64-bit cpu's only ,
  245. otherwise helpers are called in pass_1
  246. }
  247. location_force_reg(exprasmlist,location,OS_64,false);
  248. location_copy(location,left.location);
  249. location_force_reg(exprasmlist,right.location,OS_64,false);
  250. emit64_div_reg_reg(is_signed(left.resulttype.def),
  251. joinreg64(right.location.register64.reglo,right.location.register64.reghi),
  252. joinreg64(location.register64.reglo,location.register64.reghi));
  253. end
  254. else
  255. {$endif cpu64bit}
  256. begin
  257. { put numerator in register }
  258. location_force_reg(exprasmlist,left.location,OS_INT,false);
  259. hreg1:=left.location.register;
  260. if (nodetype=divn) and
  261. (right.nodetype=ordconstn) and
  262. ispowerof2(tordconstnode(right).value,power) then
  263. Begin
  264. { for signed numbers, the numerator must be adjusted before the
  265. shift instruction, but not wih unsigned numbers! Otherwise,
  266. "Cardinal($ffffffff) div 16" overflows! (JM) }
  267. If is_signed(left.resulttype.def) Then
  268. Begin
  269. objectlibrary.getlabel(hl);
  270. cg.a_cmp_const_reg_label(exprasmlist,OS_INT,OC_GT,0,hreg1,hl);
  271. if power=1 then
  272. cg.a_op_const_reg(exprasmlist,OP_ADD,OS_INT,1,hreg1)
  273. else
  274. cg.a_op_const_reg(exprasmlist,OP_ADD,OS_INT,tordconstnode(right).value-1,hreg1);
  275. cg.a_label(exprasmlist,hl);
  276. cg.a_op_const_reg(exprasmlist,OP_SAR,OS_INT,power,hreg1);
  277. End
  278. Else { not signed }
  279. cg.a_op_const_reg(exprasmlist,OP_SHR,OS_INT,power,hreg1);
  280. End
  281. else
  282. begin
  283. { bring denominator to hdenom }
  284. { hdenom is always free, it's }
  285. { only used for temporary }
  286. { purposes }
  287. hdenom := cg.getintregister(exprasmlist,OS_INT);
  288. cg.a_load_loc_reg(exprasmlist,right.location.size,right.location,hdenom);
  289. { verify if the divisor is zero, if so return an error
  290. immediately
  291. }
  292. objectlibrary.getlabel(hl);
  293. cg.a_cmp_const_reg_label(exprasmlist,OS_INT,OC_NE,0,hdenom,hl);
  294. paraloc1.init;
  295. paramanager.getintparaloc(pocall_default,1,paraloc1);
  296. paramanager.allocparaloc(exprasmlist,paraloc1);
  297. cg.a_param_const(exprasmlist,OS_S32,200,paraloc1);
  298. paramanager.freeparaloc(exprasmlist,paraloc1);
  299. cg.a_call_name(exprasmlist,'FPC_HANDLERROR');
  300. paraloc1.done;
  301. cg.a_label(exprasmlist,hl);
  302. if nodetype = modn then
  303. emit_mod_reg_reg(is_signed(left.resulttype.def),hdenom,hreg1)
  304. else
  305. emit_div_reg_reg(is_signed(left.resulttype.def),hdenom,hreg1);
  306. end;
  307. location_reset(location,LOC_REGISTER,OS_INT);
  308. location.register:=hreg1;
  309. end;
  310. cg.g_overflowcheck(exprasmlist,location,resulttype.def);
  311. end;
  312. {*****************************************************************************
  313. TCGSHLRSHRNODE
  314. *****************************************************************************}
  315. {$ifndef cpu64bit}
  316. procedure tcgshlshrnode.second_64bit;
  317. begin
  318. { already hanled in 1st pass }
  319. internalerror(2002081501);
  320. end;
  321. {$endif cpu64bit}
  322. procedure tcgshlshrnode.second_integer;
  323. var
  324. op : topcg;
  325. hcountreg : tregister;
  326. begin
  327. { determine operator }
  328. case nodetype of
  329. shln: op:=OP_SHL;
  330. shrn: op:=OP_SHR;
  331. end;
  332. { load left operators in a register }
  333. location_copy(location,left.location);
  334. location_force_reg(exprasmlist,location,OS_INT,false);
  335. { shifting by a constant directly coded: }
  336. if (right.nodetype=ordconstn) then
  337. begin
  338. { l shl 32 should 0 imho, but neither TP nor Delphi do it in this way (FK)
  339. if right.value<=31 then
  340. }
  341. cg.a_op_const_reg(exprasmlist,op,location.size,
  342. tordconstnode(right).value and 31,location.register);
  343. {
  344. else
  345. emit_reg_reg(A_XOR,S_L,hregister1,
  346. hregister1);
  347. }
  348. end
  349. else
  350. begin
  351. { load right operators in a register - this
  352. is done since most target cpu which will use this
  353. node do not support a shift count in a mem. location (cec)
  354. }
  355. if right.location.loc<>LOC_REGISTER then
  356. begin
  357. hcountreg:=cg.getintregister(exprasmlist,OS_INT);
  358. cg.a_load_loc_reg(exprasmlist,right.location.size,right.location,hcountreg);
  359. end
  360. else
  361. hcountreg:=right.location.register;
  362. cg.a_op_reg_reg(exprasmlist,op,OS_INT,hcountreg,location.register);
  363. end;
  364. end;
  365. procedure tcgshlshrnode.pass_2;
  366. begin
  367. secondpass(left);
  368. secondpass(right);
  369. {$ifndef cpu64bit}
  370. if is_64bit(left.resulttype.def) then
  371. second_64bit
  372. else
  373. {$endif cpu64bit}
  374. second_integer;
  375. end;
  376. {*****************************************************************************
  377. TCGNOTNODE
  378. *****************************************************************************}
  379. {$ifndef cpu64bit}
  380. procedure tcgnotnode.second_64bit;
  381. begin
  382. secondpass(left);
  383. location_force_reg(exprasmlist,left.location,def_cgsize(left.resulttype.def),false);
  384. location_copy(location,left.location);
  385. { perform the NOT operation }
  386. cg64.a_op64_reg_reg(exprasmlist,OP_NOT,location.size,left.location.register64,location.register64);
  387. end;
  388. {$endif cpu64bit}
  389. procedure tcgnotnode.second_integer;
  390. begin
  391. secondpass(left);
  392. location_force_reg(exprasmlist,left.location,def_cgsize(left.resulttype.def),false);
  393. location_copy(location,left.location);
  394. { perform the NOT operation }
  395. cg.a_op_reg_reg(exprasmlist,OP_NOT,location.size,location.register,location.register);
  396. end;
  397. procedure tcgnotnode.pass_2;
  398. begin
  399. if is_boolean(resulttype.def) then
  400. second_boolean
  401. {$ifdef SUPPORT_MMX}
  402. else if (cs_mmx in aktlocalswitches) and is_mmx_able_array(left.resulttype.def) then
  403. second_mmx
  404. {$endif SUPPORT_MMX}
  405. {$ifndef cpu64bit}
  406. else if is_64bit(left.resulttype.def) then
  407. second_64bit
  408. {$endif cpu64bit}
  409. else
  410. second_integer;
  411. end;
  412. begin
  413. cmoddivnode:=tcgmoddivnode;
  414. cunaryminusnode:=tcgunaryminusnode;
  415. cshlshrnode:=tcgshlshrnode;
  416. cnotnode:=tcgnotnode;
  417. end.