n386mat.pas 41 KB

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