n386mat.pas 40 KB

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