n386mat.pas 40 KB

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