navrmat.pas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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. implementation
  31. uses
  32. globtype,systems,
  33. cutils,verbose,globals,constexp,
  34. aasmbase,aasmcpu,aasmtai,aasmdata,
  35. defutil,
  36. cgbase,cgobj,cgutils,
  37. pass_2,procinfo,
  38. ncon,
  39. cpubase,
  40. ncgutil,cgcpu;
  41. {*****************************************************************************
  42. TAVRMODDIVNODE
  43. *****************************************************************************}
  44. function tavrmoddivnode.first_moddivint: tnode;
  45. var
  46. power : longint;
  47. begin
  48. if (right.nodetype=ordconstn) and
  49. (nodetype=divn) and
  50. (ispowerof2(tordconstnode(right).value,power) or
  51. (tordconstnode(right).value=1) or
  52. (tordconstnode(right).value=int64(-1))
  53. ) and
  54. not(is_64bitint(resultdef)) then
  55. result:=nil
  56. else
  57. result:=inherited first_moddivint;
  58. end;
  59. procedure tavrmoddivnode.pass_generate_code;
  60. var
  61. power : longint;
  62. numerator,
  63. helper1,
  64. helper2,
  65. resultreg : tregister;
  66. size : Tcgsize;
  67. so : tshifterop;
  68. procedure genOrdConstNodeDiv;
  69. begin
  70. {
  71. if tordconstnode(right).value=0 then
  72. internalerror(2005061701)
  73. else if tordconstnode(right).value=1 then
  74. cg.a_load_reg_reg(current_asmdata.CurrAsmList, OS_INT, OS_INT, numerator, resultreg)
  75. else if (tordconstnode(right).value = int64(-1)) then
  76. begin
  77. // note: only in the signed case possible..., may overflow
  78. current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_MVN,
  79. resultreg,numerator),toppostfix(ord(cs_check_overflow in current_settings.localswitches)*ord(PF_S))));
  80. end
  81. else if ispowerof2(tordconstnode(right).value,power) then
  82. begin
  83. if (is_signed(right.resultdef)) then
  84. begin
  85. helper1:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  86. helper2:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  87. shifterop_reset(so);
  88. so.shiftmode:=SM_ASR;
  89. so.shiftimm:=31;
  90. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_shifterop(A_MOV,helper1,numerator,so));
  91. shifterop_reset(so);
  92. so.shiftmode:=SM_LSR;
  93. so.shiftimm:=32-power;
  94. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,helper2,numerator,helper1,so));
  95. shifterop_reset(so);
  96. so.shiftmode:=SM_ASR;
  97. so.shiftimm:=power;
  98. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_shifterop(A_MOV,resultreg,helper2,so));
  99. end
  100. else
  101. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SHR,OS_INT,power,numerator,resultreg)
  102. end;
  103. }
  104. end;
  105. procedure genOrdConstNodeMod;
  106. var
  107. modreg, maskreg, tempreg : tregister;
  108. begin
  109. {
  110. if (tordconstnode(right).value = 0) then begin
  111. internalerror(2005061702);
  112. end
  113. else if (abs(tordconstnode(right).value.svalue) = 1) then
  114. begin
  115. // x mod +/-1 is always zero
  116. cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_INT, 0, resultreg);
  117. end
  118. else if (ispowerof2(tordconstnode(right).value, power)) then
  119. begin
  120. if (is_signed(right.resultdef)) then begin
  121. tempreg := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
  122. maskreg := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
  123. modreg := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
  124. cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_INT, abs(tordconstnode(right).value.svalue)-1, modreg);
  125. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SAR, OS_INT, 31, numerator, maskreg);
  126. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_AND, OS_INT, numerator, modreg, tempreg);
  127. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_ANDC, maskreg, maskreg, modreg));
  128. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_SUBFIC, modreg, tempreg, 0));
  129. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SUBFE, modreg, modreg, modreg));
  130. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_AND, OS_INT, modreg, maskreg, maskreg);
  131. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_OR, OS_INT, maskreg, tempreg, resultreg);
  132. end else begin
  133. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_AND, OS_INT, tordconstnode(right).value.svalue-1, numerator, resultreg);
  134. end;
  135. end else begin
  136. genOrdConstNodeDiv();
  137. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_MUL, OS_INT, tordconstnode(right).value.svalue, resultreg, resultreg);
  138. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_SUB, OS_INT, resultreg, numerator, resultreg);
  139. end;
  140. }
  141. end;
  142. begin
  143. secondpass(left);
  144. secondpass(right);
  145. location_copy(location,left.location);
  146. {
  147. { put numerator in register }
  148. size:=def_cgsize(left.resultdef);
  149. location_force_reg(current_asmdata.CurrAsmList,left.location,
  150. size,true);
  151. location_copy(location,left.location);
  152. numerator:=location.register;
  153. resultreg:=location.register;
  154. if location.loc=LOC_CREGISTER then
  155. begin
  156. location.loc := LOC_REGISTER;
  157. location.register := cg.getintregister(current_asmdata.CurrAsmList,size);
  158. resultreg:=location.register;
  159. end
  160. else if (nodetype=modn) or (right.nodetype=ordconstn) then
  161. begin
  162. // for a modulus op, and for const nodes we need the result register
  163. // to be an extra register
  164. resultreg:=cg.getintregister(current_asmdata.CurrAsmList,size);
  165. end;
  166. if right.nodetype=ordconstn then
  167. begin
  168. if nodetype=divn then
  169. genOrdConstNodeDiv
  170. else
  171. genOrdConstNodeMod;
  172. end;
  173. location.register:=resultreg;
  174. { unsigned division/module can only overflow in case of division by zero }
  175. { (but checking this overflow flag is more convoluted than performing a }
  176. { simple comparison with 0) }
  177. if is_signed(right.resultdef) then
  178. cg.g_overflowcheck(current_asmdata.CurrAsmList,location,resultdef);
  179. }
  180. end;
  181. {*****************************************************************************
  182. TAVRNOTNODE
  183. *****************************************************************************}
  184. procedure tavrnotnode.second_boolean;
  185. var
  186. hl : tasmlabel;
  187. tmpreg : tregister;
  188. i : longint;
  189. begin
  190. { if the location is LOC_JUMP, we do the secondpass after the
  191. labels are allocated
  192. }
  193. if left.expectloc=LOC_JUMP then
  194. begin
  195. hl:=current_procinfo.CurrTrueLabel;
  196. current_procinfo.CurrTrueLabel:=current_procinfo.CurrFalseLabel;
  197. current_procinfo.CurrFalseLabel:=hl;
  198. secondpass(left);
  199. maketojumpbool(current_asmdata.CurrAsmList,left,lr_load_regvars);
  200. hl:=current_procinfo.CurrTrueLabel;
  201. current_procinfo.CurrTrueLabel:=current_procinfo.CurrFalseLabel;
  202. current_procinfo.CurrFalseLabel:=hl;
  203. location.loc:=LOC_JUMP;
  204. end
  205. else
  206. begin
  207. secondpass(left);
  208. case left.location.loc of
  209. LOC_FLAGS :
  210. begin
  211. location_copy(location,left.location);
  212. inverse_flags(location.resflags);
  213. end;
  214. LOC_REGISTER,LOC_CREGISTER,LOC_REFERENCE,LOC_CREFERENCE,
  215. LOC_SUBSETREG,LOC_CSUBSETREG,LOC_SUBSETREF,LOC_CSUBSETREF :
  216. begin
  217. location_force_reg(current_asmdata.CurrAsmList,left.location,def_cgsize(left.resultdef),true);
  218. current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_CPI,left.location.register,0));
  219. tmpreg:=left.location.register;
  220. { avr has no cpci, so we use the first register as "zero" register }
  221. for i:=2 to tcgsize2size[left.location.size] do
  222. begin
  223. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CPC,tmpreg,left.location.register));
  224. end;
  225. location_reset(location,LOC_FLAGS,OS_NO);
  226. location.resflags:=F_EQ;
  227. end;
  228. else
  229. internalerror(2003042401);
  230. end;
  231. end;
  232. end;
  233. begin
  234. cmoddivnode:=tavrmoddivnode;
  235. cnotnode:=tavrnotnode;
  236. end.