cg386mat.pas 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 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 cg386mat;
  19. interface
  20. uses
  21. tree;
  22. procedure secondmoddiv(var p : ptree);
  23. procedure secondshlshr(var p : ptree);
  24. procedure secondumminus(var p : ptree);
  25. procedure secondnot(var p : ptree);
  26. implementation
  27. uses
  28. cobjects,verbose,globals,
  29. symtable,aasm,i386,
  30. types,cgi386,cgai386,tgeni386,hcodegen;
  31. {*****************************************************************************
  32. SecondModDiv
  33. *****************************************************************************}
  34. procedure secondmoddiv(var p : ptree);
  35. var
  36. hreg1 : tregister;
  37. pushed,popeax,popedx : boolean;
  38. power : longint;
  39. hl : plabel;
  40. begin
  41. secondpass(p^.left);
  42. set_location(p^.location,p^.left^.location);
  43. pushed:=maybe_push(p^.right^.registers32,p);
  44. secondpass(p^.right);
  45. if pushed then restore(p);
  46. { put numerator in register }
  47. if p^.left^.location.loc<>LOC_REGISTER then
  48. begin
  49. if p^.left^.location.loc=LOC_CREGISTER then
  50. begin
  51. hreg1:=getregister32;
  52. emit_reg_reg(A_MOV,S_L,p^.left^.location.register,hreg1);
  53. end
  54. else
  55. begin
  56. del_reference(p^.left^.location.reference);
  57. hreg1:=getregister32;
  58. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,newreference(p^.left^.location.reference),
  59. hreg1)));
  60. end;
  61. p^.left^.location.loc:=LOC_REGISTER;
  62. p^.left^.location.register:=hreg1;
  63. end
  64. else hreg1:=p^.left^.location.register;
  65. if (p^.treetype=divn) and (p^.right^.treetype=ordconstn) and
  66. ispowerof2(p^.right^.value,power) then
  67. begin
  68. exprasmlist^.concat(new(pai386,op_reg_reg(A_OR,S_L,hreg1,hreg1)));
  69. getlabel(hl);
  70. emitl(A_JNS,hl);
  71. if power=1 then
  72. exprasmlist^.concat(new(pai386,op_reg(A_INC,S_L,hreg1)))
  73. else exprasmlist^.concat(new(pai386,op_const_reg(A_ADD,S_L,p^.right^.value-1,hreg1)));
  74. emitl(A_LABEL,hl);
  75. exprasmlist^.concat(new(pai386,op_const_reg(A_SAR,S_L,power,hreg1)));
  76. end
  77. else
  78. begin
  79. { bring denominator to EDI }
  80. { EDI is always free, it's }
  81. { only used for temporary }
  82. { purposes }
  83. if (p^.right^.location.loc<>LOC_REGISTER) and
  84. (p^.right^.location.loc<>LOC_CREGISTER) then
  85. begin
  86. del_reference(p^.right^.location.reference);
  87. p^.left^.location.loc:=LOC_REGISTER;
  88. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,newreference(p^.right^.location.reference),R_EDI)));
  89. end
  90. else
  91. begin
  92. ungetregister32(p^.right^.location.register);
  93. emit_reg_reg(A_MOV,S_L,p^.right^.location.register,R_EDI);
  94. end;
  95. popedx:=false;
  96. popeax:=false;
  97. if hreg1=R_EDX then
  98. begin
  99. if not(R_EAX in unused) then
  100. begin
  101. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_EAX)));
  102. popeax:=true;
  103. end;
  104. emit_reg_reg(A_MOV,S_L,R_EDX,R_EAX);
  105. end
  106. else
  107. begin
  108. if not(R_EDX in unused) then
  109. begin
  110. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_EDX)));
  111. popedx:=true;
  112. end;
  113. if hreg1<>R_EAX then
  114. begin
  115. if not(R_EAX in unused) then
  116. begin
  117. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_EAX)));
  118. popeax:=true;
  119. end;
  120. emit_reg_reg(A_MOV,S_L,hreg1,R_EAX);
  121. end;
  122. end;
  123. exprasmlist^.concat(new(pai386,op_none(A_CLTD,S_NO)));
  124. exprasmlist^.concat(new(pai386,op_reg(A_IDIV,S_L,R_EDI)));
  125. if p^.treetype=divn then
  126. begin
  127. { if result register is busy then copy }
  128. if popeax then
  129. begin
  130. if hreg1=R_EAX then
  131. internalerror(112);
  132. emit_reg_reg(A_MOV,S_L,R_EAX,hreg1)
  133. end
  134. else
  135. if hreg1<>R_EAX then
  136. emit_reg_reg(A_MOV,S_L,R_EAX,hreg1);
  137. end
  138. else
  139. emit_reg_reg(A_MOV,S_L,R_EDX,hreg1);
  140. if popeax then
  141. exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_EAX)));
  142. if popedx then
  143. exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_EDX)));
  144. end;
  145. { this registers are always used when div/mod are present }
  146. usedinproc:=usedinproc or ($80 shr byte(R_EAX));
  147. usedinproc:=usedinproc or ($80 shr byte(R_EDX));
  148. p^.location.loc:=LOC_REGISTER;
  149. p^.location.register:=hreg1;
  150. end;
  151. {*****************************************************************************
  152. SecondShlShr
  153. *****************************************************************************}
  154. procedure secondshlshr(var p : ptree);
  155. var
  156. hregister1,hregister2,hregister3 : tregister;
  157. pushed,popecx : boolean;
  158. op : tasmop;
  159. begin
  160. popecx:=false;
  161. secondpass(p^.left);
  162. pushed:=maybe_push(p^.right^.registers32,p);
  163. secondpass(p^.right);
  164. if pushed then restore(p);
  165. { load left operators in a register }
  166. if p^.left^.location.loc<>LOC_REGISTER then
  167. begin
  168. if p^.left^.location.loc=LOC_CREGISTER then
  169. begin
  170. hregister1:=getregister32;
  171. emit_reg_reg(A_MOV,S_L,p^.left^.location.register,
  172. hregister1);
  173. end
  174. else
  175. begin
  176. del_reference(p^.left^.location.reference);
  177. hregister1:=getregister32;
  178. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,newreference(p^.left^.location.reference),
  179. hregister1)));
  180. end;
  181. end
  182. else hregister1:=p^.left^.location.register;
  183. { determine operator }
  184. if p^.treetype=shln then
  185. op:=A_SHL
  186. else
  187. op:=A_SHR;
  188. { shifting by a constant directly decode: }
  189. if (p^.right^.treetype=ordconstn) then
  190. begin
  191. exprasmlist^.concat(new(pai386,op_const_reg(op,S_L,p^.right^.location.reference.offset and 31,
  192. hregister1)));
  193. p^.location.loc:=LOC_REGISTER;
  194. p^.location.register:=hregister1;
  195. end
  196. else
  197. begin
  198. { load right operators in a register }
  199. if p^.right^.location.loc<>LOC_REGISTER then
  200. begin
  201. if p^.right^.location.loc=LOC_CREGISTER then
  202. begin
  203. hregister2:=getregister32;
  204. emit_reg_reg(A_MOV,S_L,p^.right^.location.register,
  205. hregister2);
  206. end
  207. else
  208. begin
  209. del_reference(p^.right^.location.reference);
  210. hregister2:=getregister32;
  211. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,newreference(p^.right^.location.reference),
  212. hregister2)));
  213. end;
  214. end
  215. else hregister2:=p^.right^.location.register;
  216. { left operator is already in a register }
  217. { hence are both in a register }
  218. { is it in the case ECX ? }
  219. if (hregister1=R_ECX) then
  220. begin
  221. { then only swap }
  222. emit_reg_reg(A_XCHG,S_L,hregister1,
  223. hregister2);
  224. hregister3:=hregister1;
  225. hregister1:=hregister2;
  226. hregister2:=hregister3;
  227. end
  228. { if second operator not in ECX ? }
  229. else if (hregister2<>R_ECX) then
  230. begin
  231. { ECX not occupied then swap with right register }
  232. if R_ECX in unused then
  233. begin
  234. emit_reg_reg(A_MOV,S_L,hregister2,R_ECX);
  235. ungetregister32(hregister2);
  236. end
  237. else
  238. begin
  239. { else save ECX and then copy it }
  240. popecx:=true;
  241. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_ECX)));
  242. emit_reg_reg(A_MOV,S_L,hregister2,R_ECX);
  243. ungetregister32(hregister2);
  244. end;
  245. end;
  246. { right operand is in ECX }
  247. emit_reg_reg(op,S_L,R_CL,hregister1);
  248. { maybe ECX back }
  249. if popecx then
  250. exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_ECX)));
  251. p^.location.register:=hregister1;
  252. end;
  253. { this register is always used when shl/shr are present }
  254. usedinproc:=usedinproc or ($80 shr byte(R_ECX));
  255. end;
  256. {*****************************************************************************
  257. SecondUmMinus
  258. *****************************************************************************}
  259. procedure secondumminus(var p : ptree);
  260. {$ifdef SUPPORT_MMX}
  261. procedure do_mmx_neg;
  262. var
  263. op : tasmop;
  264. begin
  265. p^.location.loc:=LOC_MMXREGISTER;
  266. if cs_mmx_saturation in aktswitches then
  267. case mmx_type(p^.resulttype) of
  268. mmxs8bit:
  269. op:=A_PSUBSB;
  270. mmxu8bit:
  271. op:=A_PSUBUSB;
  272. mmxs16bit,mmxfixed16:
  273. op:=A_PSUBSW;
  274. mmxu16bit:
  275. op:=A_PSUBUSW;
  276. end
  277. else
  278. case mmx_type(p^.resulttype) of
  279. mmxs8bit,mmxu8bit:
  280. op:=A_PSUBB;
  281. mmxs16bit,mmxu16bit,mmxfixed16:
  282. op:=A_PSUBW;
  283. mmxs32bit,mmxu32bit:
  284. op:=A_PSUBD;
  285. end;
  286. emit_reg_reg(op,S_NO,p^.location.register,R_MM7);
  287. emit_reg_reg(A_MOVQ,S_NO,R_MM7,p^.location.register);
  288. end;
  289. {$endif}
  290. begin
  291. secondpass(p^.left);
  292. p^.location.loc:=LOC_REGISTER;
  293. case p^.left^.location.loc of
  294. LOC_REGISTER:
  295. begin
  296. p^.location.register:=p^.left^.location.register;
  297. exprasmlist^.concat(new(pai386,op_reg(A_NEG,S_L,p^.location.register)));
  298. end;
  299. LOC_CREGISTER:
  300. begin
  301. p^.location.register:=getregister32;
  302. emit_reg_reg(A_MOV,S_L,p^.location.register,
  303. p^.location.register);
  304. exprasmlist^.concat(new(pai386,op_reg(A_NEG,S_L,p^.location.register)));
  305. end;
  306. {$ifdef SUPPORT_MMX}
  307. LOC_MMXREGISTER:
  308. begin
  309. p^.location:=p^.left^.location;
  310. emit_reg_reg(A_PXOR,S_NO,R_MM7,R_MM7);
  311. do_mmx_neg;
  312. end;
  313. LOC_CMMXREGISTER:
  314. begin
  315. p^.location.register:=getregistermmx;
  316. emit_reg_reg(A_PXOR,S_NO,R_MM7,R_MM7);
  317. emit_reg_reg(A_MOVQ,S_NO,p^.left^.location.register,
  318. p^.location.register);
  319. do_mmx_neg;
  320. end;
  321. {$endif SUPPORT_MMX}
  322. LOC_REFERENCE,LOC_MEM:
  323. begin
  324. del_reference(p^.left^.location.reference);
  325. if (p^.left^.resulttype^.deftype=floatdef) and
  326. (pfloatdef(p^.left^.resulttype)^.typ<>f32bit) then
  327. begin
  328. p^.location.loc:=LOC_FPU;
  329. floatload(pfloatdef(p^.left^.resulttype)^.typ,
  330. p^.left^.location.reference);
  331. exprasmlist^.concat(new(pai386,op_none(A_FCHS,S_NO)));
  332. end
  333. {$ifdef SUPPORT_MMX}
  334. else if (cs_mmx in aktswitches) and is_mmx_able_array(p^.left^.resulttype) then
  335. begin
  336. p^.location.register:=getregistermmx;
  337. emit_reg_reg(A_PXOR,S_NO,R_MM7,R_MM7);
  338. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOVQ,S_NO,
  339. newreference(p^.left^.location.reference),
  340. p^.location.register)));
  341. do_mmx_neg;
  342. end
  343. {$endif SUPPORT_MMX}
  344. else
  345. begin
  346. p^.location.register:=getregister32;
  347. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,
  348. newreference(p^.left^.location.reference),
  349. p^.location.register)));
  350. exprasmlist^.concat(new(pai386,op_reg(A_NEG,S_L,p^.location.register)));
  351. end;
  352. end;
  353. LOC_FPU:
  354. begin
  355. p^.location.loc:=LOC_FPU;
  356. exprasmlist^.concat(new(pai386,op_none(A_FCHS,S_NO)));
  357. end;
  358. end;
  359. { Here was a problem... }
  360. { Operand to be negated always }
  361. { seems to be converted to signed }
  362. { 32-bit before doing neg!! }
  363. { So this is useless... }
  364. { emitoverflowcheck(p);}
  365. end;
  366. {*****************************************************************************
  367. SecondNot
  368. *****************************************************************************}
  369. procedure secondnot(var p : ptree);
  370. const
  371. flagsinvers : array[F_E..F_BE] of tresflags =
  372. (F_NE,F_E,F_LE,F_GE,F_L,F_G,F_NC,F_C,
  373. F_A,F_AE,F_B,F_BE);
  374. var
  375. hl : plabel;
  376. opsize : topsize;
  377. begin
  378. if (p^.resulttype^.deftype=orddef) and
  379. (porddef(p^.resulttype)^.typ in [bool8bit,bool16bit,bool32bit]) then
  380. begin
  381. case porddef(p^.resulttype)^.typ of
  382. bool8bit : opsize:=S_B;
  383. bool16bit : opsize:=S_W;
  384. bool32bit : opsize:=S_L;
  385. end;
  386. case p^.location.loc of
  387. LOC_JUMP : begin
  388. hl:=truelabel;
  389. truelabel:=falselabel;
  390. falselabel:=hl;
  391. secondpass(p^.left);
  392. maketojumpbool(p^.left);
  393. hl:=truelabel;
  394. truelabel:=falselabel;
  395. falselabel:=hl;
  396. end;
  397. LOC_FLAGS : begin
  398. secondpass(p^.left);
  399. p^.location.resflags:=flagsinvers[p^.left^.location.resflags];
  400. end;
  401. LOC_REGISTER : begin
  402. secondpass(p^.left);
  403. p^.location.register:=p^.left^.location.register;
  404. exprasmlist^.concat(new(pai386,op_const_reg(A_XOR,opsize,1,p^.location.register)));
  405. end;
  406. LOC_CREGISTER : begin
  407. secondpass(p^.left);
  408. p^.location.loc:=LOC_REGISTER;
  409. case porddef(p^.resulttype)^.typ of
  410. bool8bit : p^.location.register:=reg32toreg8(getregister32);
  411. bool16bit : p^.location.register:=reg32toreg16(getregister32);
  412. bool32bit : p^.location.register:=getregister32;
  413. end;
  414. emit_reg_reg(A_MOV,opsize,p^.left^.location.register,p^.location.register);
  415. exprasmlist^.concat(new(pai386,op_const_reg(A_XOR,opsize,1,p^.location.register)));
  416. end;
  417. LOC_REFERENCE,
  418. LOC_MEM : begin
  419. secondpass(p^.left);
  420. del_reference(p^.left^.location.reference);
  421. p^.location.loc:=LOC_REGISTER;
  422. case porddef(p^.resulttype)^.typ of
  423. bool8bit : p^.location.register:=reg32toreg8(getregister32);
  424. bool16bit : p^.location.register:=reg32toreg16(getregister32);
  425. bool32bit : p^.location.register:=getregister32;
  426. end;
  427. if p^.left^.location.loc=LOC_CREGISTER then
  428. emit_reg_reg(A_MOV,opsize,p^.left^.location.register,p^.location.register)
  429. else
  430. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  431. newreference(p^.left^.location.reference),p^.location.register)));
  432. exprasmlist^.concat(new(pai386,op_const_reg(A_XOR,opsize,1,p^.location.register)));
  433. end;
  434. end;
  435. end
  436. {$ifdef SUPPORT_MMX}
  437. else if (cs_mmx in aktswitches) and is_mmx_able_array(p^.left^.resulttype) then
  438. begin
  439. secondpass(p^.left);
  440. p^.location.loc:=LOC_MMXREGISTER;
  441. { prepare EDI }
  442. exprasmlist^.concat(new(pai386,op_const_reg(A_MOV,S_L,$ffffffff,R_EDI)));
  443. { load operand }
  444. case p^.left^.location.loc of
  445. LOC_MMXREGISTER:
  446. p^.location:=p^.left^.location;
  447. LOC_CMMXREGISTER:
  448. begin
  449. p^.location.register:=getregistermmx;
  450. emit_reg_reg(A_MOVQ,S_NO,p^.left^.location.register,
  451. p^.location.register);
  452. end;
  453. LOC_REFERENCE,LOC_MEM:
  454. begin
  455. del_reference(p^.left^.location.reference);
  456. p^.location.register:=getregistermmx;
  457. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOVQ,S_NO,
  458. newreference(p^.left^.location.reference),
  459. p^.location.register)));
  460. end;
  461. end;
  462. { load mask }
  463. emit_reg_reg(A_MOV,S_D,R_EDI,R_MM7);
  464. { lower 32 bit }
  465. emit_reg_reg(A_PXOR,S_D,R_MM7,p^.location.register);
  466. { shift mask }
  467. exprasmlist^.concat(new(pai386,op_const_reg(A_PSLLQ,S_NO,
  468. 32,R_MM7)));
  469. { higher 32 bit }
  470. emit_reg_reg(A_PXOR,S_D,R_MM7,p^.location.register);
  471. end
  472. {$endif SUPPORT_MMX}
  473. else
  474. begin
  475. secondpass(p^.left);
  476. p^.location.loc:=LOC_REGISTER;
  477. case p^.left^.location.loc of
  478. LOC_REGISTER : begin
  479. p^.location.register:=p^.left^.location.register;
  480. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,p^.location.register)));
  481. end;
  482. LOC_CREGISTER : begin
  483. p^.location.register:=getregister32;
  484. emit_reg_reg(A_MOV,S_L,p^.left^.location.register,
  485. p^.location.register);
  486. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,p^.location.register)));
  487. end;
  488. LOC_REFERENCE,LOC_MEM :
  489. begin
  490. del_reference(p^.left^.location.reference);
  491. p^.location.register:=getregister32;
  492. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,
  493. newreference(p^.left^.location.reference),
  494. p^.location.register)));
  495. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,p^.location.register)));
  496. end;
  497. end;
  498. {if p^.left^.location.loc=loc_register then
  499. p^.location.register:=p^.left^.location.register
  500. else
  501. begin
  502. del_locref(p^.left^.location);
  503. p^.location.register:=getregister32;
  504. exprasmlist^.concat(new(pai386,op_loc_reg(A_MOV,S_L,
  505. p^.left^.location,
  506. p^.location.register)));
  507. end;
  508. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,p^.location.register)));}
  509. end;
  510. end;
  511. end.
  512. {
  513. $Log$
  514. Revision 1.3 1998-06-05 17:44:12 peter
  515. * splitted cgi386
  516. Revision 1.2 1998/06/02 17:02:59 pierre
  517. * with node corrected for objects
  518. * small bugs for SUPPORT_MMX fixed
  519. Revision 1.1 1998/06/01 16:50:18 peter
  520. + boolean -> ord conversion
  521. * fixed ord -> boolean conversion
  522. }