cg386mat.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  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_CDQ,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
  176. restore(p);
  177. { load left operators in a register }
  178. if p^.left^.location.loc<>LOC_REGISTER then
  179. begin
  180. if p^.left^.location.loc=LOC_CREGISTER then
  181. begin
  182. hregister1:=getregister32;
  183. emit_reg_reg(A_MOV,S_L,p^.left^.location.register,
  184. hregister1);
  185. end
  186. else
  187. begin
  188. del_reference(p^.left^.location.reference);
  189. hregister1:=getregister32;
  190. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,newreference(p^.left^.location.reference),
  191. hregister1)));
  192. end;
  193. end
  194. else
  195. hregister1:=p^.left^.location.register;
  196. { determine operator }
  197. if p^.treetype=shln then
  198. op:=A_SHL
  199. else
  200. op:=A_SHR;
  201. { shifting by a constant directly decode: }
  202. if (p^.right^.treetype=ordconstn) then
  203. begin
  204. exprasmlist^.concat(new(pai386,op_const_reg(op,S_L,p^.right^.location.reference.offset and 31,
  205. hregister1)));
  206. p^.location.loc:=LOC_REGISTER;
  207. p^.location.register:=hregister1;
  208. end
  209. else
  210. begin
  211. { load right operators in a register }
  212. if p^.right^.location.loc<>LOC_REGISTER then
  213. begin
  214. if p^.right^.location.loc=LOC_CREGISTER then
  215. begin
  216. hregister2:=getregister32;
  217. emit_reg_reg(A_MOV,S_L,p^.right^.location.register,
  218. hregister2);
  219. end
  220. else
  221. begin
  222. del_reference(p^.right^.location.reference);
  223. hregister2:=getregister32;
  224. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,newreference(p^.right^.location.reference),
  225. hregister2)));
  226. end;
  227. end
  228. else
  229. hregister2:=p^.right^.location.register;
  230. { left operator is already in a register }
  231. { hence are both in a register }
  232. { is it in the case ECX ? }
  233. if (hregister1=R_ECX) then
  234. begin
  235. { then only swap }
  236. emit_reg_reg(A_XCHG,S_L,hregister1,hregister2);
  237. hregister3:=hregister1;
  238. hregister1:=hregister2;
  239. hregister2:=hregister3;
  240. end
  241. { if second operator not in ECX ? }
  242. else if (hregister2<>R_ECX) then
  243. begin
  244. { ECX occupied then push it }
  245. if not (R_ECX in unused) then
  246. begin
  247. popecx:=true;
  248. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_ECX)));
  249. end;
  250. emit_reg_reg(A_MOV,S_L,hregister2,R_ECX);
  251. ungetregister32(hregister2);
  252. end;
  253. { right operand is in ECX }
  254. emit_reg_reg(op,S_L,R_CL,hregister1);
  255. { maybe ECX back }
  256. if popecx then
  257. exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_ECX)));
  258. p^.location.register:=hregister1;
  259. end;
  260. end;
  261. {*****************************************************************************
  262. SecondUmMinus
  263. *****************************************************************************}
  264. procedure secondumminus(var p : ptree);
  265. {$ifdef SUPPORT_MMX}
  266. procedure do_mmx_neg;
  267. var
  268. op : tasmop;
  269. begin
  270. p^.location.loc:=LOC_MMXREGISTER;
  271. if cs_mmx_saturation in aktlocalswitches then
  272. case mmx_type(p^.resulttype) of
  273. mmxs8bit:
  274. op:=A_PSUBSB;
  275. mmxu8bit:
  276. op:=A_PSUBUSB;
  277. mmxs16bit,mmxfixed16:
  278. op:=A_PSUBSW;
  279. mmxu16bit:
  280. op:=A_PSUBUSW;
  281. end
  282. else
  283. case mmx_type(p^.resulttype) of
  284. mmxs8bit,mmxu8bit:
  285. op:=A_PSUBB;
  286. mmxs16bit,mmxu16bit,mmxfixed16:
  287. op:=A_PSUBW;
  288. mmxs32bit,mmxu32bit:
  289. op:=A_PSUBD;
  290. end;
  291. emit_reg_reg(op,S_NO,p^.location.register,R_MM7);
  292. emit_reg_reg(A_MOVQ,S_NO,R_MM7,p^.location.register);
  293. end;
  294. {$endif}
  295. begin
  296. secondpass(p^.left);
  297. p^.location.loc:=LOC_REGISTER;
  298. case p^.left^.location.loc of
  299. LOC_REGISTER:
  300. begin
  301. p^.location.register:=p^.left^.location.register;
  302. exprasmlist^.concat(new(pai386,op_reg(A_NEG,S_L,p^.location.register)));
  303. end;
  304. LOC_CREGISTER:
  305. begin
  306. p^.location.register:=getregister32;
  307. emit_reg_reg(A_MOV,S_L,p^.location.register,
  308. p^.location.register);
  309. exprasmlist^.concat(new(pai386,op_reg(A_NEG,S_L,p^.location.register)));
  310. end;
  311. {$ifdef SUPPORT_MMX}
  312. LOC_MMXREGISTER:
  313. begin
  314. set_location(p^.location,p^.left^.location);
  315. emit_reg_reg(A_PXOR,S_NO,R_MM7,R_MM7);
  316. do_mmx_neg;
  317. end;
  318. LOC_CMMXREGISTER:
  319. begin
  320. p^.location.register:=getregistermmx;
  321. emit_reg_reg(A_PXOR,S_NO,R_MM7,R_MM7);
  322. emit_reg_reg(A_MOVQ,S_NO,p^.left^.location.register,
  323. p^.location.register);
  324. do_mmx_neg;
  325. end;
  326. {$endif SUPPORT_MMX}
  327. LOC_REFERENCE,LOC_MEM:
  328. begin
  329. del_reference(p^.left^.location.reference);
  330. if (p^.left^.resulttype^.deftype=floatdef) and
  331. (pfloatdef(p^.left^.resulttype)^.typ<>f32bit) then
  332. begin
  333. p^.location.loc:=LOC_FPU;
  334. floatload(pfloatdef(p^.left^.resulttype)^.typ,
  335. p^.left^.location.reference);
  336. exprasmlist^.concat(new(pai386,op_none(A_FCHS,S_NO)));
  337. end
  338. {$ifdef SUPPORT_MMX}
  339. else if (cs_mmx in aktlocalswitches) and is_mmx_able_array(p^.left^.resulttype) then
  340. begin
  341. p^.location.register:=getregistermmx;
  342. emit_reg_reg(A_PXOR,S_NO,R_MM7,R_MM7);
  343. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOVQ,S_NO,
  344. newreference(p^.left^.location.reference),
  345. p^.location.register)));
  346. do_mmx_neg;
  347. end
  348. {$endif SUPPORT_MMX}
  349. else
  350. begin
  351. p^.location.register:=getregister32;
  352. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,
  353. newreference(p^.left^.location.reference),
  354. p^.location.register)));
  355. exprasmlist^.concat(new(pai386,op_reg(A_NEG,S_L,p^.location.register)));
  356. end;
  357. end;
  358. LOC_FPU:
  359. begin
  360. p^.location.loc:=LOC_FPU;
  361. exprasmlist^.concat(new(pai386,op_none(A_FCHS,S_NO)));
  362. end;
  363. end;
  364. { Here was a problem... }
  365. { Operand to be negated always }
  366. { seems to be converted to signed }
  367. { 32-bit before doing neg!! }
  368. { So this is useless... }
  369. { emitoverflowcheck(p);}
  370. end;
  371. {*****************************************************************************
  372. SecondNot
  373. *****************************************************************************}
  374. procedure secondnot(var p : ptree);
  375. const
  376. flagsinvers : array[F_E..F_BE] of tresflags =
  377. (F_NE,F_E,F_LE,F_GE,F_L,F_G,F_NC,F_C,
  378. F_A,F_AE,F_B,F_BE);
  379. var
  380. hl : plabel;
  381. opsize : topsize;
  382. begin
  383. if is_boolean(p^.resulttype) then
  384. begin
  385. opsize:=def_opsize(p^.resulttype);
  386. case p^.left^.location.loc of
  387. LOC_JUMP :
  388. begin
  389. hl:=truelabel;
  390. truelabel:=falselabel;
  391. falselabel:=hl;
  392. secondpass(p^.left);
  393. maketojumpbool(p^.left);
  394. hl:=truelabel;
  395. truelabel:=falselabel;
  396. falselabel:=hl;
  397. end;
  398. LOC_FLAGS :
  399. begin
  400. secondpass(p^.left);
  401. p^.location.resflags:=flagsinvers[p^.left^.location.resflags];
  402. end;
  403. LOC_REGISTER :
  404. begin
  405. secondpass(p^.left);
  406. p^.location.register:=p^.left^.location.register;
  407. exprasmlist^.concat(new(pai386,op_const_reg(A_XOR,opsize,1,p^.location.register)));
  408. end;
  409. LOC_CREGISTER :
  410. begin
  411. secondpass(p^.left);
  412. clear_location(p^.location);
  413. p^.location.loc:=LOC_REGISTER;
  414. p^.location.register:=def_getreg(p^.resulttype);
  415. emit_reg_reg(A_MOV,opsize,p^.left^.location.register,p^.location.register);
  416. exprasmlist^.concat(new(pai386,op_const_reg(A_XOR,opsize,1,p^.location.register)));
  417. end;
  418. LOC_REFERENCE,
  419. LOC_MEM :
  420. begin
  421. secondpass(p^.left);
  422. clear_location(p^.location);
  423. p^.location.loc:=LOC_REGISTER;
  424. p^.location.register:=def_getreg(p^.resulttype);
  425. del_reference(p^.left^.location.reference);
  426. if p^.left^.location.loc=LOC_CREGISTER then
  427. emit_reg_reg(A_MOV,opsize,p^.left^.location.register,p^.location.register)
  428. else
  429. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  430. newreference(p^.left^.location.reference),p^.location.register)));
  431. exprasmlist^.concat(new(pai386,op_const_reg(A_XOR,opsize,1,p^.location.register)));
  432. end;
  433. end;
  434. end
  435. {$ifdef SUPPORT_MMX}
  436. else
  437. if (cs_mmx in aktlocalswitches) 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. set_location(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,p^.location.register);
  451. end;
  452. LOC_REFERENCE,LOC_MEM:
  453. begin
  454. del_reference(p^.left^.location.reference);
  455. p^.location.register:=getregistermmx;
  456. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOVQ,S_NO,
  457. newreference(p^.left^.location.reference),p^.location.register)));
  458. end;
  459. end;
  460. { load mask }
  461. emit_reg_reg(A_MOV,S_D,R_EDI,R_MM7);
  462. { lower 32 bit }
  463. emit_reg_reg(A_PXOR,S_D,R_MM7,p^.location.register);
  464. { shift mask }
  465. exprasmlist^.concat(new(pai386,op_const_reg(A_PSLLQ,S_NO,32,R_MM7)));
  466. { higher 32 bit }
  467. emit_reg_reg(A_PXOR,S_D,R_MM7,p^.location.register);
  468. end
  469. {$endif SUPPORT_MMX}
  470. else
  471. begin
  472. secondpass(p^.left);
  473. clear_location(p^.location);
  474. p^.location.loc:=LOC_REGISTER;
  475. case p^.left^.location.loc of
  476. LOC_REGISTER :
  477. begin
  478. p^.location.register:=p^.left^.location.register;
  479. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,p^.location.register)));
  480. end;
  481. LOC_CREGISTER :
  482. begin
  483. p^.location.register:=getregister32;
  484. emit_reg_reg(A_MOV,S_L,p^.left^.location.register,p^.location.register);
  485. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,p^.location.register)));
  486. end;
  487. LOC_REFERENCE,LOC_MEM :
  488. begin
  489. del_reference(p^.left^.location.reference);
  490. p^.location.register:=getregister32;
  491. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,
  492. newreference(p^.left^.location.reference),p^.location.register)));
  493. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,p^.location.register)));
  494. end;
  495. end;
  496. end;
  497. end;
  498. end.
  499. {
  500. $Log$
  501. Revision 1.12 1998-11-26 21:45:29 jonas
  502. - removed A_CLTD opcode (use A_CDQ instead)
  503. * changed cbw, cwde and cwd to cbtw, cwtl and cwtd in att_op2str array
  504. * in daopt386: adapted AsmInstr array to reflect changes + fixed line too long
  505. Revision 1.11 1998/11/05 14:26:02 peter
  506. * fixed shlshr which would push ecx when not needed
  507. Revision 1.10 1998/10/20 13:12:38 peter
  508. * fixed 'not not boolean', the location was not set to register
  509. Revision 1.9 1998/10/20 08:06:42 pierre
  510. * several memory corruptions due to double freemem solved
  511. => never use p^.loc.location:=p^.left^.loc.location;
  512. + finally I added now by default
  513. that ra386dir translates global and unit symbols
  514. + added a first field in tsymtable and
  515. a nextsym field in tsym
  516. (this allows to obtain ordered type info for
  517. records and objects in gdb !)
  518. Revision 1.8 1998/10/09 08:56:24 pierre
  519. * several memory leaks fixed
  520. Revision 1.7 1998/09/17 09:42:17 peter
  521. + pass_2 for cg386
  522. * Message() -> CGMessage() for pass_1/pass_2
  523. Revision 1.6 1998/09/09 14:37:37 florian
  524. * mod/div for cardinal type fixed
  525. Revision 1.5 1998/08/23 16:07:20 florian
  526. * internalerror with mod/div fixed
  527. Revision 1.4 1998/08/18 09:24:38 pierre
  528. * small warning position bug fixed
  529. * support_mmx switches splitting was missing
  530. * rhide error and warning output corrected
  531. Revision 1.3 1998/06/05 17:44:12 peter
  532. * splitted cgi386
  533. Revision 1.2 1998/06/02 17:02:59 pierre
  534. * with node corrected for objects
  535. * small bugs for SUPPORT_MMX fixed
  536. Revision 1.1 1998/06/01 16:50:18 peter
  537. + boolean -> ord conversion
  538. * fixed ord -> boolean conversion
  539. }