navrmat.pas 10 KB

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