cg68kmat.pas 21 KB

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