cg68kmat.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 by Florian Klaempfl
  4. Generate m68k 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 cg68kmat;
  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. m68k,cga68k,tgen68k;
  32. {*****************************************************************************
  33. SecondModDiv
  34. *****************************************************************************}
  35. { D0 and D1 used as temp (ok) }
  36. procedure secondmoddiv(var p : ptree);
  37. var
  38. hreg1 : tregister;
  39. power : longint;
  40. hl : plabel;
  41. reg: tregister;
  42. pushed: boolean;
  43. hl1: plabel;
  44. begin
  45. secondpass(p^.left);
  46. set_location(p^.location,p^.left^.location);
  47. pushed:=maybe_push(p^.right^.registers32,p);
  48. secondpass(p^.right);
  49. if pushed then restore(p);
  50. { put numerator in register }
  51. if p^.left^.location.loc<>LOC_REGISTER then
  52. begin
  53. if p^.left^.location.loc=LOC_CREGISTER then
  54. begin
  55. hreg1:=getregister32;
  56. emit_reg_reg(A_MOVE,S_L,p^.left^.location.register,hreg1);
  57. end
  58. else
  59. begin
  60. del_reference(p^.left^.location.reference);
  61. hreg1:=getregister32;
  62. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(p^.left^.location.reference),
  63. hreg1)));
  64. end;
  65. clear_location(p^.left^.location);
  66. p^.left^.location.loc:=LOC_REGISTER;
  67. p^.left^.location.register:=hreg1;
  68. end
  69. else hreg1:=p^.left^.location.register;
  70. if (p^.treetype=divn) and (p^.right^.treetype=ordconstn) and
  71. ispowerof2(p^.right^.value,power) then
  72. begin
  73. exprasmlist^.concat(new(pai68k, op_reg(A_TST, S_L, hreg1)));
  74. getlabel(hl);
  75. emitl(A_BPL,hl);
  76. if (power = 1) then
  77. exprasmlist^.concat(new(pai68k, op_const_reg(A_ADDQ, S_L,1, hreg1)))
  78. else
  79. Begin
  80. { optimize using ADDQ if possible! }
  81. if (p^.right^.value-1) < 9 then
  82. exprasmlist^.concat(new(pai68k, op_const_reg(A_ADDQ, S_L,p^.right^.value-1, hreg1)))
  83. else
  84. exprasmlist^.concat(new(pai68k, op_const_reg(A_ADD, S_L,p^.right^.value-1, hreg1)));
  85. end;
  86. emitl(A_LABEL, hl);
  87. if (power > 0) and (power < 9) then
  88. exprasmlist^.concat(new(pai68k, op_const_reg(A_ASR, S_L,power, hreg1)))
  89. else
  90. begin
  91. exprasmlist^.concat(new(pai68k, op_const_reg(A_MOVE,S_L,power, R_D0)));
  92. exprasmlist^.concat(new(pai68k, op_reg_reg(A_ASR,S_L,R_D0, hreg1)));
  93. end;
  94. end
  95. else
  96. begin
  97. { bring denominator to D1 }
  98. { D1 is always free, it's }
  99. { only used for temporary }
  100. { purposes }
  101. if (p^.right^.location.loc<>LOC_REGISTER) and
  102. (p^.right^.location.loc<>LOC_CREGISTER) then
  103. begin
  104. del_reference(p^.right^.location.reference);
  105. p^.left^.location.loc:=LOC_REGISTER;
  106. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(p^.right^.location.reference),R_D1)));
  107. end
  108. else
  109. begin
  110. ungetregister32(p^.right^.location.register);
  111. emit_reg_reg(A_MOVE,S_L,p^.right^.location.register,R_D1);
  112. end;
  113. { on entering this section D1 should contain the divisor }
  114. if (aktoptprocessor = MC68020) then
  115. begin
  116. { Check if divisor is ZERO - if so call HALT_ERROR }
  117. { with d0 = 200 (Division by zero!) }
  118. getlabel(hl1);
  119. exprasmlist^.concat(new(pai68k,op_reg(A_TST,S_L,R_D1)));
  120. { if not zero then simply continue on }
  121. emitl(A_BNE,hl1);
  122. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_L,200,R_D0)));
  123. emitcall('FPC_HALT_ERROR',true);
  124. emitl(A_LABEL,hl1);
  125. if (p^.treetype = modn) then
  126. Begin
  127. reg := getregister32;
  128. exprasmlist^.concat(new(pai68k,op_reg(A_CLR,S_L,reg)));
  129. getlabel(hl);
  130. { here what we do is prepare the high register with the }
  131. { correct sign. i.e we clear it, check if the low dword reg }
  132. { which will participate in the division is signed, if so we}
  133. { we extend the sign to the high doword register by inverting }
  134. { all the bits. }
  135. exprasmlist^.concat(new(pai68k,op_reg(A_TST,S_L,hreg1)));
  136. emitl(A_BPL,hl);
  137. exprasmlist^.concat(new(pai68k,op_reg(A_NOT,S_L,reg)));
  138. emitl(A_LABEL,hl);
  139. { reg:hreg1 / d1 }
  140. exprasmlist^.concat(new(pai68k,op_reg_reg_reg(A_DIVSL,S_L,R_D1,reg,hreg1)));
  141. { hreg1 already contains quotient }
  142. { looking for remainder }
  143. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,reg,hreg1)));
  144. ungetregister32(reg);
  145. end
  146. else
  147. { simple division... }
  148. Begin
  149. { reg:hreg1 / d1 }
  150. exprasmlist^.concat(new(pai68k,op_reg_reg(A_DIVS,S_L,R_D1,hreg1)));
  151. end;
  152. end
  153. else { MC68000 operations }
  154. begin
  155. { put numerator in d0 }
  156. emit_reg_reg(A_MOVE,S_L,hreg1,R_D0);
  157. { operation to perform on entry to both }
  158. { routines... d0/d1 }
  159. { return result in d0 }
  160. if p^.treetype = divn then
  161. emitcall('FPC_LONGDIV',true)
  162. else
  163. emitcall('FPC_LONGMOD',true);
  164. emit_reg_reg(A_MOVE,S_L,R_D0,hreg1);
  165. end; { endif }
  166. end;
  167. { this registers are always used when div/mod are present }
  168. usedinproc:=usedinproc or ($800 shr word(R_D1));
  169. usedinproc:=usedinproc or ($800 shr word(R_D0));
  170. clear_location(p^.location);
  171. p^.location.loc:=LOC_REGISTER;
  172. p^.location.register:=hreg1;
  173. end;
  174. {*****************************************************************************
  175. SecondShlShr
  176. *****************************************************************************}
  177. { D6 used as scratch (ok) }
  178. procedure secondshlshr(var p : ptree);
  179. var
  180. hregister1,hregister2,hregister3 : tregister;
  181. op : tasmop;
  182. pushed : boolean;
  183. begin
  184. secondpass(p^.left);
  185. pushed:=maybe_push(p^.right^.registers32,p);
  186. secondpass(p^.right);
  187. if pushed then restore(p);
  188. { load left operators in a register }
  189. if p^.left^.location.loc<>LOC_REGISTER then
  190. begin
  191. if p^.left^.location.loc=LOC_CREGISTER then
  192. begin
  193. hregister1:=getregister32;
  194. emit_reg_reg(A_MOVE,S_L,p^.left^.location.register,
  195. hregister1);
  196. end
  197. else
  198. begin
  199. del_reference(p^.left^.location.reference);
  200. hregister1:=getregister32;
  201. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(p^.left^.location.reference),
  202. hregister1)));
  203. end;
  204. end
  205. else hregister1:=p^.left^.location.register;
  206. { determine operator }
  207. if p^.treetype=shln then
  208. op:=A_LSL
  209. else
  210. op:=A_LSR;
  211. { shifting by a constant directly decode: }
  212. if (p^.right^.treetype=ordconstn) then
  213. begin
  214. if (p^.right^.location.reference.offset and 31 > 0) and (p^.right^.location.reference.offset and 31 < 9) then
  215. exprasmlist^.concat(new(pai68k,op_const_reg(op,S_L,p^.right^.location.reference.offset and 31,
  216. hregister1)))
  217. else
  218. begin
  219. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_L,p^.right^.location.reference.offset and 31,
  220. R_D6)));
  221. exprasmlist^.concat(new(pai68k,op_reg_reg(op,S_L,R_D6,hregister1)));
  222. end;
  223. p^.location.loc:=LOC_REGISTER;
  224. p^.location.register:=hregister1;
  225. end
  226. else
  227. begin
  228. { load right operators in a register }
  229. if p^.right^.location.loc<>LOC_REGISTER then
  230. begin
  231. if p^.right^.location.loc=LOC_CREGISTER then
  232. begin
  233. hregister2:=getregister32;
  234. emit_reg_reg(A_MOVE,S_L,p^.right^.location.register,
  235. hregister2);
  236. end
  237. else
  238. begin
  239. del_reference(p^.right^.location.reference);
  240. hregister2:=getregister32;
  241. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(p^.right^.location.reference),
  242. hregister2)));
  243. end;
  244. end
  245. else hregister2:=p^.right^.location.register;
  246. emit_reg_reg(op,S_L,hregister2,hregister1);
  247. p^.location.register:=hregister1;
  248. end;
  249. { this register is always used when shl/shr are present }
  250. usedinproc:=usedinproc or ($800 shr byte(R_D6));
  251. end;
  252. {*****************************************************************************
  253. SecondUmMinus
  254. *****************************************************************************}
  255. procedure secondumminus(var p : ptree);
  256. begin
  257. secondpass(p^.left);
  258. p^.location.loc:=LOC_REGISTER;
  259. case p^.left^.location.loc of
  260. LOC_REGISTER : begin
  261. p^.location.register:=p^.left^.location.register;
  262. exprasmlist^.concat(new(pai68k,op_reg(A_NEG,S_L,p^.location.register)));
  263. end;
  264. LOC_CREGISTER : begin
  265. p^.location.register:=getregister32;
  266. emit_reg_reg(A_MOVE,S_L,p^.location.register,
  267. p^.location.register);
  268. exprasmlist^.concat(new(pai68k,op_reg(A_NEG,S_L,p^.location.register)));
  269. end;
  270. LOC_REFERENCE,LOC_MEM :
  271. begin
  272. del_reference(p^.left^.location.reference);
  273. { change sign of a floating point }
  274. { in the case of emulation, get }
  275. { a free register, and change sign }
  276. { manually. }
  277. { otherwise simply load into an FPU}
  278. { register. }
  279. if (p^.left^.resulttype^.deftype=floatdef) and
  280. (pfloatdef(p^.left^.resulttype)^.typ<>f32bit) then
  281. begin
  282. { move to FPU }
  283. floatload(pfloatdef(p^.left^.resulttype)^.typ,
  284. p^.left^.location.reference,p^.location);
  285. if (cs_fp_emulation) in aktmoduleswitches then
  286. { if in emulation mode change sign manually }
  287. exprasmlist^.concat(new(pai68k,op_const_reg(A_BCHG,S_L,31,
  288. p^.location.fpureg)))
  289. else
  290. exprasmlist^.concat(new(pai68k,op_reg(A_FNEG,S_FX,
  291. p^.location.fpureg)));
  292. end
  293. else
  294. begin
  295. p^.location.register:=getregister32;
  296. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,
  297. newreference(p^.left^.location.reference),
  298. p^.location.register)));
  299. exprasmlist^.concat(new(pai68k,op_reg(A_NEG,S_L,p^.location.register)));
  300. end;
  301. end;
  302. LOC_FPU : begin
  303. p^.location.loc:=LOC_FPU;
  304. p^.location.fpureg := p^.left^.location.fpureg;
  305. if (cs_fp_emulation) in aktmoduleswitches then
  306. exprasmlist^.concat(new(pai68k,op_const_reg(A_BCHG,S_L,31,p^.location.fpureg)))
  307. else
  308. exprasmlist^.concat(new(pai68k,op_reg(A_FNEG,S_FX,p^.location.fpureg)));
  309. end;
  310. end;
  311. { emitoverflowcheck;}
  312. end;
  313. {*****************************************************************************
  314. SecondNot
  315. *****************************************************************************}
  316. procedure secondnot(var p : ptree);
  317. const
  318. flagsinvers : array[F_E..F_BE] of tresflags =
  319. (F_NE,F_E,F_LE,F_GE,F_L,F_G,F_NC,F_C,
  320. F_A,F_AE,F_B,F_BE);
  321. var
  322. hl : plabel;
  323. begin
  324. if (p^.resulttype^.deftype=orddef) and
  325. (porddef(p^.resulttype)^.typ=bool8bit) then
  326. begin
  327. case p^.location.loc of
  328. LOC_JUMP : begin
  329. hl:=truelabel;
  330. truelabel:=falselabel;
  331. falselabel:=hl;
  332. secondpass(p^.left);
  333. maketojumpbool(p^.left);
  334. hl:=truelabel;
  335. truelabel:=falselabel;
  336. falselabel:=hl;
  337. end;
  338. LOC_FLAGS : begin
  339. secondpass(p^.left);
  340. p^.location.resflags:=flagsinvers[p^.left^.location.resflags];
  341. end;
  342. LOC_REGISTER : begin
  343. secondpass(p^.left);
  344. p^.location.register:=p^.left^.location.register;
  345. exprasmlist^.concat(new(pai68k,op_const_reg(A_EOR,S_B,1,p^.location.register)));
  346. end;
  347. LOC_CREGISTER : begin
  348. secondpass(p^.left);
  349. p^.location.loc:=LOC_REGISTER;
  350. p^.location.register:=getregister32;
  351. emit_reg_reg(A_MOVE,S_B,p^.left^.location.register,
  352. p^.location.register);
  353. exprasmlist^.concat(new(pai68k,op_const_reg(A_EOR,S_B,1,p^.location.register)));
  354. end;
  355. LOC_REFERENCE,LOC_MEM : begin
  356. secondpass(p^.left);
  357. del_reference(p^.left^.location.reference);
  358. p^.location.loc:=LOC_REGISTER;
  359. p^.location.register:=getregister32;
  360. if p^.left^.location.loc=LOC_CREGISTER then
  361. emit_reg_reg(A_MOVE,S_B,p^.left^.location.register,
  362. p^.location.register)
  363. else
  364. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_B,
  365. newreference(p^.left^.location.reference),
  366. p^.location.register)));
  367. exprasmlist^.concat(new(pai68k,op_const_reg(A_EOR,S_B,1,p^.location.register)));
  368. end;
  369. end;
  370. end
  371. else
  372. begin
  373. secondpass(p^.left);
  374. p^.location.loc:=LOC_REGISTER;
  375. case p^.left^.location.loc of
  376. LOC_REGISTER : begin
  377. p^.location.register:=p^.left^.location.register;
  378. exprasmlist^.concat(new(pai68k,op_reg(A_NOT,S_L,p^.location.register)));
  379. end;
  380. LOC_CREGISTER : begin
  381. p^.location.register:=getregister32;
  382. emit_reg_reg(A_MOVE,S_L,p^.left^.location.register,
  383. p^.location.register);
  384. exprasmlist^.concat(new(pai68k,op_reg(A_NOT,S_L,p^.location.register)));
  385. end;
  386. LOC_REFERENCE,LOC_MEM :
  387. begin
  388. del_reference(p^.left^.location.reference);
  389. p^.location.register:=getregister32;
  390. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,
  391. newreference(p^.left^.location.reference),
  392. p^.location.register)));
  393. exprasmlist^.concat(new(pai68k,op_reg(A_NOT,S_L,p^.location.register)));
  394. end;
  395. end;
  396. {if p^.left^.location.loc=loc_register then
  397. p^.location.register:=p^.left^.location.register
  398. else
  399. begin
  400. del_locref(p^.left^.location);
  401. p^.location.register:=getregister32;
  402. exprasmlist^.concat(new(pai68k,op_loc_reg(A_MOV,S_L,
  403. p^.left^.location,
  404. p^.location.register)));
  405. end;
  406. exprasmlist^.concat(new(pai68k,op_reg(A_NOT,S_L,p^.location.register)));}
  407. end;
  408. end;
  409. end.
  410. {
  411. $Log$
  412. Revision 1.3 1998-10-13 16:50:10 pierre
  413. * undid some changes of Peter that made the compiler wrong
  414. for m68k (I had to reinsert some ifdefs)
  415. * removed several memory leaks under m68k
  416. * removed the meory leaks for assembler readers
  417. * cross compiling shoud work again better
  418. ( crosscompiling sysamiga works
  419. but as68k still complain about some code !)
  420. Revision 1.2 1998/09/14 10:44:01 peter
  421. * all internal RTL functions start with FPC_
  422. Revision 1.1 1998/09/01 09:07:09 peter
  423. * m68k fixes, splitted cg68k like cgi386
  424. }