cg68kmat.pas 20 KB

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