narmmat.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  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) and
  54. not(is_64bitint(resultdef)) then
  55. result:=nil
  56. else
  57. result:=inherited first_moddivint;
  58. end;
  59. procedure tarmmoddivnode.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. 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. end;
  103. {
  104. procedure genOrdConstNodeMod;
  105. var
  106. modreg, maskreg, tempreg : tregister;
  107. begin
  108. if (tordconstnode(right).value = 0) then begin
  109. internalerror(2005061702);
  110. end
  111. else if (abs(tordconstnode(right).value.svalue) = 1) then
  112. begin
  113. // x mod +/-1 is always zero
  114. cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_INT, 0, resultreg);
  115. end
  116. else if (ispowerof2(tordconstnode(right).value, power)) then
  117. begin
  118. if (is_signed(right.resultdef)) then begin
  119. tempreg := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
  120. maskreg := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
  121. modreg := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
  122. cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_INT, abs(tordconstnode(right).value.svalue)-1, modreg);
  123. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SAR, OS_INT, 31, numerator, maskreg);
  124. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_AND, OS_INT, numerator, modreg, tempreg);
  125. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_ANDC, maskreg, maskreg, modreg));
  126. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_SUBFIC, modreg, tempreg, 0));
  127. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SUBFE, modreg, modreg, modreg));
  128. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_AND, OS_INT, modreg, maskreg, maskreg);
  129. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_OR, OS_INT, maskreg, tempreg, resultreg);
  130. end else begin
  131. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_AND, OS_INT, tordconstnode(right).value.svalue-1, numerator, resultreg);
  132. end;
  133. end else begin
  134. genOrdConstNodeDiv();
  135. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_MUL, OS_INT, tordconstnode(right).value.svalue, resultreg, resultreg);
  136. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_SUB, OS_INT, resultreg, numerator, resultreg);
  137. end;
  138. end;
  139. }
  140. begin
  141. secondpass(left);
  142. secondpass(right);
  143. location_copy(location,left.location);
  144. { put numerator in register }
  145. size:=def_cgsize(left.resultdef);
  146. location_force_reg(current_asmdata.CurrAsmList,left.location,
  147. size,true);
  148. location_copy(location,left.location);
  149. numerator:=location.register;
  150. resultreg:=location.register;
  151. if location.loc=LOC_CREGISTER then
  152. begin
  153. location.loc := LOC_REGISTER;
  154. location.register := cg.getintregister(current_asmdata.CurrAsmList,size);
  155. resultreg:=location.register;
  156. end
  157. else if (nodetype=modn) or (right.nodetype=ordconstn) then
  158. begin
  159. // for a modulus op, and for const nodes we need the result register
  160. // to be an extra register
  161. resultreg:=cg.getintregister(current_asmdata.CurrAsmList,size);
  162. end;
  163. if right.nodetype=ordconstn then
  164. begin
  165. if nodetype=divn then
  166. genOrdConstNodeDiv
  167. else
  168. // genOrdConstNodeMod;
  169. end;
  170. location.register:=resultreg;
  171. { unsigned division/module can only overflow in case of division by zero }
  172. { (but checking this overflow flag is more convoluted than performing a }
  173. { simple comparison with 0) }
  174. if is_signed(right.resultdef) then
  175. cg.g_overflowcheck(current_asmdata.CurrAsmList,location,resultdef);
  176. end;
  177. {*****************************************************************************
  178. TARMNOTNODE
  179. *****************************************************************************}
  180. procedure tarmnotnode.second_boolean;
  181. var
  182. hl : tasmlabel;
  183. begin
  184. { if the location is LOC_JUMP, we do the secondpass after the
  185. labels are allocated
  186. }
  187. if left.expectloc=LOC_JUMP then
  188. begin
  189. hl:=current_procinfo.CurrTrueLabel;
  190. current_procinfo.CurrTrueLabel:=current_procinfo.CurrFalseLabel;
  191. current_procinfo.CurrFalseLabel:=hl;
  192. secondpass(left);
  193. maketojumpbool(current_asmdata.CurrAsmList,left,lr_load_regvars);
  194. hl:=current_procinfo.CurrTrueLabel;
  195. current_procinfo.CurrTrueLabel:=current_procinfo.CurrFalseLabel;
  196. current_procinfo.CurrFalseLabel:=hl;
  197. location.loc:=LOC_JUMP;
  198. end
  199. else
  200. begin
  201. secondpass(left);
  202. case left.location.loc of
  203. LOC_FLAGS :
  204. begin
  205. location_copy(location,left.location);
  206. inverse_flags(location.resflags);
  207. end;
  208. LOC_REGISTER,LOC_CREGISTER,LOC_REFERENCE,LOC_CREFERENCE,
  209. LOC_SUBSETREG,LOC_CSUBSETREG,LOC_SUBSETREF,LOC_CSUBSETREF :
  210. begin
  211. location_force_reg(current_asmdata.CurrAsmList,left.location,def_cgsize(left.resultdef),true);
  212. current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_CMP,left.location.register,0));
  213. location_reset(location,LOC_FLAGS,OS_NO);
  214. location.resflags:=F_EQ;
  215. end;
  216. else
  217. internalerror(2003042401);
  218. end;
  219. end;
  220. end;
  221. {*****************************************************************************
  222. TARMUNARYMINUSNODE
  223. *****************************************************************************}
  224. procedure tarmunaryminusnode.second_float;
  225. begin
  226. secondpass(left);
  227. location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
  228. location_force_fpureg(current_asmdata.CurrAsmList,left.location,false);
  229. location:=left.location;
  230. current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSF,
  231. location.register,left.location.register,0),
  232. cgsize2fpuoppostfix[def_cgsize(resultdef)]));
  233. end;
  234. begin
  235. cmoddivnode:=tarmmoddivnode;
  236. cnotnode:=tarmnotnode;
  237. cunaryminusnode:=tarmunaryminusnode;
  238. end.