narmmat.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  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,cpuinfo,
  43. ncgutil,cgcpu,
  44. nadd,pass_1,symdef;
  45. {*****************************************************************************
  46. TARMMODDIVNODE
  47. *****************************************************************************}
  48. function tarmmoddivnode.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 if (current_settings.cputype in [cpu_armv7m]) and
  61. (nodetype=divn) and
  62. not(is_64bitint(resultdef)) then
  63. result:=nil
  64. else if (current_settings.cputype in [cpu_armv7m]) and
  65. (nodetype=modn) and
  66. not(is_64bitint(resultdef)) then
  67. begin
  68. if (right.nodetype=ordconstn) and
  69. ispowerof2(tordconstnode(right).value,power) and
  70. (tordconstnode(right).value<=256) and
  71. (tordconstnode(right).value>0) then
  72. result:=caddnode.create(andn,left,cordconstnode.create(tordconstnode(right).value-1,sinttype,false))
  73. else
  74. begin
  75. result:=caddnode.create(subn,left,caddnode.create(muln,right.getcopy, cmoddivnode.Create(divn,left.getcopy,right.getcopy)));
  76. right:=nil;
  77. end;
  78. left:=nil;
  79. end
  80. else
  81. result:=inherited first_moddivint;
  82. end;
  83. procedure tarmmoddivnode.pass_generate_code;
  84. var
  85. power : longint;
  86. numerator,
  87. helper1,
  88. helper2,
  89. resultreg : tregister;
  90. size : Tcgsize;
  91. so : tshifterop;
  92. procedure genOrdConstNodeDiv;
  93. begin
  94. if tordconstnode(right).value=0 then
  95. internalerror(2005061701)
  96. else if tordconstnode(right).value=1 then
  97. cg.a_load_reg_reg(current_asmdata.CurrAsmList, OS_INT, OS_INT, numerator, resultreg)
  98. else if (tordconstnode(right).value = int64(-1)) then
  99. begin
  100. // note: only in the signed case possible..., may overflow
  101. current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_MVN,
  102. resultreg,numerator),toppostfix(ord(cs_check_overflow in current_settings.localswitches)*ord(PF_S))));
  103. end
  104. else if ispowerof2(tordconstnode(right).value,power) then
  105. begin
  106. if (is_signed(right.resultdef)) then
  107. begin
  108. helper1:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  109. helper2:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  110. shifterop_reset(so);
  111. so.shiftmode:=SM_ASR;
  112. so.shiftimm:=31;
  113. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_shifterop(A_MOV,helper1,numerator,so));
  114. shifterop_reset(so);
  115. so.shiftmode:=SM_LSR;
  116. so.shiftimm:=32-power;
  117. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,helper2,numerator,helper1,so));
  118. shifterop_reset(so);
  119. so.shiftmode:=SM_ASR;
  120. so.shiftimm:=power;
  121. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_shifterop(A_MOV,resultreg,helper2,so));
  122. end
  123. else
  124. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SHR,OS_INT,power,numerator,resultreg)
  125. end;
  126. end;
  127. {
  128. procedure genOrdConstNodeMod;
  129. var
  130. modreg, maskreg, tempreg : tregister;
  131. begin
  132. if (tordconstnode(right).value = 0) then begin
  133. internalerror(2005061702);
  134. end
  135. else if (abs(tordconstnode(right).value.svalue) = 1) then
  136. begin
  137. // x mod +/-1 is always zero
  138. cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_INT, 0, resultreg);
  139. end
  140. else if (ispowerof2(tordconstnode(right).value, power)) then
  141. begin
  142. if (is_signed(right.resultdef)) then begin
  143. tempreg := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
  144. maskreg := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
  145. modreg := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
  146. cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_INT, abs(tordconstnode(right).value.svalue)-1, modreg);
  147. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SAR, OS_INT, 31, numerator, maskreg);
  148. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_AND, OS_INT, numerator, modreg, tempreg);
  149. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_ANDC, maskreg, maskreg, modreg));
  150. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_SUBFIC, modreg, tempreg, 0));
  151. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SUBFE, modreg, modreg, modreg));
  152. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_AND, OS_INT, modreg, maskreg, maskreg);
  153. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_OR, OS_INT, maskreg, tempreg, resultreg);
  154. end else begin
  155. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_AND, OS_INT, tordconstnode(right).value.svalue-1, numerator, resultreg);
  156. end;
  157. end else begin
  158. genOrdConstNodeDiv();
  159. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_MUL, OS_INT, tordconstnode(right).value.svalue, resultreg, resultreg);
  160. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_SUB, OS_INT, resultreg, numerator, resultreg);
  161. end;
  162. end;
  163. }
  164. begin
  165. secondpass(left);
  166. secondpass(right);
  167. if (current_settings.cputype in [cpu_armv7m]) and
  168. (nodetype=divn) and
  169. not(is_64bitint(resultdef)) then
  170. begin
  171. size:=def_cgsize(left.resultdef);
  172. location_force_reg(current_asmdata.CurrAsmList,left.location,size,true);
  173. location_copy(location,left.location);
  174. location.loc := LOC_REGISTER;
  175. location.register := cg.getintregister(current_asmdata.CurrAsmList,size);
  176. resultreg:=location.register;
  177. if (right.nodetype=ordconstn) and
  178. ((tordconstnode(right).value=1) or
  179. (tordconstnode(right).value=int64(-1)) or
  180. (tordconstnode(right).value=0) or
  181. ispowerof2(tordconstnode(right).value,power)) then
  182. begin
  183. numerator:=left.location.register;
  184. genOrdConstNodeDiv;
  185. end
  186. else
  187. begin
  188. location_force_reg(current_asmdata.CurrAsmList,right.location,size,true);
  189. if is_signed(left.resultdef) or
  190. is_signed(right.resultdef) then
  191. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_IDIV,OS_INT,right.location.register,left.location.register,location.register)
  192. else
  193. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_DIV,OS_INT,right.location.register,left.location.register,location.register);
  194. end;
  195. end
  196. else
  197. begin
  198. location_copy(location,left.location);
  199. { put numerator in register }
  200. size:=def_cgsize(left.resultdef);
  201. location_force_reg(current_asmdata.CurrAsmList,left.location,
  202. size,true);
  203. location_copy(location,left.location);
  204. numerator:=location.register;
  205. resultreg:=location.register;
  206. if location.loc=LOC_CREGISTER then
  207. begin
  208. location.loc := LOC_REGISTER;
  209. location.register := cg.getintregister(current_asmdata.CurrAsmList,size);
  210. resultreg:=location.register;
  211. end
  212. else if (nodetype=modn) or (right.nodetype=ordconstn) then
  213. begin
  214. // for a modulus op, and for const nodes we need the result register
  215. // to be an extra register
  216. resultreg:=cg.getintregister(current_asmdata.CurrAsmList,size);
  217. end;
  218. if right.nodetype=ordconstn then
  219. begin
  220. if nodetype=divn then
  221. genOrdConstNodeDiv
  222. else
  223. // genOrdConstNodeMod;
  224. end;
  225. location.register:=resultreg;
  226. end;
  227. { unsigned division/module can only overflow in case of division by zero }
  228. { (but checking this overflow flag is more convoluted than performing a }
  229. { simple comparison with 0) }
  230. if is_signed(right.resultdef) then
  231. cg.g_overflowcheck(current_asmdata.CurrAsmList,location,resultdef);
  232. end;
  233. {*****************************************************************************
  234. TARMNOTNODE
  235. *****************************************************************************}
  236. procedure tarmnotnode.second_boolean;
  237. var
  238. hl : tasmlabel;
  239. begin
  240. { if the location is LOC_JUMP, we do the secondpass after the
  241. labels are allocated
  242. }
  243. if left.expectloc=LOC_JUMP then
  244. begin
  245. hl:=current_procinfo.CurrTrueLabel;
  246. current_procinfo.CurrTrueLabel:=current_procinfo.CurrFalseLabel;
  247. current_procinfo.CurrFalseLabel:=hl;
  248. secondpass(left);
  249. maketojumpbool(current_asmdata.CurrAsmList,left,lr_load_regvars);
  250. hl:=current_procinfo.CurrTrueLabel;
  251. current_procinfo.CurrTrueLabel:=current_procinfo.CurrFalseLabel;
  252. current_procinfo.CurrFalseLabel:=hl;
  253. location.loc:=LOC_JUMP;
  254. end
  255. else
  256. begin
  257. secondpass(left);
  258. case left.location.loc of
  259. LOC_FLAGS :
  260. begin
  261. location_copy(location,left.location);
  262. inverse_flags(location.resflags);
  263. end;
  264. LOC_REGISTER,LOC_CREGISTER,LOC_REFERENCE,LOC_CREFERENCE,
  265. LOC_SUBSETREG,LOC_CSUBSETREG,LOC_SUBSETREF,LOC_CSUBSETREF :
  266. begin
  267. location_force_reg(current_asmdata.CurrAsmList,left.location,def_cgsize(left.resultdef),true);
  268. current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_CMP,left.location.register,0));
  269. location_reset(location,LOC_FLAGS,OS_NO);
  270. location.resflags:=F_EQ;
  271. end;
  272. else
  273. internalerror(2003042401);
  274. end;
  275. end;
  276. end;
  277. {*****************************************************************************
  278. TARMUNARYMINUSNODE
  279. *****************************************************************************}
  280. procedure tarmunaryminusnode.second_float;
  281. var
  282. op: tasmop;
  283. begin
  284. secondpass(left);
  285. case current_settings.fputype of
  286. fpu_fpa,
  287. fpu_fpa10,
  288. fpu_fpa11:
  289. begin
  290. location_force_fpureg(current_asmdata.CurrAsmList,left.location,false);
  291. location:=left.location;
  292. current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSF,
  293. location.register,left.location.register,0),
  294. cgsize2fpuoppostfix[def_cgsize(resultdef)]));
  295. end;
  296. fpu_vfpv2,
  297. fpu_vfpv3,
  298. fpu_vfpv3_d16:
  299. begin
  300. location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,true);
  301. location:=left.location;
  302. if (left.location.loc=LOC_CMMREGISTER) then
  303. location.register:=cg.getmmregister(current_asmdata.CurrAsmList,location.size);
  304. if (location.size=OS_F32) then
  305. op:=A_FNEGS
  306. else
  307. op:=A_FNEGD;
  308. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op,
  309. location.register,left.location.register));
  310. end;
  311. else
  312. internalerror(2009112602);
  313. end;
  314. end;
  315. begin
  316. cmoddivnode:=tarmmoddivnode;
  317. cnotnode:=tarmnotnode;
  318. cunaryminusnode:=tarmunaryminusnode;
  319. end.