cg386mat.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  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. { sign extension depends on the left type }
  124. if porddef(p^.left^.resulttype)^.typ=u32bit then
  125. exprasmlist^.concat(new(pai386,op_reg_reg(A_XOR,S_L,R_EDX,R_EDX)))
  126. else
  127. exprasmlist^.concat(new(pai386,op_none(A_CLTD,S_NO)));
  128. { division depends on the right type }
  129. if porddef(p^.right^.resulttype)^.typ=u32bit then
  130. exprasmlist^.concat(new(pai386,op_reg(A_DIV,S_L,R_EDI)))
  131. else
  132. exprasmlist^.concat(new(pai386,op_reg(A_IDIV,S_L,R_EDI)));
  133. if p^.treetype=divn then
  134. begin
  135. { if result register is busy then copy }
  136. if popeax then
  137. begin
  138. if hreg1=R_EAX then
  139. internalerror(112);
  140. emit_reg_reg(A_MOV,S_L,R_EAX,hreg1)
  141. end
  142. else
  143. if hreg1<>R_EAX then
  144. emit_reg_reg(A_MOV,S_L,R_EAX,hreg1);
  145. end
  146. else
  147. emit_reg_reg(A_MOV,S_L,R_EDX,hreg1);
  148. if popeax then
  149. exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_EAX)));
  150. if popedx then
  151. exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_EDX)));
  152. end;
  153. { this registers are always used when div/mod are present }
  154. usedinproc:=usedinproc or ($80 shr byte(R_EAX));
  155. usedinproc:=usedinproc or ($80 shr byte(R_EDX));
  156. p^.location.loc:=LOC_REGISTER;
  157. p^.location.register:=hreg1;
  158. end;
  159. {*****************************************************************************
  160. SecondShlShr
  161. *****************************************************************************}
  162. procedure secondshlshr(var p : ptree);
  163. var
  164. hregister1,hregister2,hregister3 : tregister;
  165. pushed,popecx : boolean;
  166. op : tasmop;
  167. begin
  168. popecx:=false;
  169. secondpass(p^.left);
  170. pushed:=maybe_push(p^.right^.registers32,p);
  171. secondpass(p^.right);
  172. if pushed then restore(p);
  173. { load left operators in a register }
  174. if p^.left^.location.loc<>LOC_REGISTER then
  175. begin
  176. if p^.left^.location.loc=LOC_CREGISTER then
  177. begin
  178. hregister1:=getregister32;
  179. emit_reg_reg(A_MOV,S_L,p^.left^.location.register,
  180. hregister1);
  181. end
  182. else
  183. begin
  184. del_reference(p^.left^.location.reference);
  185. hregister1:=getregister32;
  186. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,newreference(p^.left^.location.reference),
  187. hregister1)));
  188. end;
  189. end
  190. else hregister1:=p^.left^.location.register;
  191. { determine operator }
  192. if p^.treetype=shln then
  193. op:=A_SHL
  194. else
  195. op:=A_SHR;
  196. { shifting by a constant directly decode: }
  197. if (p^.right^.treetype=ordconstn) then
  198. begin
  199. exprasmlist^.concat(new(pai386,op_const_reg(op,S_L,p^.right^.location.reference.offset and 31,
  200. hregister1)));
  201. p^.location.loc:=LOC_REGISTER;
  202. p^.location.register:=hregister1;
  203. end
  204. else
  205. begin
  206. { load right operators in a register }
  207. if p^.right^.location.loc<>LOC_REGISTER then
  208. begin
  209. if p^.right^.location.loc=LOC_CREGISTER then
  210. begin
  211. hregister2:=getregister32;
  212. emit_reg_reg(A_MOV,S_L,p^.right^.location.register,
  213. hregister2);
  214. end
  215. else
  216. begin
  217. del_reference(p^.right^.location.reference);
  218. hregister2:=getregister32;
  219. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,newreference(p^.right^.location.reference),
  220. hregister2)));
  221. end;
  222. end
  223. else hregister2:=p^.right^.location.register;
  224. { left operator is already in a register }
  225. { hence are both in a register }
  226. { is it in the case ECX ? }
  227. if (hregister1=R_ECX) then
  228. begin
  229. { then only swap }
  230. emit_reg_reg(A_XCHG,S_L,hregister1,
  231. hregister2);
  232. hregister3:=hregister1;
  233. hregister1:=hregister2;
  234. hregister2:=hregister3;
  235. end
  236. { if second operator not in ECX ? }
  237. else if (hregister2<>R_ECX) then
  238. begin
  239. { ECX not occupied then swap with right register }
  240. if R_ECX in unused then
  241. begin
  242. emit_reg_reg(A_MOV,S_L,hregister2,R_ECX);
  243. ungetregister32(hregister2);
  244. end
  245. else
  246. begin
  247. { else save ECX and then copy it }
  248. popecx:=true;
  249. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_ECX)));
  250. emit_reg_reg(A_MOV,S_L,hregister2,R_ECX);
  251. ungetregister32(hregister2);
  252. end;
  253. end;
  254. { right operand is in ECX }
  255. emit_reg_reg(op,S_L,R_CL,hregister1);
  256. { maybe ECX back }
  257. if popecx then
  258. exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_ECX)));
  259. p^.location.register:=hregister1;
  260. end;
  261. { this register is always used when shl/shr are present }
  262. usedinproc:=usedinproc or ($80 shr byte(R_ECX));
  263. end;
  264. {*****************************************************************************
  265. SecondUmMinus
  266. *****************************************************************************}
  267. procedure secondumminus(var p : ptree);
  268. {$ifdef SUPPORT_MMX}
  269. procedure do_mmx_neg;
  270. var
  271. op : tasmop;
  272. begin
  273. p^.location.loc:=LOC_MMXREGISTER;
  274. if cs_mmx_saturation in aktlocalswitches then
  275. case mmx_type(p^.resulttype) of
  276. mmxs8bit:
  277. op:=A_PSUBSB;
  278. mmxu8bit:
  279. op:=A_PSUBUSB;
  280. mmxs16bit,mmxfixed16:
  281. op:=A_PSUBSW;
  282. mmxu16bit:
  283. op:=A_PSUBUSW;
  284. end
  285. else
  286. case mmx_type(p^.resulttype) of
  287. mmxs8bit,mmxu8bit:
  288. op:=A_PSUBB;
  289. mmxs16bit,mmxu16bit,mmxfixed16:
  290. op:=A_PSUBW;
  291. mmxs32bit,mmxu32bit:
  292. op:=A_PSUBD;
  293. end;
  294. emit_reg_reg(op,S_NO,p^.location.register,R_MM7);
  295. emit_reg_reg(A_MOVQ,S_NO,R_MM7,p^.location.register);
  296. end;
  297. {$endif}
  298. begin
  299. secondpass(p^.left);
  300. p^.location.loc:=LOC_REGISTER;
  301. case p^.left^.location.loc of
  302. LOC_REGISTER:
  303. begin
  304. p^.location.register:=p^.left^.location.register;
  305. exprasmlist^.concat(new(pai386,op_reg(A_NEG,S_L,p^.location.register)));
  306. end;
  307. LOC_CREGISTER:
  308. begin
  309. p^.location.register:=getregister32;
  310. emit_reg_reg(A_MOV,S_L,p^.location.register,
  311. p^.location.register);
  312. exprasmlist^.concat(new(pai386,op_reg(A_NEG,S_L,p^.location.register)));
  313. end;
  314. {$ifdef SUPPORT_MMX}
  315. LOC_MMXREGISTER:
  316. begin
  317. p^.location:=p^.left^.location;
  318. emit_reg_reg(A_PXOR,S_NO,R_MM7,R_MM7);
  319. do_mmx_neg;
  320. end;
  321. LOC_CMMXREGISTER:
  322. begin
  323. p^.location.register:=getregistermmx;
  324. emit_reg_reg(A_PXOR,S_NO,R_MM7,R_MM7);
  325. emit_reg_reg(A_MOVQ,S_NO,p^.left^.location.register,
  326. p^.location.register);
  327. do_mmx_neg;
  328. end;
  329. {$endif SUPPORT_MMX}
  330. LOC_REFERENCE,LOC_MEM:
  331. begin
  332. del_reference(p^.left^.location.reference);
  333. if (p^.left^.resulttype^.deftype=floatdef) and
  334. (pfloatdef(p^.left^.resulttype)^.typ<>f32bit) then
  335. begin
  336. p^.location.loc:=LOC_FPU;
  337. floatload(pfloatdef(p^.left^.resulttype)^.typ,
  338. p^.left^.location.reference);
  339. exprasmlist^.concat(new(pai386,op_none(A_FCHS,S_NO)));
  340. end
  341. {$ifdef SUPPORT_MMX}
  342. else if (cs_mmx in aktlocalswitches) and is_mmx_able_array(p^.left^.resulttype) then
  343. begin
  344. p^.location.register:=getregistermmx;
  345. emit_reg_reg(A_PXOR,S_NO,R_MM7,R_MM7);
  346. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOVQ,S_NO,
  347. newreference(p^.left^.location.reference),
  348. p^.location.register)));
  349. do_mmx_neg;
  350. end
  351. {$endif SUPPORT_MMX}
  352. else
  353. begin
  354. p^.location.register:=getregister32;
  355. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,
  356. newreference(p^.left^.location.reference),
  357. p^.location.register)));
  358. exprasmlist^.concat(new(pai386,op_reg(A_NEG,S_L,p^.location.register)));
  359. end;
  360. end;
  361. LOC_FPU:
  362. begin
  363. p^.location.loc:=LOC_FPU;
  364. exprasmlist^.concat(new(pai386,op_none(A_FCHS,S_NO)));
  365. end;
  366. end;
  367. { Here was a problem... }
  368. { Operand to be negated always }
  369. { seems to be converted to signed }
  370. { 32-bit before doing neg!! }
  371. { So this is useless... }
  372. { emitoverflowcheck(p);}
  373. end;
  374. {*****************************************************************************
  375. SecondNot
  376. *****************************************************************************}
  377. procedure secondnot(var p : ptree);
  378. const
  379. flagsinvers : array[F_E..F_BE] of tresflags =
  380. (F_NE,F_E,F_LE,F_GE,F_L,F_G,F_NC,F_C,
  381. F_A,F_AE,F_B,F_BE);
  382. var
  383. hl : plabel;
  384. opsize : topsize;
  385. begin
  386. if (p^.resulttype^.deftype=orddef) and
  387. (porddef(p^.resulttype)^.typ in [bool8bit,bool16bit,bool32bit]) then
  388. begin
  389. case porddef(p^.resulttype)^.typ of
  390. bool8bit : opsize:=S_B;
  391. bool16bit : opsize:=S_W;
  392. bool32bit : opsize:=S_L;
  393. end;
  394. case p^.location.loc of
  395. LOC_JUMP : begin
  396. hl:=truelabel;
  397. truelabel:=falselabel;
  398. falselabel:=hl;
  399. secondpass(p^.left);
  400. maketojumpbool(p^.left);
  401. hl:=truelabel;
  402. truelabel:=falselabel;
  403. falselabel:=hl;
  404. end;
  405. LOC_FLAGS : begin
  406. secondpass(p^.left);
  407. p^.location.resflags:=flagsinvers[p^.left^.location.resflags];
  408. end;
  409. LOC_REGISTER : begin
  410. secondpass(p^.left);
  411. p^.location.register:=p^.left^.location.register;
  412. exprasmlist^.concat(new(pai386,op_const_reg(A_XOR,opsize,1,p^.location.register)));
  413. end;
  414. LOC_CREGISTER : begin
  415. secondpass(p^.left);
  416. p^.location.loc:=LOC_REGISTER;
  417. case porddef(p^.resulttype)^.typ of
  418. bool8bit : p^.location.register:=reg32toreg8(getregister32);
  419. bool16bit : p^.location.register:=reg32toreg16(getregister32);
  420. bool32bit : p^.location.register:=getregister32;
  421. end;
  422. emit_reg_reg(A_MOV,opsize,p^.left^.location.register,p^.location.register);
  423. exprasmlist^.concat(new(pai386,op_const_reg(A_XOR,opsize,1,p^.location.register)));
  424. end;
  425. LOC_REFERENCE,
  426. LOC_MEM : begin
  427. secondpass(p^.left);
  428. del_reference(p^.left^.location.reference);
  429. p^.location.loc:=LOC_REGISTER;
  430. case porddef(p^.resulttype)^.typ of
  431. bool8bit : p^.location.register:=reg32toreg8(getregister32);
  432. bool16bit : p^.location.register:=reg32toreg16(getregister32);
  433. bool32bit : p^.location.register:=getregister32;
  434. end;
  435. if p^.left^.location.loc=LOC_CREGISTER then
  436. emit_reg_reg(A_MOV,opsize,p^.left^.location.register,p^.location.register)
  437. else
  438. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  439. newreference(p^.left^.location.reference),p^.location.register)));
  440. exprasmlist^.concat(new(pai386,op_const_reg(A_XOR,opsize,1,p^.location.register)));
  441. end;
  442. end;
  443. end
  444. {$ifdef SUPPORT_MMX}
  445. else if (cs_mmx in aktlocalswitches) and is_mmx_able_array(p^.left^.resulttype) then
  446. begin
  447. secondpass(p^.left);
  448. p^.location.loc:=LOC_MMXREGISTER;
  449. { prepare EDI }
  450. exprasmlist^.concat(new(pai386,op_const_reg(A_MOV,S_L,$ffffffff,R_EDI)));
  451. { load operand }
  452. case p^.left^.location.loc of
  453. LOC_MMXREGISTER:
  454. p^.location:=p^.left^.location;
  455. LOC_CMMXREGISTER:
  456. begin
  457. p^.location.register:=getregistermmx;
  458. emit_reg_reg(A_MOVQ,S_NO,p^.left^.location.register,
  459. p^.location.register);
  460. end;
  461. LOC_REFERENCE,LOC_MEM:
  462. begin
  463. del_reference(p^.left^.location.reference);
  464. p^.location.register:=getregistermmx;
  465. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOVQ,S_NO,
  466. newreference(p^.left^.location.reference),
  467. p^.location.register)));
  468. end;
  469. end;
  470. { load mask }
  471. emit_reg_reg(A_MOV,S_D,R_EDI,R_MM7);
  472. { lower 32 bit }
  473. emit_reg_reg(A_PXOR,S_D,R_MM7,p^.location.register);
  474. { shift mask }
  475. exprasmlist^.concat(new(pai386,op_const_reg(A_PSLLQ,S_NO,
  476. 32,R_MM7)));
  477. { higher 32 bit }
  478. emit_reg_reg(A_PXOR,S_D,R_MM7,p^.location.register);
  479. end
  480. {$endif SUPPORT_MMX}
  481. else
  482. begin
  483. secondpass(p^.left);
  484. p^.location.loc:=LOC_REGISTER;
  485. case p^.left^.location.loc of
  486. LOC_REGISTER : begin
  487. p^.location.register:=p^.left^.location.register;
  488. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,p^.location.register)));
  489. end;
  490. LOC_CREGISTER : begin
  491. p^.location.register:=getregister32;
  492. emit_reg_reg(A_MOV,S_L,p^.left^.location.register,
  493. p^.location.register);
  494. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,p^.location.register)));
  495. end;
  496. LOC_REFERENCE,LOC_MEM :
  497. begin
  498. del_reference(p^.left^.location.reference);
  499. p^.location.register:=getregister32;
  500. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,
  501. newreference(p^.left^.location.reference),
  502. p^.location.register)));
  503. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,p^.location.register)));
  504. end;
  505. end;
  506. {if p^.left^.location.loc=loc_register then
  507. p^.location.register:=p^.left^.location.register
  508. else
  509. begin
  510. del_locref(p^.left^.location);
  511. p^.location.register:=getregister32;
  512. exprasmlist^.concat(new(pai386,op_loc_reg(A_MOV,S_L,
  513. p^.left^.location,
  514. p^.location.register)));
  515. end;
  516. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,p^.location.register)));}
  517. end;
  518. end;
  519. end.
  520. {
  521. $Log$
  522. Revision 1.6 1998-09-09 14:37:37 florian
  523. * mod/div for cardinal type fixed
  524. Revision 1.5 1998/08/23 16:07:20 florian
  525. * internalerror with mod/div fixed
  526. Revision 1.4 1998/08/18 09:24:38 pierre
  527. * small warning position bug fixed
  528. * support_mmx switches splitting was missing
  529. * rhide error and warning output corrected
  530. Revision 1.3 1998/06/05 17:44:12 peter
  531. * splitted cgi386
  532. Revision 1.2 1998/06/02 17:02:59 pierre
  533. * with node corrected for objects
  534. * small bugs for SUPPORT_MMX fixed
  535. Revision 1.1 1998/06/01 16:50:18 peter
  536. + boolean -> ord conversion
  537. * fixed ord -> boolean conversion
  538. }