cg386mat.pas 24 KB

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