n68kmat.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. Generate 680x0 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 n68kmat;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. node,nmat;
  23. type
  24. tm68kmoddivnode = class(tmoddivnode)
  25. procedure pass_2;override;
  26. end;
  27. tm68kshlshrnode = class(tshlshrnode)
  28. procedure pass_2;override;
  29. end;
  30. tm68knotnode = class(tnotnode)
  31. procedure pass_2;override;
  32. end;
  33. implementation
  34. uses
  35. globtype,systems,
  36. cutils,verbose,globals,
  37. symconst,symdef,aasmbase,aasmtai,aasmcpu,defbase,
  38. cginfo,cgbase,pass_1,pass_2,
  39. ncon,
  40. cpubase,cpuinfo,paramgr,
  41. tgobj,ncgutil,cgobj,rgobj,rgcpu,cgcpu,cg64f32;
  42. {*****************************************************************************
  43. TM68kMODDIVNODE
  44. *****************************************************************************}
  45. procedure tm68kmoddivnode.pass_2;
  46. var
  47. hreg1 : tregister;
  48. hdenom,hnumerator : tregister;
  49. shrdiv,popeax,popedx : boolean;
  50. power : longint;
  51. hl : tasmlabel;
  52. pushedregs : tmaybesave;
  53. begin
  54. shrdiv := false;
  55. secondpass(left);
  56. if codegenerror then
  57. exit;
  58. maybe_save(exprasmlist,right.registers32,left.location,pushedregs);
  59. secondpass(right);
  60. maybe_restore(exprasmlist,left.location,pushedregs);
  61. if codegenerror then
  62. exit;
  63. location_copy(location,left.location);
  64. if is_64bitint(resulttype.def) then
  65. begin
  66. { should be handled in pass_1 (JM) }
  67. internalerror(200109052);
  68. end
  69. else
  70. begin
  71. { put numerator in register }
  72. location_force_reg(exprasmlist,left.location,OS_INT,false);
  73. hreg1:=left.location.register;
  74. if (nodetype=divn) and
  75. (right.nodetype=ordconstn) and
  76. ispowerof2(tordconstnode(right).value,power) then
  77. Begin
  78. shrdiv := true;
  79. { for signed numbers, the numerator must be adjusted before the
  80. shift instruction, but not wih unsigned numbers! Otherwise,
  81. "Cardinal($ffffffff) div 16" overflows! (JM) }
  82. If is_signed(left.resulttype.def) Then
  83. Begin
  84. objectlibrary.getlabel(hl);
  85. cg.a_cmp_const_reg_label(exprasmlist,OS_INT,OC_GT,0,hreg1,hl);
  86. if power=1 then
  87. cg.a_op_const_reg(exprasmlist,OP_ADD,1,hreg1)
  88. else
  89. cg.a_op_const_reg(exprasmlist,OP_ADD,
  90. tordconstnode(right).value-1,hreg1);
  91. cg.a_label(exprasmlist,hl);
  92. cg.a_op_const_reg(exprasmlist,OP_SAR,power,hreg1);
  93. End
  94. Else { not signed }
  95. Begin
  96. cg.a_op_const_reg(exprasmlist,OP_SHR,power,hreg1);
  97. end;
  98. End
  99. else
  100. begin
  101. { bring denominator to hdenom }
  102. { hdenom is always free, it's }
  103. { only used for temporary }
  104. { purposes }
  105. hdenom := rg.getregisterint(exprasmlist);
  106. if right.location.loc<>LOC_CREGISTER then
  107. location_release(exprasmlist,right.location);
  108. cg.a_load_loc_reg(exprasmlist,right.location,hdenom);
  109. if nodetype = modn then
  110. begin
  111. hnumerator := rg.getregisterint(exprasmlist);
  112. cg.a_load_reg_reg(exprasmlist,OS_INT,hreg1,hnumerator);
  113. end;
  114. { verify if the divisor is zero, if so return an error
  115. immediately
  116. }
  117. objectlibrary.getlabel(hl);
  118. cg.a_cmp_const_reg_label(exprasmlist,OS_INT,OC_NE,0,hdenom,hl);
  119. cg.a_param_const(exprasmlist,OS_S32,200,paramanager.getintparaloc(1));
  120. cg.a_call_name(exprasmlist,'FPC_HANDLERROR');
  121. cg.a_label(exprasmlist,hl);
  122. if is_signed(left.resulttype.def) then
  123. cg.a_op_reg_reg(exprasmlist,OP_IDIV,OS_INT,hdenom,hreg1)
  124. else
  125. cg.a_op_reg_reg(exprasmlist,OP_DIV,OS_INT,hdenom,hreg1);
  126. if nodetype = modn then
  127. begin
  128. {$warning modnode should be tested}
  129. { I mod J = I - (I div J) * J }
  130. cg.a_op_reg_reg(exprasmlist,OP_IMUL,OS_INT,hdenom,hreg1);
  131. cg.a_op_reg_reg(exprasmlist,OP_SUB,OS_INT,hnumerator,hreg1);
  132. rg.ungetregister(exprasmlist,hnumerator);
  133. end;
  134. end;
  135. location_reset(location,LOC_REGISTER,OS_INT);
  136. location.register:=hreg1;
  137. end;
  138. cg.g_overflowcheck(exprasmlist,self);
  139. end;
  140. {*****************************************************************************
  141. TI386SHLRSHRNODE
  142. *****************************************************************************}
  143. procedure tm68kshlshrnode.pass_2;
  144. var
  145. hcountreg : tregister;
  146. op : topcg;
  147. l1,l2,l3 : tasmlabel;
  148. pushedregs : tmaybesave;
  149. freescratch : boolean;
  150. begin
  151. freescratch:=false;
  152. secondpass(left);
  153. maybe_save(exprasmlist,right.registers32,left.location,pushedregs);
  154. secondpass(right);
  155. maybe_restore(exprasmlist,left.location,pushedregs);
  156. { determine operator }
  157. case nodetype of
  158. shln: op:=OP_SHL;
  159. shrn: op:=OP_SHR;
  160. end;
  161. if is_64bitint(left.resulttype.def) then
  162. begin
  163. location_reset(location,LOC_REGISTER,OS_64);
  164. { load left operator in a register }
  165. location_force_reg(exprasmlist,left.location,OS_64,false);
  166. location_copy(location,left.location);
  167. if (right.nodetype=ordconstn) then
  168. begin
  169. cg64.a_op64_const_reg(exprasmlist,op,tordconstnode(right).value,
  170. joinreg64(location.registerlow,location.registerhigh));
  171. end
  172. else
  173. begin
  174. { load right operators in a register - this
  175. is done since most target cpu which will use this
  176. node do not support a shift count in a mem. location (cec)
  177. }
  178. if right.location.loc<>LOC_REGISTER then
  179. begin
  180. if right.location.loc<>LOC_CREGISTER then
  181. location_release(exprasmlist,right.location);
  182. hcountreg:=cg.get_scratch_reg_int(exprasmlist);
  183. cg.a_load_loc_reg(exprasmlist,right.location,hcountreg);
  184. freescratch := true;
  185. end
  186. else
  187. hcountreg:=right.location.register;
  188. cg64.a_op64_reg_reg(exprasmlist,op,hcountreg,
  189. joinreg64(location.registerlow,location.registerhigh));
  190. if freescratch then
  191. cg.free_scratch_reg(exprasmlist,hcountreg);
  192. end;
  193. end
  194. else
  195. begin
  196. { load left operators in a register }
  197. location_copy(location,left.location);
  198. location_force_reg(exprasmlist,location,OS_INT,false);
  199. { shifting by a constant directly coded: }
  200. if (right.nodetype=ordconstn) then
  201. begin
  202. { l shl 32 should 0 imho, but neither TP nor Delphi do it in this way (FK)
  203. if right.value<=31 then
  204. }
  205. cg.a_op_const_reg(exprasmlist,op,tordconstnode(right).value and 31,
  206. location.register);
  207. {
  208. else
  209. emit_reg_reg(A_XOR,S_L,hregister1,
  210. hregister1);
  211. }
  212. end
  213. else
  214. begin
  215. { load right operators in a register - this
  216. is done since most target cpu which will use this
  217. node do not support a shift count in a mem. location (cec)
  218. }
  219. if right.location.loc<>LOC_REGISTER then
  220. begin
  221. if right.location.loc<>LOC_CREGISTER then
  222. location_release(exprasmlist,right.location);
  223. hcountreg:=cg.get_scratch_reg_int(exprasmlist);
  224. freescratch := true;
  225. cg.a_load_loc_reg(exprasmlist,right.location,hcountreg);
  226. end
  227. else
  228. hcountreg:=right.location.register;
  229. cg.a_op_reg_reg(exprasmlist,op,OS_INT,hcountreg,location.register);
  230. if freescratch then
  231. cg.free_scratch_reg(exprasmlist,hcountreg);
  232. end;
  233. end;
  234. end;
  235. {*****************************************************************************
  236. TM68KNOTNODE
  237. *****************************************************************************}
  238. procedure tm68knotnode.pass_2;
  239. var
  240. hl : tasmlabel;
  241. opsize : tcgsize;
  242. begin
  243. opsize:=def_cgsize(resulttype.def);
  244. if is_boolean(resulttype.def) then
  245. begin
  246. { the second pass could change the location of left }
  247. { if it is a register variable, so we've to do }
  248. { this before the case statement }
  249. if left.location.loc<>LOC_JUMP then
  250. secondpass(left);
  251. case left.location.loc of
  252. LOC_JUMP :
  253. begin
  254. location_reset(location,LOC_JUMP,OS_NO);
  255. hl:=truelabel;
  256. truelabel:=falselabel;
  257. falselabel:=hl;
  258. secondpass(left);
  259. maketojumpbool(exprasmlist,left,lr_load_regvars);
  260. hl:=truelabel;
  261. truelabel:=falselabel;
  262. falselabel:=hl;
  263. end;
  264. LOC_FLAGS :
  265. begin
  266. location_copy(location,left.location);
  267. location_release(exprasmlist,left.location);
  268. inverse_flags(location.resflags);
  269. end;
  270. LOC_CONSTANT,
  271. LOC_REGISTER,
  272. LOC_CREGISTER,
  273. LOC_REFERENCE,
  274. LOC_CREFERENCE :
  275. begin
  276. location_force_reg(exprasmlist,left.location,def_cgsize(resulttype.def),true);
  277. exprasmlist.concat(taicpu.op_reg(A_TST,tcgsize2opsize[opsize],left.location.register));
  278. location_release(exprasmlist,left.location);
  279. location_reset(location,LOC_FLAGS,OS_NO);
  280. location.resflags:=F_E;
  281. end;
  282. else
  283. internalerror(200203224);
  284. end;
  285. end
  286. else if is_64bitint(left.resulttype.def) then
  287. begin
  288. secondpass(left);
  289. location_copy(location,left.location);
  290. location_force_reg(exprasmlist,location,OS_64,false);
  291. cg64.a_op64_loc_reg(exprasmlist,OP_NOT,location,
  292. joinreg64(location.registerlow,location.registerhigh));
  293. end
  294. else
  295. begin
  296. secondpass(left);
  297. location_copy(location,left.location);
  298. location_force_reg(exprasmlist,location,opsize,false);
  299. cg.a_op_reg_reg(exprasmlist,OP_NOT,opsize,location.register,location.register);
  300. end;
  301. end;
  302. begin
  303. cmoddivnode:=tm68kmoddivnode;
  304. cshlshrnode:=tm68kshlshrnode;
  305. cnotnode:=tm68knotnode;
  306. end.
  307. {
  308. $Log$
  309. Revision 1.2 2002-08-15 08:13:54 carl
  310. - a_load_sym_ofs_reg removed
  311. * loadvmt now calls loadaddr_ref_reg instead
  312. Revision 1.1 2002/08/14 19:16:34 carl
  313. + m68k type conversion nodes
  314. + started some mathematical nodes
  315. * out of bound references should now be handled correctly
  316. }