navrmat.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. {
  2. Copyright (c) 1998-2008 by Florian Klaempfl
  3. Generates AVR assembler for math nodes
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit navrmat;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. node,nmat,ncgmat;
  22. type
  23. tavrmoddivnode = class(tmoddivnode)
  24. function first_moddivint: tnode;override;
  25. procedure pass_generate_code;override;
  26. end;
  27. tavrnotnode = class(tcgnotnode)
  28. procedure second_boolean;override;
  29. end;
  30. tavrshlshrnode = class(tcgshlshrnode)
  31. procedure second_integer;override;
  32. end;
  33. implementation
  34. uses
  35. globtype,systems,
  36. cutils,verbose,globals,constexp,
  37. symtype,symdef,
  38. aasmbase,aasmcpu,aasmtai,aasmdata,
  39. defutil,
  40. cgbase,cgobj,hlcgobj,cgutils,
  41. pass_2,procinfo,
  42. ncon,
  43. cpubase,
  44. ncgutil,cgcpu;
  45. {*****************************************************************************
  46. TAVRMODDIVNODE
  47. *****************************************************************************}
  48. function tavrmoddivnode.first_moddivint: tnode;
  49. var
  50. power : longint;
  51. begin
  52. if (right.nodetype=ordconstn) and
  53. (nodetype=divn) and
  54. (ispowerof2(tordconstnode(right).value,power) or
  55. (tordconstnode(right).value=1) or
  56. (tordconstnode(right).value=int64(-1))
  57. ) and
  58. not(is_64bitint(resultdef)) then
  59. result:=nil
  60. else
  61. result:=inherited first_moddivint;
  62. end;
  63. procedure tavrmoddivnode.pass_generate_code;
  64. var
  65. power : longint;
  66. numerator,
  67. helper1,
  68. helper2,
  69. resultreg : tregister;
  70. size : Tcgsize;
  71. procedure genOrdConstNodeDiv;
  72. begin
  73. {
  74. if tordconstnode(right).value=0 then
  75. internalerror(2005061701)
  76. else if tordconstnode(right).value=1 then
  77. cg.a_load_reg_reg(current_asmdata.CurrAsmList, OS_INT, OS_INT, numerator, resultreg)
  78. else if (tordconstnode(right).value = int64(-1)) then
  79. begin
  80. // note: only in the signed case possible..., may overflow
  81. current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_MVN,
  82. resultreg,numerator),toppostfix(ord(cs_check_overflow in current_settings.localswitches)*ord(PF_S))));
  83. end
  84. else if ispowerof2(tordconstnode(right).value,power) then
  85. begin
  86. if (is_signed(right.resultdef)) then
  87. begin
  88. helper1:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  89. helper2:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  90. shifterop_reset(so);
  91. so.shiftmode:=SM_ASR;
  92. so.shiftimm:=31;
  93. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_shifterop(A_MOV,helper1,numerator,so));
  94. shifterop_reset(so);
  95. so.shiftmode:=SM_LSR;
  96. so.shiftimm:=32-power;
  97. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,helper2,numerator,helper1,so));
  98. shifterop_reset(so);
  99. so.shiftmode:=SM_ASR;
  100. so.shiftimm:=power;
  101. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_shifterop(A_MOV,resultreg,helper2,so));
  102. end
  103. else
  104. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SHR,OS_INT,power,numerator,resultreg)
  105. end;
  106. }
  107. end;
  108. procedure genOrdConstNodeMod;
  109. var
  110. modreg, maskreg, tempreg : tregister;
  111. begin
  112. {
  113. if (tordconstnode(right).value = 0) then begin
  114. internalerror(2005061702);
  115. end
  116. else if (abs(tordconstnode(right).value.svalue) = 1) then
  117. begin
  118. // x mod +/-1 is always zero
  119. cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_INT, 0, resultreg);
  120. end
  121. else if (ispowerof2(tordconstnode(right).value, power)) then
  122. begin
  123. if (is_signed(right.resultdef)) then begin
  124. tempreg := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
  125. maskreg := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
  126. modreg := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
  127. cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_INT, abs(tordconstnode(right).value.svalue)-1, modreg);
  128. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SAR, OS_INT, 31, numerator, maskreg);
  129. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_AND, OS_INT, numerator, modreg, tempreg);
  130. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_ANDC, maskreg, maskreg, modreg));
  131. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_SUBFIC, modreg, tempreg, 0));
  132. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SUBFE, modreg, modreg, modreg));
  133. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_AND, OS_INT, modreg, maskreg, maskreg);
  134. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_OR, OS_INT, maskreg, tempreg, resultreg);
  135. end else begin
  136. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_AND, OS_INT, tordconstnode(right).value.svalue-1, numerator, resultreg);
  137. end;
  138. end else begin
  139. genOrdConstNodeDiv();
  140. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_MUL, OS_INT, tordconstnode(right).value.svalue, resultreg, resultreg);
  141. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_SUB, OS_INT, resultreg, numerator, resultreg);
  142. end;
  143. }
  144. end;
  145. begin
  146. secondpass(left);
  147. secondpass(right);
  148. location_copy(location,left.location);
  149. {$ifdef dummy}
  150. { put numerator in register }
  151. size:=def_cgsize(left.resultdef);
  152. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,
  153. left.resultdef,left.resultdef,true);
  154. location_copy(location,left.location);
  155. numerator:=location.register;
  156. resultreg:=location.register;
  157. if location.loc=LOC_CREGISTER then
  158. begin
  159. location.loc := LOC_REGISTER;
  160. location.register := cg.getintregister(current_asmdata.CurrAsmList,size);
  161. resultreg:=location.register;
  162. end
  163. else if (nodetype=modn) or (right.nodetype=ordconstn) then
  164. begin
  165. // for a modulus op, and for const nodes we need the result register
  166. // to be an extra register
  167. resultreg:=cg.getintregister(current_asmdata.CurrAsmList,size);
  168. end;
  169. if right.nodetype=ordconstn then
  170. begin
  171. if nodetype=divn then
  172. genOrdConstNodeDiv
  173. else
  174. genOrdConstNodeMod;
  175. end;
  176. location.register:=resultreg;
  177. { unsigned division/module can only overflow in case of division by zero }
  178. { (but checking this overflow flag is more convoluted than performing a }
  179. { simple comparison with 0) }
  180. if is_signed(right.resultdef) then
  181. cg.g_overflowcheck(current_asmdata.CurrAsmList,location,resultdef);
  182. {$endif dummy}
  183. end;
  184. {*****************************************************************************
  185. TAVRNOTNODE
  186. *****************************************************************************}
  187. procedure tavrnotnode.second_boolean;
  188. var
  189. hl : tasmlabel;
  190. tmpreg : tregister;
  191. i : longint;
  192. begin
  193. { if the location is LOC_JUMP, we do the secondpass after the
  194. labels are allocated
  195. }
  196. if left.expectloc=LOC_JUMP then
  197. begin
  198. hl:=current_procinfo.CurrTrueLabel;
  199. current_procinfo.CurrTrueLabel:=current_procinfo.CurrFalseLabel;
  200. current_procinfo.CurrFalseLabel:=hl;
  201. secondpass(left);
  202. if left.location.loc<>LOC_JUMP then
  203. internalerror(2012081304);
  204. maketojumpbool(current_asmdata.CurrAsmList,left,lr_load_regvars);
  205. hl:=current_procinfo.CurrTrueLabel;
  206. current_procinfo.CurrTrueLabel:=current_procinfo.CurrFalseLabel;
  207. current_procinfo.CurrFalseLabel:=hl;
  208. location.loc:=LOC_JUMP;
  209. end
  210. else
  211. begin
  212. secondpass(left);
  213. case left.location.loc of
  214. LOC_FLAGS :
  215. begin
  216. location_copy(location,left.location);
  217. inverse_flags(location.resflags);
  218. end;
  219. LOC_REGISTER,LOC_CREGISTER,LOC_REFERENCE,LOC_CREFERENCE,
  220. LOC_SUBSETREG,LOC_CSUBSETREG,LOC_SUBSETREF,LOC_CSUBSETREF :
  221. begin
  222. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
  223. current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_CPI,left.location.register,0));
  224. tmpreg:=left.location.register;
  225. { avr has no cpci, so we use the first register as "zero" register }
  226. for i:=2 to tcgsize2size[left.location.size] do
  227. begin
  228. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CPC,tmpreg,left.location.register));
  229. end;
  230. location_reset(location,LOC_FLAGS,OS_NO);
  231. location.resflags:=F_EQ;
  232. end;
  233. else
  234. internalerror(2003042401);
  235. end;
  236. end;
  237. end;
  238. procedure tavrshlshrnode.second_integer;
  239. var
  240. op : topcg;
  241. opdef: tdef;
  242. hcountreg : tregister;
  243. opsize : tcgsize;
  244. shiftval : longint;
  245. begin
  246. { determine operator }
  247. case nodetype of
  248. shln: op:=OP_SHL;
  249. shrn: op:=OP_SHR;
  250. else
  251. internalerror(2013120102);
  252. end;
  253. opsize:=left.location.size;
  254. opdef:=left.resultdef;
  255. if not(left.location.loc in [LOC_CREGISTER,LOC_REGISTER]) or
  256. { location_force_reg can be also used to change the size of a register }
  257. (left.location.size<>opsize) then
  258. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,opdef,true);
  259. location_reset(location,LOC_REGISTER,opsize);
  260. location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
  261. { shifting by a constant directly coded: }
  262. if (right.nodetype=ordconstn) then
  263. begin
  264. { shl/shr must "wrap around", so use ... and 31 }
  265. { In TP, "byte/word shl 16 = 0", so no "and 15" in case of
  266. a 16 bit ALU }
  267. if tcgsize2size[opsize]<=4 then
  268. shiftval:=tordconstnode(right).value.uvalue and 31
  269. else
  270. shiftval:=tordconstnode(right).value.uvalue and 63;
  271. hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,op,opdef,
  272. shiftval,left.location.register,location.register);
  273. end
  274. else
  275. begin
  276. { load right operators in a register - this
  277. is done since most target cpu which will use this
  278. node do not support a shift count in a mem. location (cec)
  279. }
  280. hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,sinttype,true);
  281. hlcg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,op,opdef,right.location.register,left.location.register,location.register);
  282. end;
  283. { shl/shr nodes return the same type as left, which can be different
  284. from opdef }
  285. if opdef<>resultdef then
  286. begin
  287. hcountreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
  288. hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,opdef,resultdef,location.register,hcountreg);
  289. location.register:=hcountreg;
  290. end;
  291. end;
  292. begin
  293. cmoddivnode:=tavrmoddivnode;
  294. cnotnode:=tavrnotnode;
  295. cshlshrnode:=tavrshlshrnode;
  296. end.