n386mat.pas 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. Generate i386 assembler for math 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 cg386mat;
  19. {$i defines.inc}
  20. interface
  21. uses
  22. node,nmat;
  23. ti386moddivnode = class(tmoddivnode)
  24. procedure pass_2;override;
  25. end;
  26. ti386shlshrnode = class(tshlshrnode)
  27. procedure pass_2;override;
  28. end;
  29. ti386unaryminusnode = class(tunaryminus)
  30. procedure pass_2;override;
  31. end;
  32. ti386notnode = class(tnotnode)
  33. procedure pass_2;override;
  34. end;
  35. implementation
  36. uses
  37. globtype,systems,
  38. cutils,cobjects,verbose,globals,
  39. symconst,symtable,aasm,types,
  40. hcodegen,temp_gen,pass_2,
  41. cpubase,cpuasm,
  42. cgai386,tgeni386;
  43. {*****************************************************************************
  44. TI386MODDIVNODE
  45. *****************************************************************************}
  46. procedure ti386moddivnode.pass_2;
  47. var
  48. hreg1 : tregister;
  49. hreg2 : tregister;
  50. shrdiv, andmod, pushed,popeax,popedx : boolean;
  51. power : longint;
  52. hl : pasmlabel;
  53. hloc : tlocation;
  54. pushedreg : tpushed;
  55. typename,opname : string[6];
  56. begin
  57. shrdiv := false;
  58. andmod := false;
  59. secondpass(left);
  60. pushed:=maybe_push(right.registers32,left,is_64bitint(left.resulttype));
  61. secondpass(right);
  62. if pushed then
  63. restore(left,is_64bitint(left.resulttype));
  64. set_location(location,left.location);
  65. if is_64bitint(resulttype) then
  66. begin
  67. { save lcoation, because we change it now }
  68. set_location(hloc,location);
  69. release_qword_loc(location);
  70. release_qword_loc(right.location);
  71. location.registerlow:=getexplicitregister32(R_EAX);
  72. location.registerhigh:=getexplicitregister32(R_EDX);
  73. pushusedregisters(pushedreg,$ff
  74. and not($80 shr byte(location.registerlow))
  75. and not($80 shr byte(location.registerhigh)));
  76. { the left operand is in hloc, because the
  77. location of left is location but location
  78. is already destroyed
  79. }
  80. emit_pushq_loc(hloc);
  81. clear_location(hloc);
  82. emit_pushq_loc(right.location);
  83. if porddef(resulttype)^.typ=u64bit then
  84. typename:='QWORD'
  85. else
  86. typename:='INT64';
  87. if treetype=divn then
  88. opname:='DIV_'
  89. else
  90. opname:='MOD_';
  91. emitcall('FPC_'+opname+typename);
  92. emit_reg_reg(A_MOV,S_L,R_EAX,location.registerlow);
  93. emit_reg_reg(A_MOV,S_L,R_EDX,location.registerhigh);
  94. popusedregisters(pushedreg);
  95. location.loc:=LOC_REGISTER;
  96. end
  97. else
  98. begin
  99. { put numerator in register }
  100. if left.location.loc<>LOC_REGISTER then
  101. begin
  102. if left.location.loc=LOC_CREGISTER then
  103. begin
  104. hreg1:=getregister32;
  105. emit_reg_reg(A_MOV,S_L,left.location.register,hreg1);
  106. end
  107. else
  108. begin
  109. del_reference(left.location.reference);
  110. hreg1:=getregister32;
  111. emit_ref_reg(A_MOV,S_L,newreference(left.location.reference),
  112. hreg1);
  113. end;
  114. clear_location(left.location);
  115. left.location.loc:=LOC_REGISTER;
  116. left.location.register:=hreg1;
  117. end
  118. else hreg1:=left.location.register;
  119. if (treetype=divn) and (right.treetype=ordconstn) and
  120. ispowerof2(right.tordconstnode(value),power) then
  121. Begin
  122. shrdiv := true;
  123. {for signed numbers, the numerator must be adjusted before the
  124. shift instruction, but not wih unsigned numbers! Otherwise,
  125. "Cardinal($ffffffff) div 16" overflows! (JM)}
  126. If is_signed(left.resulttype) Then
  127. Begin
  128. If (aktOptProcessor <> class386) and
  129. not(CS_LittleSize in aktglobalswitches) then
  130. { use a sequence without jumps, saw this in
  131. comp.compilers (JM) }
  132. begin
  133. { no jumps, but more operations }
  134. if (hreg1 = R_EAX) and
  135. (R_EDX in unused) then
  136. begin
  137. hreg2 := getexplicitregister32(R_EDX);
  138. emit_none(A_CDQ,S_NO);
  139. end
  140. else
  141. begin
  142. {$ifndef noAllocEdi}
  143. getexplicitregister32(R_EDI);
  144. {$endif noAllocEdi}
  145. hreg2 := R_EDI;
  146. emit_reg_reg(A_MOV,S_L,hreg1,R_EDI);
  147. { if the left value is signed, R_EDI := $ffffffff,
  148. otherwise 0 }
  149. emit_const_reg(A_SAR,S_L,31,R_EDI);
  150. { if signed, R_EDI := right value-1, otherwise 0 }
  151. end;
  152. emit_const_reg(A_AND,S_L,tordconstnode(right).value-1,hreg2);
  153. { add to the left value }
  154. emit_reg_reg(A_ADD,S_L,hreg2,hreg1);
  155. { release EDX if we used it }
  156. {$ifndef noAllocEdi}
  157. { also releas EDI }
  158. ungetregister32(hreg2);
  159. {$else noAllocEdi}
  160. if (hreg2 = R_EDX) then
  161. ungetregister32(hreg2);
  162. {$endif noAllocEdi}
  163. { do the shift }
  164. emit_const_reg(A_SAR,S_L,power,hreg1);
  165. end
  166. else
  167. begin
  168. { a jump, but less operations }
  169. emit_reg_reg(A_TEST,S_L,hreg1,hreg1);
  170. getlabel(hl);
  171. emitjmp(C_NS,hl);
  172. if power=1 then
  173. emit_reg(A_INC,S_L,hreg1)
  174. else
  175. emit_const_reg(A_ADD,S_L,tordconstnode(right).value-1,hreg1);
  176. emitlab(hl);
  177. emit_const_reg(A_SAR,S_L,power,hreg1);
  178. end
  179. End
  180. Else
  181. emit_const_reg(A_SHR,S_L,power,hreg1);
  182. End
  183. else
  184. if (treetype=modn) and (right.treetype=ordconstn) and
  185. ispowerof2(tordconstnode(right).value,power) and Not(is_signed(left.resulttype)) Then
  186. {is there a similar trick for MOD'ing signed numbers? (JM)}
  187. Begin
  188. emit_const_reg(A_AND,S_L,tordconstnode(right).value-1,hreg1);
  189. andmod := true;
  190. End
  191. else
  192. begin
  193. { bring denominator to EDI }
  194. { EDI is always free, it's }
  195. { only used for temporary }
  196. { purposes }
  197. {$ifndef noAllocEdi}
  198. getexplicitregister32(R_EDI);
  199. {$endif noAllocEdi}
  200. if (right.location.loc<>LOC_REGISTER) and
  201. (right.location.loc<>LOC_CREGISTER) then
  202. begin
  203. del_reference(right.location.reference);
  204. left.location.loc:=LOC_REGISTER;
  205. emit_ref_reg(A_MOV,S_L,newreference(right.location.reference),R_EDI);
  206. end
  207. else
  208. begin
  209. emit_reg_reg(A_MOV,S_L,right.location.register,R_EDI);
  210. ungetregister32(right.location.register);
  211. end;
  212. popedx:=false;
  213. popeax:=false;
  214. if hreg1=R_EDX then
  215. begin
  216. if not(R_EAX in unused) then
  217. begin
  218. emit_reg(A_PUSH,S_L,R_EAX);
  219. popeax:=true;
  220. end;
  221. emit_reg_reg(A_MOV,S_L,R_EDX,R_EAX);
  222. end
  223. else
  224. begin
  225. if not(R_EDX in unused) then
  226. begin
  227. emit_reg(A_PUSH,S_L,R_EDX);
  228. popedx:=true;
  229. end;
  230. if hreg1<>R_EAX then
  231. begin
  232. if not(R_EAX in unused) then
  233. begin
  234. emit_reg(A_PUSH,S_L,R_EAX);
  235. popeax:=true;
  236. end;
  237. emit_reg_reg(A_MOV,S_L,hreg1,R_EAX);
  238. end;
  239. end;
  240. { sign extension depends on the left type }
  241. if porddef(left.resulttype)^.typ=u32bit then
  242. emit_reg_reg(A_XOR,S_L,R_EDX,R_EDX)
  243. else
  244. emit_none(A_CDQ,S_NO);
  245. { division depends on the right type }
  246. if porddef(right.resulttype)^.typ=u32bit then
  247. emit_reg(A_DIV,S_L,R_EDI)
  248. else
  249. emit_reg(A_IDIV,S_L,R_EDI);
  250. {$ifndef noAllocEdi}
  251. ungetregister32(R_EDI);
  252. {$endif noAllocEdi}
  253. if treetype=divn then
  254. begin
  255. { if result register is busy then copy }
  256. if popeax then
  257. begin
  258. if hreg1=R_EAX then
  259. internalerror(112);
  260. emit_reg_reg(A_MOV,S_L,R_EAX,hreg1)
  261. end
  262. else
  263. if hreg1<>R_EAX then
  264. Begin
  265. ungetregister32(hreg1);
  266. hreg1 := getexplicitregister32(R_EAX);
  267. { I don't think it's possible that now hreg1 <> R_EAX
  268. since popeax is false, but for all certainty I do
  269. support that situation (JM)}
  270. if hreg1 <> R_EAX then
  271. emit_reg_reg(A_MOV,S_L,R_EAX,hreg1);
  272. end;
  273. end
  274. else
  275. {if we did the mod by an "and", the result is in hreg1 and
  276. EDX certainly hasn't been pushed (JM)}
  277. if not(andmod) Then
  278. if popedx then
  279. {the mod was done by an (i)div (so the result is now in
  280. edx), but edx was occupied prior to the division, so
  281. move the result into a safe place (JM)}
  282. emit_reg_reg(A_MOV,S_L,R_EDX,hreg1)
  283. else
  284. Begin
  285. {Get rid of the unnecessary hreg1 if possible (same as with
  286. EAX in divn) (JM)}
  287. ungetregister32(hreg1);
  288. hreg1 := getexplicitregister32(R_EDX);
  289. if hreg1 <> R_EDX then
  290. emit_reg_reg(A_MOV,S_L,R_EDX,hreg1);;
  291. End;
  292. if popeax then
  293. emit_reg(A_POP,S_L,R_EAX);
  294. if popedx then
  295. emit_reg(A_POP,S_L,R_EDX);
  296. end;
  297. If not(andmod or shrdiv) then
  298. {andmod and shrdiv only use hreg1 (which is already in usedinproc,
  299. since it was acquired with getregister), the others also use both
  300. EAX and EDX (JM)}
  301. Begin
  302. usedinproc:=usedinproc or ($80 shr byte(R_EAX));
  303. usedinproc:=usedinproc or ($80 shr byte(R_EDX));
  304. End;
  305. clear_location(location);
  306. location.loc:=LOC_REGISTER;
  307. location.register:=hreg1;
  308. end;
  309. end;
  310. {*****************************************************************************
  311. TI386SHLRSHRNODE
  312. *****************************************************************************}
  313. procedure ti386shlshrnode.pass_2;
  314. var
  315. hregister1,hregister2,hregister3,
  316. hregisterhigh,hregisterlow : tregister;
  317. pushed,popecx : boolean;
  318. op : tasmop;
  319. l1,l2,l3 : pasmlabel;
  320. begin
  321. popecx:=false;
  322. secondpass(left);
  323. pushed:=maybe_push(right.registers32,left,is_64bitint(left.resulttype));
  324. secondpass(right);
  325. if pushed then
  326. restore(left,is_64bitint(left.resulttype));
  327. if is_64bitint(left.resulttype) then
  328. begin
  329. { load left operator in a register }
  330. if left.location.loc<>LOC_REGISTER then
  331. begin
  332. if left.location.loc=LOC_CREGISTER then
  333. begin
  334. hregisterlow:=getregister32;
  335. hregisterhigh:=getregister32;
  336. emit_reg_reg(A_MOV,S_L,left.location.registerlow,
  337. hregisterlow);
  338. emit_reg_reg(A_MOV,S_L,left.location.registerhigh,
  339. hregisterlow);
  340. end
  341. else
  342. begin
  343. del_reference(left.location.reference);
  344. hregisterlow:=getregister32;
  345. hregisterhigh:=getregister32;
  346. emit_mov_ref_reg64(left.location.reference,
  347. hregisterlow,
  348. hregisterhigh);
  349. end;
  350. end
  351. else
  352. begin
  353. hregisterlow:=left.location.registerlow;
  354. hregisterhigh:=left.location.registerhigh;
  355. end;
  356. { shifting by a constant directly coded: }
  357. if (right.treetype=ordconstn) then
  358. begin
  359. { shrd/shl works only for values <=31 !! }
  360. if right.tordconstnode(value)>31 then
  361. begin
  362. if treetype=shln then
  363. begin
  364. emit_reg_reg(A_XOR,S_L,hregisterhigh,
  365. hregisterhigh);
  366. emit_const_reg(A_SHL,S_L,tordconstnode(right).value and 31,
  367. hregisterlow);
  368. end
  369. else
  370. begin
  371. emit_reg_reg(A_XOR,S_L,hregisterlow,
  372. hregisterlow);
  373. emit_const_reg(A_SHR,S_L,tordconstnode(right).value and 31,
  374. hregisterhigh);
  375. end;
  376. location.registerhigh:=hregisterlow;
  377. location.registerlow:=hregisterhigh;
  378. end
  379. else
  380. begin
  381. if treetype=shln then
  382. begin
  383. emit_const_reg_reg(A_SHLD,S_L,tordconstnode(right).value and 31,
  384. hregisterlow,hregisterhigh);
  385. emit_const_reg(A_SHL,S_L,tordconstnode(right).value and 31,
  386. hregisterlow);
  387. end
  388. else
  389. begin
  390. emit_const_reg_reg(A_SHRD,S_L,tordconstnode(right).value and 31,
  391. hregisterhigh,hregisterlow);
  392. emit_const_reg(A_SHR,S_L,tordconstnode(right).value and 31,
  393. hregisterhigh);
  394. end;
  395. location.registerlow:=hregisterlow;
  396. location.registerhigh:=hregisterhigh;
  397. end;
  398. location.loc:=LOC_REGISTER;
  399. end
  400. else
  401. begin
  402. { load right operators in a register }
  403. if right.location.loc<>LOC_REGISTER then
  404. begin
  405. if right.location.loc=LOC_CREGISTER then
  406. begin
  407. hregister2:=getexplicitregister32(R_ECX);
  408. emit_reg_reg(A_MOV,S_L,right.location.register,
  409. hregister2);
  410. end
  411. else
  412. begin
  413. del_reference(right.location.reference);
  414. hregister2:=getexplicitregister32(R_ECX);
  415. emit_ref_reg(A_MOV,S_L,newreference(right.location.reference),
  416. hregister2);
  417. end;
  418. end
  419. else
  420. hregister2:=right.location.register;
  421. { left operator is already in a register }
  422. { hence are both in a register }
  423. { is it in the case ECX ? }
  424. if (hregisterlow=R_ECX) then
  425. begin
  426. { then only swap }
  427. emit_reg_reg(A_XCHG,S_L,hregisterlow,hregister2);
  428. hregister3:=hregisterlow;
  429. hregisterlow:=hregister2;
  430. hregister2:=hregister3;
  431. end
  432. else if (hregisterhigh=R_ECX) then
  433. begin
  434. { then only swap }
  435. emit_reg_reg(A_XCHG,S_L,hregisterhigh,hregister2);
  436. hregister3:=hregisterhigh;
  437. hregisterhigh:=hregister2;
  438. hregister2:=hregister3;
  439. end
  440. { if second operator not in ECX ? }
  441. else if (hregister2<>R_ECX) then
  442. begin
  443. { ECX occupied then push it }
  444. if not (R_ECX in unused) then
  445. begin
  446. popecx:=true;
  447. emit_reg(A_PUSH,S_L,R_ECX);
  448. end;
  449. emit_reg_reg(A_MOV,S_L,hregister2,R_ECX);
  450. end;
  451. if hregister2 <> R_ECX then
  452. ungetregister32(hregister2);
  453. { the damned shift instructions work only til a count of 32 }
  454. { so we've to do some tricks here }
  455. if treetype=shln then
  456. begin
  457. getlabel(l1);
  458. getlabel(l2);
  459. getlabel(l3);
  460. emit_const_reg(A_CMP,S_L,64,R_ECX);
  461. emitjmp(C_L,l1);
  462. emit_reg_reg(A_XOR,S_L,hregisterlow,hregisterlow);
  463. emit_reg_reg(A_XOR,S_L,hregisterhigh,hregisterhigh);
  464. emitjmp(C_None,l3);
  465. emitlab(l1);
  466. emit_const_reg(A_CMP,S_L,32,R_ECX);
  467. emitjmp(C_L,l2);
  468. emit_const_reg(A_SUB,S_L,32,R_ECX);
  469. emit_reg_reg(A_SHL,S_L,R_CL,
  470. hregisterlow);
  471. emit_reg_reg(A_MOV,S_L,hregisterlow,hregisterhigh);
  472. emit_reg_reg(A_XOR,S_L,hregisterlow,hregisterlow);
  473. emitjmp(C_None,l3);
  474. emitlab(l2);
  475. emit_reg_reg_reg(A_SHLD,S_L,R_CL,
  476. hregisterlow,hregisterhigh);
  477. emit_reg_reg(A_SHL,S_L,R_CL,
  478. hregisterlow);
  479. emitlab(l3);
  480. end
  481. else
  482. begin
  483. getlabel(l1);
  484. getlabel(l2);
  485. getlabel(l3);
  486. emit_const_reg(A_CMP,S_L,64,R_ECX);
  487. emitjmp(C_L,l1);
  488. emit_reg_reg(A_XOR,S_L,hregisterlow,hregisterlow);
  489. emit_reg_reg(A_XOR,S_L,hregisterhigh,hregisterhigh);
  490. emitjmp(C_None,l3);
  491. emitlab(l1);
  492. emit_const_reg(A_CMP,S_L,32,R_ECX);
  493. emitjmp(C_L,l2);
  494. emit_const_reg(A_SUB,S_L,32,R_ECX);
  495. emit_reg_reg(A_SHR,S_L,R_CL,
  496. hregisterhigh);
  497. emit_reg_reg(A_MOV,S_L,hregisterhigh,hregisterlow);
  498. emit_reg_reg(A_XOR,S_L,hregisterhigh,hregisterhigh);
  499. emitjmp(C_None,l3);
  500. emitlab(l2);
  501. emit_reg_reg_reg(A_SHRD,S_L,R_CL,
  502. hregisterhigh,hregisterlow);
  503. emit_reg_reg(A_SHR,S_L,R_CL,
  504. hregisterhigh);
  505. emitlab(l3);
  506. end;
  507. { maybe put ECX back }
  508. if popecx then
  509. emit_reg(A_POP,S_L,R_ECX)
  510. else ungetregister32(R_ECX);
  511. location.registerlow:=hregisterlow;
  512. location.registerhigh:=hregisterhigh;
  513. end;
  514. end
  515. else
  516. begin
  517. { load left operators in a register }
  518. if left.location.loc<>LOC_REGISTER then
  519. begin
  520. if left.location.loc=LOC_CREGISTER then
  521. begin
  522. hregister1:=getregister32;
  523. emit_reg_reg(A_MOV,S_L,left.location.register,
  524. hregister1);
  525. end
  526. else
  527. begin
  528. del_reference(left.location.reference);
  529. hregister1:=getregister32;
  530. emit_ref_reg(A_MOV,S_L,newreference(left.location.reference),
  531. hregister1);
  532. end;
  533. end
  534. else
  535. hregister1:=left.location.register;
  536. { determine operator }
  537. if treetype=shln then
  538. op:=A_SHL
  539. else
  540. op:=A_SHR;
  541. { shifting by a constant directly coded: }
  542. if (right.treetype=ordconstn) then
  543. begin
  544. { l shl 32 should 0 imho, but neither TP nor Delphi do it in this way (FK)
  545. if right.value<=31 then
  546. }
  547. emit_const_reg(op,S_L,tordconstnode(right).value and 31,
  548. hregister1);
  549. {
  550. else
  551. emit_reg_reg(A_XOR,S_L,hregister1,
  552. hregister1);
  553. }
  554. location.loc:=LOC_REGISTER;
  555. location.register:=hregister1;
  556. end
  557. else
  558. begin
  559. { load right operators in a register }
  560. if right.location.loc<>LOC_REGISTER then
  561. begin
  562. if right.location.loc=LOC_CREGISTER then
  563. begin
  564. hregister2:=getexplicitregister32(R_ECX);
  565. emit_reg_reg(A_MOV,S_L,right.location.register,
  566. hregister2);
  567. end
  568. else
  569. begin
  570. del_reference(right.location.reference);
  571. hregister2:=getexplicitregister32(R_ECX);
  572. emit_ref_reg(A_MOV,S_L,newreference(right.location.reference),
  573. hregister2);
  574. end;
  575. end
  576. else
  577. hregister2:=right.location.register;
  578. { left operator is already in a register }
  579. { hence are both in a register }
  580. { is it in the case ECX ? }
  581. if (hregister1=R_ECX) then
  582. begin
  583. { then only swap }
  584. emit_reg_reg(A_XCHG,S_L,hregister1,hregister2);
  585. hregister3:=hregister1;
  586. hregister1:=hregister2;
  587. hregister2:=hregister3;
  588. end
  589. { if second operator not in ECX ? }
  590. else if (hregister2<>R_ECX) then
  591. begin
  592. { ECX occupied then push it }
  593. if not (R_ECX in unused) then
  594. begin
  595. popecx:=true;
  596. emit_reg(A_PUSH,S_L,R_ECX);
  597. end;
  598. emit_reg_reg(A_MOV,S_L,hregister2,R_ECX);
  599. end;
  600. ungetregister32(hregister2);
  601. { right operand is in ECX }
  602. emit_reg_reg(op,S_L,R_CL,hregister1);
  603. { maybe ECX back }
  604. if popecx then
  605. emit_reg(A_POP,S_L,R_ECX);
  606. location.register:=hregister1;
  607. end;
  608. end;
  609. end;
  610. {*****************************************************************************
  611. Ti386UNARYMINUSNODE
  612. *****************************************************************************}
  613. procedure ti386unaryminusnode.pass_2;
  614. {$ifdef SUPPORT_MMX}
  615. procedure do_mmx_neg;
  616. var
  617. op : tasmop;
  618. begin
  619. location.loc:=LOC_MMXREGISTER;
  620. if cs_mmx_saturation in aktlocalswitches then
  621. case mmx_type(resulttype) of
  622. mmxs8bit:
  623. op:=A_PSUBSB;
  624. mmxu8bit:
  625. op:=A_PSUBUSB;
  626. mmxs16bit,mmxfixed16:
  627. op:=A_PSUBSW;
  628. mmxu16bit:
  629. op:=A_PSUBUSW;
  630. end
  631. else
  632. case mmx_type(resulttype) of
  633. mmxs8bit,mmxu8bit:
  634. op:=A_PSUBB;
  635. mmxs16bit,mmxu16bit,mmxfixed16:
  636. op:=A_PSUBW;
  637. mmxs32bit,mmxu32bit:
  638. op:=A_PSUBD;
  639. end;
  640. emit_reg_reg(op,S_NO,location.register,R_MM7);
  641. emit_reg_reg(A_MOVQ,S_NO,R_MM7,location.register);
  642. end;
  643. {$endif}
  644. begin
  645. if is_64bitint(left.resulttype) then
  646. begin
  647. secondpass(left);
  648. clear_location(location);
  649. location.loc:=LOC_REGISTER;
  650. case left.location.loc of
  651. LOC_REGISTER :
  652. begin
  653. location.registerlow:=left.location.registerlow;
  654. location.registerhigh:=left.location.registerhigh;
  655. end;
  656. LOC_CREGISTER :
  657. begin
  658. location.registerlow:=getregister32;
  659. location.registerhigh:=getregister32;
  660. emit_reg_reg(A_MOV,S_L,left.location.registerlow,location.registerlow);
  661. emit_reg_reg(A_MOV,S_L,left.location.registerhigh,location.registerhigh);
  662. end;
  663. LOC_REFERENCE,LOC_MEM :
  664. begin
  665. del_reference(left.location.reference);
  666. location.registerlow:=getregister32;
  667. location.registerhigh:=getregister32;
  668. emit_mov_ref_reg64(left.location.reference,
  669. location.registerlow,
  670. location.registerhigh);
  671. end;
  672. end;
  673. {
  674. emit_reg(A_NEG,S_L,location.registerlow);
  675. emit_const_reg(A_ADC,S_L,0,location.registerhigh);
  676. emit_reg(A_NEG,S_L,location.registerhigh);
  677. }
  678. emit_reg(A_NOT,S_L,location.registerhigh);
  679. emit_reg(A_NEG,S_L,location.registerlow);
  680. emit_const_reg(A_SBB,S_L,-1,location.registerhigh);
  681. end
  682. else
  683. begin
  684. secondpass(left);
  685. location.loc:=LOC_REGISTER;
  686. case left.location.loc of
  687. LOC_REGISTER:
  688. begin
  689. location.register:=left.location.register;
  690. emit_reg(A_NEG,S_L,location.register);
  691. end;
  692. LOC_CREGISTER:
  693. begin
  694. location.register:=getregister32;
  695. emit_reg_reg(A_MOV,S_L,location.register,
  696. location.register);
  697. emit_reg(A_NEG,S_L,location.register);
  698. end;
  699. {$ifdef SUPPORT_MMX}
  700. LOC_MMXREGISTER:
  701. begin
  702. set_location(location,left.location);
  703. emit_reg_reg(A_PXOR,S_NO,R_MM7,R_MM7);
  704. do_mmx_neg;
  705. end;
  706. LOC_CMMXREGISTER:
  707. begin
  708. location.register:=getregistermmx;
  709. emit_reg_reg(A_PXOR,S_NO,R_MM7,R_MM7);
  710. emit_reg_reg(A_MOVQ,S_NO,left.location.register,
  711. location.register);
  712. do_mmx_neg;
  713. end;
  714. {$endif SUPPORT_MMX}
  715. LOC_REFERENCE,LOC_MEM:
  716. begin
  717. del_reference(left.location.reference);
  718. if (left.resulttype^.deftype=floatdef) and
  719. (pfloatdef(left.resulttype)^.typ<>f32bit) then
  720. begin
  721. location.loc:=LOC_FPU;
  722. floatload(pfloatdef(left.resulttype)^.typ,
  723. left.location.reference);
  724. emit_none(A_FCHS,S_NO);
  725. end
  726. {$ifdef SUPPORT_MMX}
  727. else if (cs_mmx in aktlocalswitches) and is_mmx_able_array(left.resulttype) then
  728. begin
  729. location.register:=getregistermmx;
  730. emit_reg_reg(A_PXOR,S_NO,R_MM7,R_MM7);
  731. emit_ref_reg(A_MOVQ,S_NO,
  732. newreference(left.location.reference),
  733. location.register);
  734. do_mmx_neg;
  735. end
  736. {$endif SUPPORT_MMX}
  737. else
  738. begin
  739. location.register:=getregister32;
  740. emit_ref_reg(A_MOV,S_L,
  741. newreference(left.location.reference),
  742. location.register);
  743. emit_reg(A_NEG,S_L,location.register);
  744. end;
  745. end;
  746. LOC_FPU:
  747. begin
  748. location.loc:=LOC_FPU;
  749. emit_none(A_FCHS,S_NO);
  750. end;
  751. LOC_CFPUREGISTER:
  752. begin
  753. emit_reg(A_FLD,S_NO,
  754. correct_fpuregister(left.location.register,fpuvaroffset));
  755. inc(fpuvaroffset);
  756. location.loc:=LOC_FPU;
  757. emit_none(A_FCHS,S_NO);
  758. end;
  759. end;
  760. end;
  761. { Here was a problem... }
  762. { Operand to be negated always }
  763. { seems to be converted to signed }
  764. { 32-bit before doing neg!! }
  765. { So this is useless... }
  766. { that's not true: -2^31 gives an overflow error if it is negaded (FK) }
  767. { emitoverflowcheck(p);}
  768. end;
  769. {*****************************************************************************
  770. TI386NOTNODE
  771. *****************************************************************************}
  772. procedure ti386notnode.pass_2;
  773. const
  774. flagsinvers : array[F_E..F_BE] of tresflags =
  775. (F_NE,F_E,F_LE,F_GE,F_L,F_G,F_NC,F_C,
  776. F_BE,F_B,F_AE,F_A);
  777. var
  778. hl : pasmlabel;
  779. opsize : topsize;
  780. begin
  781. if is_boolean(resulttype) then
  782. begin
  783. opsize:=def_opsize(resulttype);
  784. { the second pass could change the location of left }
  785. { if it is a register variable, so we've to do }
  786. { this before the case statement }
  787. if left.location.loc in [LOC_REFERENCE,LOC_MEM,
  788. LOC_FLAGS,LOC_REGISTER,LOC_CREGISTER] then
  789. secondpass(left);
  790. case left.location.loc of
  791. LOC_JUMP :
  792. begin
  793. hl:=truelabel;
  794. truelabel:=falselabel;
  795. falselabel:=hl;
  796. secondpass(left);
  797. maketojumpbool(left);
  798. hl:=truelabel;
  799. truelabel:=falselabel;
  800. falselabel:=hl;
  801. end;
  802. LOC_FLAGS :
  803. location.resflags:=flagsinvers[left.location.resflags];
  804. LOC_REGISTER :
  805. begin
  806. {location.register:=left.location.register;
  807. emit_const_reg(A_XOR,opsize,1,location.register);}
  808. location.loc:=LOC_FLAGS;
  809. location.resflags:=F_E;
  810. emit_reg_reg(A_TEST,opsize,
  811. left.location.register,left.location.register);
  812. ungetregister(left.location.register);
  813. end;
  814. LOC_CREGISTER :
  815. begin
  816. clear_location(location);
  817. location.loc:=LOC_REGISTER;
  818. location.register:=def_getreg(resulttype);
  819. emit_reg_reg(A_MOV,opsize,left.location.register,location.register);
  820. emit_reg_reg(A_TEST,opsize,location.register,location.register);
  821. ungetregister(location.register);
  822. location.loc:=LOC_FLAGS;
  823. location.resflags:=F_E;
  824. end;
  825. LOC_REFERENCE,
  826. LOC_MEM :
  827. begin
  828. clear_location(location);
  829. location.loc:=LOC_REGISTER;
  830. del_reference(left.location.reference);
  831. { this was placed before del_ref => internaalerror(10) }
  832. location.register:=def_getreg(resulttype);
  833. emit_ref_reg(A_MOV,opsize,
  834. newreference(left.location.reference),location.register);
  835. emit_reg_reg(A_TEST,opsize,location.register,location.register);
  836. ungetregister(location.register);
  837. location.loc:=LOC_FLAGS;
  838. location.resflags:=F_E;
  839. end;
  840. end;
  841. end
  842. {$ifdef SUPPORT_MMX}
  843. else
  844. if (cs_mmx in aktlocalswitches) and is_mmx_able_array(left.resulttype) then
  845. begin
  846. secondpass(left);
  847. location.loc:=LOC_MMXREGISTER;
  848. { prepare EDI }
  849. {$ifndef noAllocEdi}
  850. getexplicitregister32(R_EDI);
  851. {$endif noAllocEdi}
  852. emit_const_reg(A_MOV,S_L,$ffffffff,R_EDI);
  853. { load operand }
  854. case left.location.loc of
  855. LOC_MMXREGISTER:
  856. set_location(location,left.location);
  857. LOC_CMMXREGISTER:
  858. begin
  859. location.register:=getregistermmx;
  860. emit_reg_reg(A_MOVQ,S_NO,left.location.register,location.register);
  861. end;
  862. LOC_REFERENCE,LOC_MEM:
  863. begin
  864. del_reference(left.location.reference);
  865. location.register:=getregistermmx;
  866. emit_ref_reg(A_MOVQ,S_NO,
  867. newreference(left.location.reference),location.register);
  868. end;
  869. end;
  870. { load mask }
  871. emit_reg_reg(A_MOVD,S_NO,R_EDI,R_MM7);
  872. {$ifndef noAllocEdi}
  873. ungetregister32(R_EDI);
  874. {$endif noAllocEdi}
  875. { lower 32 bit }
  876. emit_reg_reg(A_PXOR,S_D,R_MM7,location.register);
  877. { shift mask }
  878. emit_const_reg(A_PSLLQ,S_NO,32,R_MM7);
  879. { higher 32 bit }
  880. emit_reg_reg(A_PXOR,S_D,R_MM7,location.register);
  881. end
  882. {$endif SUPPORT_MMX}
  883. else if is_64bitint(left.resulttype) then
  884. begin
  885. secondpass(left);
  886. clear_location(location);
  887. location.loc:=LOC_REGISTER;
  888. case left.location.loc of
  889. LOC_REGISTER :
  890. begin
  891. location.registerlow:=left.location.registerlow;
  892. location.registerhigh:=left.location.registerhigh;
  893. emit_reg(A_NOT,S_L,location.registerlow);
  894. emit_reg(A_NOT,S_L,location.registerhigh);
  895. end;
  896. LOC_CREGISTER :
  897. begin
  898. location.registerlow:=getregister32;
  899. location.registerhigh:=getregister32;
  900. emit_reg_reg(A_MOV,S_L,left.location.registerlow,location.registerlow);
  901. emit_reg_reg(A_MOV,S_L,left.location.registerhigh,location.registerhigh);
  902. emit_reg(A_NOT,S_L,location.registerlow);
  903. emit_reg(A_NOT,S_L,location.registerhigh);
  904. end;
  905. LOC_REFERENCE,LOC_MEM :
  906. begin
  907. del_reference(left.location.reference);
  908. location.registerlow:=getregister32;
  909. location.registerhigh:=getregister32;
  910. emit_mov_ref_reg64(left.location.reference,
  911. location.registerlow,
  912. location.registerhigh);
  913. emit_reg(A_NOT,S_L,location.registerlow);
  914. emit_reg(A_NOT,S_L,location.registerhigh);
  915. end;
  916. end;
  917. end
  918. else
  919. begin
  920. secondpass(left);
  921. clear_location(location);
  922. location.loc:=LOC_REGISTER;
  923. case left.location.loc of
  924. LOC_REGISTER :
  925. begin
  926. location.register:=left.location.register;
  927. emit_reg(A_NOT,S_L,location.register);
  928. end;
  929. LOC_CREGISTER :
  930. begin
  931. location.register:=getregister32;
  932. emit_reg_reg(A_MOV,S_L,left.location.register,location.register);
  933. emit_reg(A_NOT,S_L,location.register);
  934. end;
  935. LOC_REFERENCE,LOC_MEM :
  936. begin
  937. del_reference(left.location.reference);
  938. location.register:=getregister32;
  939. emit_ref_reg(A_MOV,S_L,
  940. newreference(left.location.reference),location.register);
  941. emit_reg(A_NOT,S_L,location.register);
  942. end;
  943. end;
  944. end;
  945. end;
  946. begin
  947. cmoddivnode:=ti386moddivnode;
  948. cshlshrnode:=ti386shlshrnode;
  949. cunaryminusnode:=ti386unaryminusnode;
  950. cnotnode:=ti386notnode;
  951. end.
  952. {
  953. $Log$
  954. Revision 1.2 2000-09-24 15:06:18 peter
  955. * use defines.inc
  956. Revision 1.1 2000/09/22 22:24:37 florian
  957. * initial revision
  958. }