cg386mat.pas 41 KB

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