narmmat.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Generate ARM 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 narmmat;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. node,nmat,ncgmat;
  22. type
  23. tarmmoddivnode = class(tmoddivnode)
  24. function first_moddivint: tnode;override;
  25. procedure pass_generate_code;override;
  26. end;
  27. tarmnotnode = class(tcgnotnode)
  28. procedure second_boolean;override;
  29. end;
  30. tarmunaryminusnode = class(tcgunaryminusnode)
  31. procedure second_float;override;
  32. end;
  33. implementation
  34. uses
  35. globtype,systems,
  36. cutils,verbose,globals,constexp,
  37. aasmbase,aasmcpu,aasmtai,aasmdata,
  38. defutil,
  39. cgbase,cgobj,cgutils,
  40. pass_2,procinfo,
  41. ncon,
  42. cpubase,
  43. ncgutil,cgcpu;
  44. {*****************************************************************************
  45. TARMMODDIVNODE
  46. *****************************************************************************}
  47. function tarmmoddivnode.first_moddivint: tnode;
  48. var
  49. power : longint;
  50. begin
  51. if (right.nodetype=ordconstn) and
  52. (nodetype=divn) and
  53. (ispowerof2(tordconstnode(right).value,power) or
  54. (tordconstnode(right).value=1) or
  55. (tordconstnode(right).value=int64(-1))
  56. ) and
  57. not(is_64bitint(resultdef)) then
  58. result:=nil
  59. else
  60. result:=inherited first_moddivint;
  61. end;
  62. procedure tarmmoddivnode.pass_generate_code;
  63. var
  64. power : longint;
  65. numerator,
  66. helper1,
  67. helper2,
  68. resultreg : tregister;
  69. size : Tcgsize;
  70. so : tshifterop;
  71. procedure genOrdConstNodeDiv;
  72. begin
  73. if tordconstnode(right).value=0 then
  74. internalerror(2005061701)
  75. else if tordconstnode(right).value=1 then
  76. cg.a_load_reg_reg(current_asmdata.CurrAsmList, OS_INT, OS_INT, numerator, resultreg)
  77. else if (tordconstnode(right).value = int64(-1)) then
  78. begin
  79. // note: only in the signed case possible..., may overflow
  80. current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_MVN,
  81. resultreg,numerator),toppostfix(ord(cs_check_overflow in current_settings.localswitches)*ord(PF_S))));
  82. end
  83. else if ispowerof2(tordconstnode(right).value,power) then
  84. begin
  85. if (is_signed(right.resultdef)) then
  86. begin
  87. helper1:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  88. helper2:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  89. shifterop_reset(so);
  90. so.shiftmode:=SM_ASR;
  91. so.shiftimm:=31;
  92. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_shifterop(A_MOV,helper1,numerator,so));
  93. shifterop_reset(so);
  94. so.shiftmode:=SM_LSR;
  95. so.shiftimm:=32-power;
  96. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,helper2,numerator,helper1,so));
  97. shifterop_reset(so);
  98. so.shiftmode:=SM_ASR;
  99. so.shiftimm:=power;
  100. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_shifterop(A_MOV,resultreg,helper2,so));
  101. end
  102. else
  103. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SHR,OS_INT,power,numerator,resultreg)
  104. end;
  105. end;
  106. {
  107. procedure genOrdConstNodeMod;
  108. var
  109. modreg, maskreg, tempreg : tregister;
  110. begin
  111. if (tordconstnode(right).value = 0) then begin
  112. internalerror(2005061702);
  113. end
  114. else if (abs(tordconstnode(right).value.svalue) = 1) then
  115. begin
  116. // x mod +/-1 is always zero
  117. cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_INT, 0, resultreg);
  118. end
  119. else if (ispowerof2(tordconstnode(right).value, power)) then
  120. begin
  121. if (is_signed(right.resultdef)) then begin
  122. tempreg := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
  123. maskreg := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
  124. modreg := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
  125. cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_INT, abs(tordconstnode(right).value.svalue)-1, modreg);
  126. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SAR, OS_INT, 31, numerator, maskreg);
  127. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_AND, OS_INT, numerator, modreg, tempreg);
  128. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_ANDC, maskreg, maskreg, modreg));
  129. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_SUBFIC, modreg, tempreg, 0));
  130. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SUBFE, modreg, modreg, modreg));
  131. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_AND, OS_INT, modreg, maskreg, maskreg);
  132. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_OR, OS_INT, maskreg, tempreg, resultreg);
  133. end else begin
  134. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_AND, OS_INT, tordconstnode(right).value.svalue-1, numerator, resultreg);
  135. end;
  136. end else begin
  137. genOrdConstNodeDiv();
  138. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_MUL, OS_INT, tordconstnode(right).value.svalue, resultreg, resultreg);
  139. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_SUB, OS_INT, resultreg, numerator, resultreg);
  140. end;
  141. end;
  142. }
  143. begin
  144. secondpass(left);
  145. secondpass(right);
  146. location_copy(location,left.location);
  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. end;
  180. {*****************************************************************************
  181. TARMNOTNODE
  182. *****************************************************************************}
  183. procedure tarmnotnode.second_boolean;
  184. var
  185. hl : tasmlabel;
  186. begin
  187. { if the location is LOC_JUMP, we do the secondpass after the
  188. labels are allocated
  189. }
  190. if left.expectloc=LOC_JUMP then
  191. begin
  192. hl:=current_procinfo.CurrTrueLabel;
  193. current_procinfo.CurrTrueLabel:=current_procinfo.CurrFalseLabel;
  194. current_procinfo.CurrFalseLabel:=hl;
  195. secondpass(left);
  196. maketojumpbool(current_asmdata.CurrAsmList,left,lr_load_regvars);
  197. hl:=current_procinfo.CurrTrueLabel;
  198. current_procinfo.CurrTrueLabel:=current_procinfo.CurrFalseLabel;
  199. current_procinfo.CurrFalseLabel:=hl;
  200. location.loc:=LOC_JUMP;
  201. end
  202. else
  203. begin
  204. secondpass(left);
  205. case left.location.loc of
  206. LOC_FLAGS :
  207. begin
  208. location_copy(location,left.location);
  209. inverse_flags(location.resflags);
  210. end;
  211. LOC_REGISTER,LOC_CREGISTER,LOC_REFERENCE,LOC_CREFERENCE,
  212. LOC_SUBSETREG,LOC_CSUBSETREG,LOC_SUBSETREF,LOC_CSUBSETREF :
  213. begin
  214. location_force_reg(current_asmdata.CurrAsmList,left.location,def_cgsize(left.resultdef),true);
  215. current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_CMP,left.location.register,0));
  216. location_reset(location,LOC_FLAGS,OS_NO);
  217. location.resflags:=F_EQ;
  218. end;
  219. else
  220. internalerror(2003042401);
  221. end;
  222. end;
  223. end;
  224. {*****************************************************************************
  225. TARMUNARYMINUSNODE
  226. *****************************************************************************}
  227. procedure tarmunaryminusnode.second_float;
  228. begin
  229. secondpass(left);
  230. location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
  231. location_force_fpureg(current_asmdata.CurrAsmList,left.location,false);
  232. location:=left.location;
  233. current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSF,
  234. location.register,left.location.register,0),
  235. cgsize2fpuoppostfix[def_cgsize(resultdef)]));
  236. end;
  237. begin
  238. cmoddivnode:=tarmmoddivnode;
  239. cnotnode:=tarmnotnode;
  240. cunaryminusnode:=tarmunaryminusnode;
  241. end.