n386mat.pas 39 KB

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