n386mat.pas 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931
  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,cpuinfo,
  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. objectlibrary.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. objectlibrary.getlabel(l1);
  369. objectlibrary.getlabel(l2);
  370. objectlibrary.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. objectlibrary.getlabel(l1);
  395. objectlibrary.getlabel(l2);
  396. objectlibrary.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. emit_reg_reg(A_TEST,opsize,left.location.register,left.location.register);
  708. location_release(exprasmlist,left.location);
  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.37 2002-08-12 15:08:42 carl
  779. + stab register indexes for powerpc (moved from gdb to cpubase)
  780. + tprocessor enumeration moved to cpuinfo
  781. + linker in target_info is now a class
  782. * many many updates for m68k (will soon start to compile)
  783. - removed some ifdef or correct them for correct cpu
  784. Revision 1.36 2002/08/11 14:32:30 peter
  785. * renamed current_library to objectlibrary
  786. Revision 1.35 2002/08/11 13:24:17 peter
  787. * saving of asmsymbols in ppu supported
  788. * asmsymbollist global is removed and moved into a new class
  789. tasmlibrarydata that will hold the info of a .a file which
  790. corresponds with a single module. Added librarydata to tmodule
  791. to keep the library info stored for the module. In the future the
  792. objectfiles will also be stored to the tasmlibrarydata class
  793. * all getlabel/newasmsymbol and friends are moved to the new class
  794. Revision 1.34 2002/08/02 07:44:31 jonas
  795. * made assigned() handling generic
  796. * add nodes now can also evaluate constant expressions at compile time
  797. that contain nil nodes
  798. Revision 1.33 2002/07/20 11:58:02 florian
  799. * types.pas renamed to defbase.pas because D6 contains a types
  800. unit so this would conflicts if D6 programms are compiled
  801. + Willamette/SSE2 instructions to assembler added
  802. Revision 1.32 2002/07/01 18:46:33 peter
  803. * internal linker
  804. * reorganized aasm layer
  805. Revision 1.31 2002/05/18 13:34:25 peter
  806. * readded missing revisions
  807. Revision 1.30 2002/05/16 19:46:51 carl
  808. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  809. + try to fix temp allocation (still in ifdef)
  810. + generic constructor calls
  811. + start of tassembler / tmodulebase class cleanup
  812. Revision 1.28 2002/05/13 19:54:38 peter
  813. * removed n386ld and n386util units
  814. * maybe_save/maybe_restore added instead of the old maybe_push
  815. Revision 1.27 2002/05/12 16:53:17 peter
  816. * moved entry and exitcode to ncgutil and cgobj
  817. * foreach gets extra argument for passing local data to the
  818. iterator function
  819. * -CR checks also class typecasts at runtime by changing them
  820. into as
  821. * fixed compiler to cycle with the -CR option
  822. * fixed stabs with elf writer, finally the global variables can
  823. be watched
  824. * removed a lot of routines from cga unit and replaced them by
  825. calls to cgobj
  826. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  827. u32bit then the other is typecasted also to u32bit without giving
  828. a rangecheck warning/error.
  829. * fixed pascal calling method with reversing also the high tree in
  830. the parast, detected by tcalcst3 test
  831. Revision 1.26 2002/04/04 19:06:12 peter
  832. * removed unused units
  833. * use tlocation.size in cg.a_*loc*() routines
  834. Revision 1.25 2002/04/02 17:11:36 peter
  835. * tlocation,treference update
  836. * LOC_CONSTANT added for better constant handling
  837. * secondadd splitted in multiple routines
  838. * location_force_reg added for loading a location to a register
  839. of a specified size
  840. * secondassignment parses now first the right and then the left node
  841. (this is compatible with Kylix). This saves a lot of push/pop especially
  842. with string operations
  843. * adapted some routines to use the new cg methods
  844. Revision 1.24 2002/03/31 20:26:39 jonas
  845. + a_loadfpu_* and a_loadmm_* methods in tcg
  846. * register allocation is now handled by a class and is mostly processor
  847. independent (+rgobj.pas and i386/rgcpu.pas)
  848. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  849. * some small improvements and fixes to the optimizer
  850. * some register allocation fixes
  851. * some fpuvaroffset fixes in the unary minus node
  852. * push/popusedregisters is now called rg.save/restoreusedregisters and
  853. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  854. also better optimizable)
  855. * fixed and optimized register saving/restoring for new/dispose nodes
  856. * LOC_FPU locations now also require their "register" field to be set to
  857. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  858. - list field removed of the tnode class because it's not used currently
  859. and can cause hard-to-find bugs
  860. Revision 1.23 2002/03/04 19:10:14 peter
  861. * removed compiler warnings
  862. }