n386mat.pas 41 KB

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