n386mat.pas 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 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 fpcdefs.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,aasmbase,aasmtai,aasmcpu,defbase,
  42. cginfo,cgbase,pass_1,pass_2,
  43. ncon,
  44. cpubase,
  45. cga,tgobj,ncgutil,cgobj,rgobj,rgcpu;
  46. {*****************************************************************************
  47. TI386MODDIVNODE
  48. *****************************************************************************}
  49. procedure ti386moddivnode.pass_2;
  50. var
  51. hreg1 : tregister;
  52. hreg2 : tregister;
  53. shrdiv,popeax,popedx : boolean;
  54. power : longint;
  55. hl : tasmlabel;
  56. pushedregs : tmaybesave;
  57. begin
  58. shrdiv := false;
  59. secondpass(left);
  60. if codegenerror then
  61. exit;
  62. maybe_save(exprasmlist,right.registers32,left.location,pushedregs);
  63. secondpass(right);
  64. maybe_restore(exprasmlist,left.location,pushedregs);
  65. if codegenerror then
  66. exit;
  67. location_copy(location,left.location);
  68. if is_64bitint(resulttype.def) then
  69. begin
  70. { should be handled in pass_1 (JM) }
  71. internalerror(200109052);
  72. end
  73. else
  74. begin
  75. { put numerator in register }
  76. location_force_reg(exprasmlist,left.location,OS_INT,false);
  77. hreg1:=left.location.register;
  78. if (nodetype=divn) and
  79. (right.nodetype=ordconstn) and
  80. ispowerof2(tordconstnode(right).value,power) then
  81. Begin
  82. shrdiv := true;
  83. { for signed numbers, the numerator must be adjusted before the
  84. shift instruction, but not wih unsigned numbers! Otherwise,
  85. "Cardinal($ffffffff) div 16" overflows! (JM) }
  86. If is_signed(left.resulttype.def) Then
  87. Begin
  88. If (aktOptProcessor <> class386) and
  89. not(CS_LittleSize in aktglobalswitches) then
  90. { use a sequence without jumps, saw this in
  91. comp.compilers (JM) }
  92. begin
  93. { no jumps, but more operations }
  94. if (hreg1 = R_EAX) and
  95. (R_EDX in rg.unusedregsint) then
  96. begin
  97. hreg2 := rg.getexplicitregisterint(exprasmlist,R_EDX);
  98. emit_none(A_CDQ,S_NO);
  99. end
  100. else
  101. begin
  102. rg.getexplicitregisterint(exprasmlist,R_EDI);
  103. hreg2 := R_EDI;
  104. emit_reg_reg(A_MOV,S_L,hreg1,R_EDI);
  105. { if the left value is signed, R_EDI := $ffffffff,
  106. otherwise 0 }
  107. emit_const_reg(A_SAR,S_L,31,R_EDI);
  108. { if signed, R_EDI := right value-1, otherwise 0 }
  109. end;
  110. emit_const_reg(A_AND,S_L,tordconstnode(right).value-1,hreg2);
  111. { add to the left value }
  112. emit_reg_reg(A_ADD,S_L,hreg2,hreg1);
  113. { release EDX if we used it }
  114. { also releas EDI }
  115. rg.ungetregisterint(exprasmlist,hreg2);
  116. { do the shift }
  117. emit_const_reg(A_SAR,S_L,power,hreg1);
  118. end
  119. else
  120. begin
  121. { a jump, but less operations }
  122. emit_reg_reg(A_TEST,S_L,hreg1,hreg1);
  123. getlabel(hl);
  124. emitjmp(C_NS,hl);
  125. if power=1 then
  126. emit_reg(A_INC,S_L,hreg1)
  127. else
  128. emit_const_reg(A_ADD,S_L,tordconstnode(right).value-1,hreg1);
  129. cg.a_label(exprasmlist,hl);
  130. emit_const_reg(A_SAR,S_L,power,hreg1);
  131. end
  132. End
  133. Else
  134. emit_const_reg(A_SHR,S_L,power,hreg1);
  135. End
  136. else
  137. begin
  138. { bring denominator to EDI }
  139. { EDI is always free, it's }
  140. { only used for temporary }
  141. { purposes }
  142. rg.getexplicitregisterint(exprasmlist,R_EDI);
  143. if right.location.loc<>LOC_CREGISTER then
  144. location_release(exprasmlist,right.location);
  145. cg.a_load_loc_reg(exprasmlist,right.location,R_EDI);
  146. popedx:=false;
  147. popeax:=false;
  148. if hreg1=R_EDX then
  149. begin
  150. if not(R_EAX in rg.unusedregsint) then
  151. begin
  152. emit_reg(A_PUSH,S_L,R_EAX);
  153. popeax:=true;
  154. end
  155. else
  156. rg.getexplicitregisterint(exprasmlist,R_EAX);
  157. emit_reg_reg(A_MOV,S_L,R_EDX,R_EAX);
  158. end
  159. else
  160. begin
  161. if not(R_EDX in rg.unusedregsint) then
  162. begin
  163. emit_reg(A_PUSH,S_L,R_EDX);
  164. popedx:=true;
  165. end
  166. else
  167. rg.getexplicitregisterint(exprasmlist,R_EDX);
  168. if hreg1<>R_EAX then
  169. begin
  170. if not(R_EAX in rg.unusedregsint) then
  171. begin
  172. emit_reg(A_PUSH,S_L,R_EAX);
  173. popeax:=true;
  174. end
  175. else
  176. rg.getexplicitregisterint(exprasmlist,R_EAX);
  177. emit_reg_reg(A_MOV,S_L,hreg1,R_EAX);
  178. end;
  179. end;
  180. { sign extension depends on the left type }
  181. if torddef(left.resulttype.def).typ=u32bit then
  182. emit_reg_reg(A_XOR,S_L,R_EDX,R_EDX)
  183. else
  184. emit_none(A_CDQ,S_NO);
  185. { division depends on the right type }
  186. if torddef(right.resulttype.def).typ=u32bit then
  187. emit_reg(A_DIV,S_L,R_EDI)
  188. else
  189. emit_reg(A_IDIV,S_L,R_EDI);
  190. rg.ungetregisterint(exprasmlist,R_EDI);
  191. if nodetype=divn then
  192. begin
  193. if not popedx and (hreg1 <> R_EDX) then
  194. rg.ungetregister(exprasmlist,R_EDX);
  195. { if result register is busy then copy }
  196. if popeax then
  197. begin
  198. if hreg1=R_EAX then
  199. internalerror(112);
  200. emit_reg_reg(A_MOV,S_L,R_EAX,hreg1)
  201. end
  202. else
  203. if hreg1<>R_EAX then
  204. Begin
  205. rg.ungetregisterint(exprasmlist,hreg1);
  206. { no need to allocate eax, that's already done before }
  207. { the div (JM) }
  208. hreg1 := R_EAX;
  209. end;
  210. end
  211. else
  212. begin
  213. if not popeax and (hreg1 <> R_EAX)then
  214. rg.ungetregister(exprasmlist,R_EAX);
  215. if popedx then
  216. {the mod was done by an (i)div (so the result is now in
  217. edx), but edx was occupied prior to the division, so
  218. move the result into a safe place (JM)}
  219. emit_reg_reg(A_MOV,S_L,R_EDX,hreg1)
  220. else
  221. Begin
  222. if hreg1 <> R_EDX then
  223. rg.ungetregisterint(exprasmlist,hreg1);
  224. hreg1 := R_EDX
  225. End;
  226. end;
  227. if popeax then
  228. emit_reg(A_POP,S_L,R_EAX);
  229. if popedx then
  230. emit_reg(A_POP,S_L,R_EDX);
  231. end;
  232. If not(shrdiv) then
  233. { shrdiv only use hreg1 (which is already in usedinproc, }
  234. { since it was acquired with getregister), the others also }
  235. { use both EAX and EDX (JM) }
  236. Begin
  237. include(rg.usedinproc,R_EAX);
  238. include(rg.usedinproc,R_EDX);
  239. End;
  240. location_reset(location,LOC_REGISTER,OS_INT);
  241. location.register:=hreg1;
  242. end;
  243. end;
  244. {*****************************************************************************
  245. TI386SHLRSHRNODE
  246. *****************************************************************************}
  247. procedure ti386shlshrnode.pass_2;
  248. var
  249. hregister2,hregister3,
  250. hregisterhigh,hregisterlow : tregister;
  251. popecx : boolean;
  252. op : tasmop;
  253. l1,l2,l3 : tasmlabel;
  254. pushedregs : tmaybesave;
  255. begin
  256. popecx:=false;
  257. secondpass(left);
  258. maybe_save(exprasmlist,right.registers32,left.location,pushedregs);
  259. secondpass(right);
  260. maybe_restore(exprasmlist,left.location,pushedregs);
  261. { determine operator }
  262. case nodetype of
  263. shln: op:=A_SHL;
  264. shrn: op:=A_SHR;
  265. end;
  266. if is_64bitint(left.resulttype.def) then
  267. begin
  268. location_reset(location,LOC_REGISTER,OS_64);
  269. { load left operator in a register }
  270. location_force_reg(exprasmlist,left.location,OS_64,false);
  271. hregisterhigh:=left.location.registerhigh;
  272. hregisterlow:=left.location.registerlow;
  273. { shifting by a constant directly coded: }
  274. if (right.nodetype=ordconstn) then
  275. begin
  276. { shrd/shl works only for values <=31 !! }
  277. if tordconstnode(right).value>31 then
  278. begin
  279. if nodetype=shln then
  280. begin
  281. emit_reg_reg(A_XOR,S_L,hregisterhigh,
  282. hregisterhigh);
  283. if ((tordconstnode(right).value and 31) <> 0) then
  284. emit_const_reg(A_SHL,S_L,tordconstnode(right).value and 31,
  285. hregisterlow);
  286. end
  287. else
  288. begin
  289. emit_reg_reg(A_XOR,S_L,hregisterlow,
  290. hregisterlow);
  291. if ((tordconstnode(right).value and 31) <> 0) then
  292. emit_const_reg(A_SHR,S_L,tordconstnode(right).value and 31,
  293. hregisterhigh);
  294. end;
  295. location.registerhigh:=hregisterlow;
  296. location.registerlow:=hregisterhigh;
  297. end
  298. else
  299. begin
  300. if nodetype=shln then
  301. begin
  302. emit_const_reg_reg(A_SHLD,S_L,tordconstnode(right).value and 31,
  303. hregisterlow,hregisterhigh);
  304. emit_const_reg(A_SHL,S_L,tordconstnode(right).value and 31,
  305. hregisterlow);
  306. end
  307. else
  308. begin
  309. emit_const_reg_reg(A_SHRD,S_L,tordconstnode(right).value and 31,
  310. hregisterhigh,hregisterlow);
  311. emit_const_reg(A_SHR,S_L,tordconstnode(right).value and 31,
  312. hregisterhigh);
  313. end;
  314. location.registerlow:=hregisterlow;
  315. location.registerhigh:=hregisterhigh;
  316. end;
  317. end
  318. else
  319. begin
  320. { load right operators in a register }
  321. if right.location.loc<>LOC_REGISTER then
  322. begin
  323. if right.location.loc<>LOC_CREGISTER then
  324. location_release(exprasmlist,right.location);
  325. hregister2:=rg.getexplicitregisterint(exprasmlist,R_ECX);
  326. cg.a_load_loc_reg(exprasmlist,right.location,hregister2);
  327. end
  328. else
  329. hregister2:=right.location.register;
  330. { left operator is already in a register }
  331. { hence are both in a register }
  332. { is it in the case ECX ? }
  333. if (hregisterlow=R_ECX) then
  334. begin
  335. { then only swap }
  336. emit_reg_reg(A_XCHG,S_L,hregisterlow,hregister2);
  337. hregister3:=hregisterlow;
  338. hregisterlow:=hregister2;
  339. hregister2:=hregister3;
  340. end
  341. else if (hregisterhigh=R_ECX) then
  342. begin
  343. { then only swap }
  344. emit_reg_reg(A_XCHG,S_L,hregisterhigh,hregister2);
  345. hregister3:=hregisterhigh;
  346. hregisterhigh:=hregister2;
  347. hregister2:=hregister3;
  348. end
  349. { if second operator not in ECX ? }
  350. else if (hregister2<>R_ECX) then
  351. begin
  352. { ECX occupied then push it }
  353. if not (R_ECX in rg.unusedregsint) then
  354. begin
  355. popecx:=true;
  356. emit_reg(A_PUSH,S_L,R_ECX);
  357. end
  358. else
  359. rg.getexplicitregisterint(exprasmlist,R_ECX);
  360. emit_reg_reg(A_MOV,S_L,hregister2,R_ECX);
  361. end;
  362. if hregister2 <> R_ECX then
  363. rg.ungetregisterint(exprasmlist,hregister2);
  364. { the damned shift instructions work only til a count of 32 }
  365. { so we've to do some tricks here }
  366. if nodetype=shln then
  367. begin
  368. getlabel(l1);
  369. getlabel(l2);
  370. getlabel(l3);
  371. emit_const_reg(A_CMP,S_L,64,R_ECX);
  372. emitjmp(C_L,l1);
  373. emit_reg_reg(A_XOR,S_L,hregisterlow,hregisterlow);
  374. emit_reg_reg(A_XOR,S_L,hregisterhigh,hregisterhigh);
  375. cg.a_jmp_always(exprasmlist,l3);
  376. cg.a_label(exprasmlist,l1);
  377. emit_const_reg(A_CMP,S_L,32,R_ECX);
  378. emitjmp(C_L,l2);
  379. emit_const_reg(A_SUB,S_L,32,R_ECX);
  380. emit_reg_reg(A_SHL,S_L,R_CL,
  381. hregisterlow);
  382. emit_reg_reg(A_MOV,S_L,hregisterlow,hregisterhigh);
  383. emit_reg_reg(A_XOR,S_L,hregisterlow,hregisterlow);
  384. cg.a_jmp_always(exprasmlist,l3);
  385. cg.a_label(exprasmlist,l2);
  386. emit_reg_reg_reg(A_SHLD,S_L,R_CL,
  387. hregisterlow,hregisterhigh);
  388. emit_reg_reg(A_SHL,S_L,R_CL,
  389. hregisterlow);
  390. cg.a_label(exprasmlist,l3);
  391. end
  392. else
  393. begin
  394. getlabel(l1);
  395. getlabel(l2);
  396. getlabel(l3);
  397. emit_const_reg(A_CMP,S_L,64,R_ECX);
  398. emitjmp(C_L,l1);
  399. emit_reg_reg(A_XOR,S_L,hregisterlow,hregisterlow);
  400. emit_reg_reg(A_XOR,S_L,hregisterhigh,hregisterhigh);
  401. cg.a_jmp_always(exprasmlist,l3);
  402. cg.a_label(exprasmlist,l1);
  403. emit_const_reg(A_CMP,S_L,32,R_ECX);
  404. emitjmp(C_L,l2);
  405. emit_const_reg(A_SUB,S_L,32,R_ECX);
  406. emit_reg_reg(A_SHR,S_L,R_CL,
  407. hregisterhigh);
  408. emit_reg_reg(A_MOV,S_L,hregisterhigh,hregisterlow);
  409. emit_reg_reg(A_XOR,S_L,hregisterhigh,hregisterhigh);
  410. cg.a_jmp_always(exprasmlist,l3);
  411. cg.a_label(exprasmlist,l2);
  412. emit_reg_reg_reg(A_SHRD,S_L,R_CL,
  413. hregisterhigh,hregisterlow);
  414. emit_reg_reg(A_SHR,S_L,R_CL,
  415. hregisterhigh);
  416. cg.a_label(exprasmlist,l3);
  417. end;
  418. { maybe put ECX back }
  419. if popecx then
  420. emit_reg(A_POP,S_L,R_ECX)
  421. else
  422. rg.ungetregisterint(exprasmlist,R_ECX);
  423. location.registerlow:=hregisterlow;
  424. location.registerhigh:=hregisterhigh;
  425. end;
  426. end
  427. else
  428. begin
  429. { load left operators in a register }
  430. location_copy(location,left.location);
  431. location_force_reg(exprasmlist,location,OS_INT,false);
  432. { shifting by a constant directly coded: }
  433. if (right.nodetype=ordconstn) then
  434. begin
  435. { l shl 32 should 0 imho, but neither TP nor Delphi do it in this way (FK)
  436. if right.value<=31 then
  437. }
  438. emit_const_reg(op,S_L,tordconstnode(right).value and 31,
  439. location.register);
  440. {
  441. else
  442. emit_reg_reg(A_XOR,S_L,hregister1,
  443. hregister1);
  444. }
  445. end
  446. else
  447. begin
  448. { load right operators in a register }
  449. if right.location.loc<>LOC_REGISTER then
  450. begin
  451. if right.location.loc<>LOC_CREGISTER then
  452. location_release(exprasmlist,right.location);
  453. hregister2:=rg.getexplicitregisterint(exprasmlist,R_ECX);
  454. cg.a_load_loc_reg(exprasmlist,right.location,hregister2);
  455. end
  456. else
  457. hregister2:=right.location.register;
  458. { left operator is already in a register }
  459. { hence are both in a register }
  460. { is it in the case ECX ? }
  461. if (location.register=R_ECX) then
  462. begin
  463. { then only swap }
  464. emit_reg_reg(A_XCHG,S_L,location.register,hregister2);
  465. hregister3:=location.register;
  466. location.register:=hregister2;
  467. hregister2:=hregister3;
  468. end
  469. { if second operator not in ECX ? }
  470. else if (hregister2<>R_ECX) then
  471. begin
  472. { ECX occupied then push it }
  473. if not (R_ECX in rg.unusedregsint) then
  474. begin
  475. popecx:=true;
  476. emit_reg(A_PUSH,S_L,R_ECX);
  477. end
  478. else
  479. rg.getexplicitregisterint(exprasmlist,R_ECX);
  480. emit_reg_reg(A_MOV,S_L,hregister2,R_ECX);
  481. end;
  482. rg.ungetregisterint(exprasmlist,hregister2);
  483. { right operand is in ECX }
  484. emit_reg_reg(op,S_L,R_CL,location.register);
  485. { maybe ECX back }
  486. if popecx then
  487. emit_reg(A_POP,S_L,R_ECX)
  488. else
  489. rg.ungetregisterint(exprasmlist,R_ECX);
  490. end;
  491. end;
  492. end;
  493. {*****************************************************************************
  494. TI386UNARYMINUSNODE
  495. *****************************************************************************}
  496. function ti386unaryminusnode.pass_1 : tnode;
  497. begin
  498. result:=nil;
  499. firstpass(left);
  500. if codegenerror then
  501. exit;
  502. registers32:=left.registers32;
  503. registersfpu:=left.registersfpu;
  504. {$ifdef SUPPORT_MMX}
  505. registersmmx:=left.registersmmx;
  506. {$endif SUPPORT_MMX}
  507. if (left.resulttype.def.deftype=floatdef) then
  508. begin
  509. if (registersfpu < 1) then
  510. registersfpu := 1;
  511. location.loc:=LOC_FPUREGISTER;
  512. end
  513. {$ifdef SUPPORT_MMX}
  514. else if (cs_mmx in aktlocalswitches) and
  515. is_mmx_able_array(left.resulttype.def) then
  516. begin
  517. if (left.location.loc<>LOC_MMXREGISTER) and
  518. (registersmmx<1) then
  519. registersmmx:=1;
  520. end
  521. {$endif SUPPORT_MMX}
  522. else if is_64bitint(left.resulttype.def) then
  523. begin
  524. if (left.location.loc<>LOC_REGISTER) and
  525. (registers32<2) then
  526. registers32:=2;
  527. location.loc:=LOC_REGISTER;
  528. end
  529. else if (left.resulttype.def.deftype=orddef) then
  530. begin
  531. if (left.location.loc<>LOC_REGISTER) and
  532. (registers32<1) then
  533. registers32:=1;
  534. location.loc:=LOC_REGISTER;
  535. end;
  536. end;
  537. procedure ti386unaryminusnode.pass_2;
  538. {$ifdef SUPPORT_MMX}
  539. procedure do_mmx_neg;
  540. var
  541. op : tasmop;
  542. begin
  543. location_reset(location,LOC_MMXREGISTER,OS_NO);
  544. if cs_mmx_saturation in aktlocalswitches then
  545. case mmx_type(resulttype.def) of
  546. mmxs8bit:
  547. op:=A_PSUBSB;
  548. mmxu8bit:
  549. op:=A_PSUBUSB;
  550. mmxs16bit,mmxfixed16:
  551. op:=A_PSUBSW;
  552. mmxu16bit:
  553. op:=A_PSUBUSW;
  554. end
  555. else
  556. case mmx_type(resulttype.def) of
  557. mmxs8bit,mmxu8bit:
  558. op:=A_PSUBB;
  559. mmxs16bit,mmxu16bit,mmxfixed16:
  560. op:=A_PSUBW;
  561. mmxs32bit,mmxu32bit:
  562. op:=A_PSUBD;
  563. end;
  564. emit_reg_reg(op,S_NO,location.register,R_MM7);
  565. emit_reg_reg(A_MOVQ,S_NO,R_MM7,location.register);
  566. end;
  567. {$endif}
  568. begin
  569. if is_64bitint(left.resulttype.def) then
  570. begin
  571. secondpass(left);
  572. { load left operator in a register }
  573. location_copy(location,left.location);
  574. location_force_reg(exprasmlist,location,OS_64,false);
  575. emit_reg(A_NOT,S_L,location.registerhigh);
  576. emit_reg(A_NEG,S_L,location.registerlow);
  577. emit_const_reg(A_SBB,S_L,-1,location.registerhigh);
  578. end
  579. else
  580. begin
  581. secondpass(left);
  582. location_reset(location,LOC_REGISTER,OS_INT);
  583. case left.location.loc of
  584. LOC_REGISTER:
  585. begin
  586. location.register:=left.location.register;
  587. emit_reg(A_NEG,S_L,location.register);
  588. end;
  589. LOC_CREGISTER:
  590. begin
  591. location.register:=rg.getregisterint(exprasmlist);
  592. emit_reg_reg(A_MOV,S_L,location.register,
  593. location.register);
  594. emit_reg(A_NEG,S_L,location.register);
  595. end;
  596. {$ifdef SUPPORT_MMX}
  597. LOC_MMXREGISTER:
  598. begin
  599. location_copy(location,left.location);
  600. emit_reg_reg(A_PXOR,S_NO,R_MM7,R_MM7);
  601. do_mmx_neg;
  602. end;
  603. LOC_CMMXREGISTER:
  604. begin
  605. location.register:=rg.getregistermm(exprasmlist);
  606. emit_reg_reg(A_PXOR,S_NO,R_MM7,R_MM7);
  607. emit_reg_reg(A_MOVQ,S_NO,left.location.register,
  608. location.register);
  609. do_mmx_neg;
  610. end;
  611. {$endif SUPPORT_MMX}
  612. LOC_REFERENCE,
  613. LOC_CREFERENCE:
  614. begin
  615. reference_release(exprasmlist,left.location.reference);
  616. if (left.resulttype.def.deftype=floatdef) then
  617. begin
  618. location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
  619. location.register:=R_ST;
  620. cg.a_loadfpu_ref_reg(exprasmlist,
  621. def_cgsize(left.resulttype.def),
  622. left.location.reference,R_ST);
  623. emit_none(A_FCHS,S_NO);
  624. end
  625. {$ifdef SUPPORT_MMX}
  626. else if (cs_mmx in aktlocalswitches) and is_mmx_able_array(left.resulttype.def) then
  627. begin
  628. location.register:=rg.getregistermm(exprasmlist);
  629. emit_reg_reg(A_PXOR,S_NO,R_MM7,R_MM7);
  630. emit_ref_reg(A_MOVQ,S_NO,left.location.reference,location.register);
  631. do_mmx_neg;
  632. end
  633. {$endif SUPPORT_MMX}
  634. else
  635. begin
  636. location.register:=rg.getregisterint(exprasmlist);
  637. emit_ref_reg(A_MOV,S_L,left.location.reference,location.register);
  638. emit_reg(A_NEG,S_L,location.register);
  639. end;
  640. end;
  641. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  642. begin
  643. { "load st,st" is ignored by the code generator }
  644. cg.a_loadfpu_reg_reg(exprasmlist,left.location.register,R_ST);
  645. location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
  646. location.register:=R_ST;
  647. emit_none(A_FCHS,S_NO);
  648. end;
  649. else
  650. internalerror(200203225);
  651. end;
  652. end;
  653. { Here was a problem... }
  654. { Operand to be negated always }
  655. { seems to be converted to signed }
  656. { 32-bit before doing neg!! }
  657. { So this is useless... }
  658. { that's not true: -2^31 gives an overflow error if it is negaded (FK) }
  659. { emitoverflowcheck(p);}
  660. end;
  661. {*****************************************************************************
  662. TI386NOTNODE
  663. *****************************************************************************}
  664. procedure ti386notnode.pass_2;
  665. const
  666. flagsinvers : array[F_E..F_BE] of tresflags =
  667. (F_NE,F_E,F_LE,F_GE,F_L,F_G,F_NC,F_C,
  668. F_BE,F_B,F_AE,F_A);
  669. var
  670. hl : tasmlabel;
  671. opsize : topsize;
  672. begin
  673. if is_boolean(resulttype.def) then
  674. begin
  675. opsize:=def_opsize(resulttype.def);
  676. { the second pass could change the location of left }
  677. { if it is a register variable, so we've to do }
  678. { this before the case statement }
  679. if left.location.loc<>LOC_JUMP then
  680. secondpass(left);
  681. case left.location.loc of
  682. LOC_JUMP :
  683. begin
  684. location_reset(location,LOC_JUMP,OS_NO);
  685. hl:=truelabel;
  686. truelabel:=falselabel;
  687. falselabel:=hl;
  688. secondpass(left);
  689. maketojumpbool(exprasmlist,left,lr_load_regvars);
  690. hl:=truelabel;
  691. truelabel:=falselabel;
  692. falselabel:=hl;
  693. end;
  694. LOC_FLAGS :
  695. begin
  696. location_release(exprasmlist,left.location);
  697. location_reset(location,LOC_FLAGS,OS_NO);
  698. location.resflags:=flagsinvers[left.location.resflags];
  699. end;
  700. LOC_CONSTANT,
  701. LOC_REGISTER,
  702. LOC_CREGISTER,
  703. LOC_REFERENCE,
  704. LOC_CREFERENCE :
  705. begin
  706. location_force_reg(exprasmlist,left.location,def_cgsize(resulttype.def),true);
  707. location_release(exprasmlist,left.location);
  708. emit_reg_reg(A_TEST,opsize,left.location.register,left.location.register);
  709. location_reset(location,LOC_FLAGS,OS_NO);
  710. location.resflags:=F_E;
  711. end;
  712. else
  713. internalerror(200203224);
  714. end;
  715. end
  716. {$ifdef SUPPORT_MMX}
  717. else
  718. if (cs_mmx in aktlocalswitches) and is_mmx_able_array(left.resulttype.def) then
  719. begin
  720. secondpass(left);
  721. location_reset(location,LOC_MMXREGISTER,OS_NO);
  722. { prepare EDI }
  723. rg.getexplicitregisterint(exprasmlist,R_EDI);
  724. emit_const_reg(A_MOV,S_L,longint($ffffffff),R_EDI);
  725. { load operand }
  726. case left.location.loc of
  727. LOC_MMXREGISTER:
  728. location_copy(location,left.location);
  729. LOC_CMMXREGISTER:
  730. begin
  731. location.register:=rg.getregistermm(exprasmlist);
  732. emit_reg_reg(A_MOVQ,S_NO,left.location.register,location.register);
  733. end;
  734. LOC_REFERENCE,
  735. LOC_CREFERENCE:
  736. begin
  737. location_release(exprasmlist,left.location);
  738. location.register:=rg.getregistermm(exprasmlist);
  739. emit_ref_reg(A_MOVQ,S_NO,left.location.reference,location.register);
  740. end;
  741. end;
  742. { load mask }
  743. emit_reg_reg(A_MOVD,S_NO,R_EDI,R_MM7);
  744. rg.ungetregisterint(exprasmlist,R_EDI);
  745. { lower 32 bit }
  746. emit_reg_reg(A_PXOR,S_D,R_MM7,location.register);
  747. { shift mask }
  748. emit_const_reg(A_PSLLQ,S_NO,32,R_MM7);
  749. { higher 32 bit }
  750. emit_reg_reg(A_PXOR,S_D,R_MM7,location.register);
  751. end
  752. {$endif SUPPORT_MMX}
  753. else if is_64bitint(left.resulttype.def) then
  754. begin
  755. secondpass(left);
  756. location_copy(location,left.location);
  757. location_force_reg(exprasmlist,location,OS_64,false);
  758. emit_reg(A_NOT,S_L,location.registerlow);
  759. emit_reg(A_NOT,S_L,location.registerhigh);
  760. end
  761. else
  762. begin
  763. secondpass(left);
  764. location_copy(location,left.location);
  765. location_force_reg(exprasmlist,location,def_cgsize(resulttype.def),false);
  766. opsize:=def_opsize(resulttype.def);
  767. emit_reg(A_NOT,opsize,location.register);
  768. end;
  769. end;
  770. begin
  771. cmoddivnode:=ti386moddivnode;
  772. cshlshrnode:=ti386shlshrnode;
  773. cunaryminusnode:=ti386unaryminusnode;
  774. cnotnode:=ti386notnode;
  775. end.
  776. {
  777. $Log$
  778. Revision 1.33 2002-07-20 11:58:02 florian
  779. * types.pas renamed to defbase.pas because D6 contains a types
  780. unit so this would conflicts if D6 programms are compiled
  781. + Willamette/SSE2 instructions to assembler added
  782. Revision 1.32 2002/07/01 18:46:33 peter
  783. * internal linker
  784. * reorganized aasm layer
  785. Revision 1.31 2002/05/18 13:34:25 peter
  786. * readded missing revisions
  787. Revision 1.30 2002/05/16 19:46:51 carl
  788. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  789. + try to fix temp allocation (still in ifdef)
  790. + generic constructor calls
  791. + start of tassembler / tmodulebase class cleanup
  792. Revision 1.28 2002/05/13 19:54:38 peter
  793. * removed n386ld and n386util units
  794. * maybe_save/maybe_restore added instead of the old maybe_push
  795. Revision 1.27 2002/05/12 16:53:17 peter
  796. * moved entry and exitcode to ncgutil and cgobj
  797. * foreach gets extra argument for passing local data to the
  798. iterator function
  799. * -CR checks also class typecasts at runtime by changing them
  800. into as
  801. * fixed compiler to cycle with the -CR option
  802. * fixed stabs with elf writer, finally the global variables can
  803. be watched
  804. * removed a lot of routines from cga unit and replaced them by
  805. calls to cgobj
  806. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  807. u32bit then the other is typecasted also to u32bit without giving
  808. a rangecheck warning/error.
  809. * fixed pascal calling method with reversing also the high tree in
  810. the parast, detected by tcalcst3 test
  811. Revision 1.26 2002/04/04 19:06:12 peter
  812. * removed unused units
  813. * use tlocation.size in cg.a_*loc*() routines
  814. Revision 1.25 2002/04/02 17:11:36 peter
  815. * tlocation,treference update
  816. * LOC_CONSTANT added for better constant handling
  817. * secondadd splitted in multiple routines
  818. * location_force_reg added for loading a location to a register
  819. of a specified size
  820. * secondassignment parses now first the right and then the left node
  821. (this is compatible with Kylix). This saves a lot of push/pop especially
  822. with string operations
  823. * adapted some routines to use the new cg methods
  824. Revision 1.24 2002/03/31 20:26:39 jonas
  825. + a_loadfpu_* and a_loadmm_* methods in tcg
  826. * register allocation is now handled by a class and is mostly processor
  827. independent (+rgobj.pas and i386/rgcpu.pas)
  828. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  829. * some small improvements and fixes to the optimizer
  830. * some register allocation fixes
  831. * some fpuvaroffset fixes in the unary minus node
  832. * push/popusedregisters is now called rg.save/restoreusedregisters and
  833. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  834. also better optimizable)
  835. * fixed and optimized register saving/restoring for new/dispose nodes
  836. * LOC_FPU locations now also require their "register" field to be set to
  837. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  838. - list field removed of the tnode class because it's not used currently
  839. and can cause hard-to-find bugs
  840. Revision 1.23 2002/03/04 19:10:14 peter
  841. * removed compiler warnings
  842. }