n386mat.pas 44 KB

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