2
0

ncpuinl.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Generates ARM inline 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 ncpuinl;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. node,ninl,ncginl;
  22. type
  23. taarch64inlinenode = class(tcgInlineNode)
  24. function first_abs_real: tnode; override;
  25. function first_sqr_real: tnode; override;
  26. function first_sqrt_real: tnode; override;
  27. function first_round_real: tnode; override;
  28. function first_trunc_real: tnode; override;
  29. function first_fma : tnode; override;
  30. procedure second_abs_real; override;
  31. procedure second_sqr_real; override;
  32. procedure second_sqrt_real; override;
  33. procedure second_abs_long; override;
  34. procedure second_round_real; override;
  35. procedure second_trunc_real; override;
  36. procedure second_get_frame; override;
  37. procedure second_fma; override;
  38. procedure second_prefetch; override;
  39. private
  40. procedure load_fpu_location;
  41. end;
  42. implementation
  43. uses
  44. globtype,verbose,globals,
  45. cpuinfo, defutil,symdef,aasmdata,aasmcpu,
  46. cgbase,cgutils,pass_1,pass_2,
  47. ncal,nutils,
  48. cpubase,ncgutil,cgobj,cgcpu, hlcgobj;
  49. {*****************************************************************************
  50. taarch64inlinenode
  51. *****************************************************************************}
  52. procedure taarch64inlinenode.load_fpu_location;
  53. begin
  54. secondpass(left);
  55. hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
  56. location_copy(location,left.location);
  57. location.register:=cg.getmmregister(current_asmdata.CurrAsmList,location.size);
  58. location.loc:=LOC_MMREGISTER;
  59. end;
  60. function taarch64inlinenode.first_abs_real : tnode;
  61. begin
  62. expectloc:=LOC_MMREGISTER;
  63. result:=nil;
  64. end;
  65. function taarch64inlinenode.first_sqr_real : tnode;
  66. begin
  67. expectloc:=LOC_MMREGISTER;
  68. result:=nil;
  69. end;
  70. function taarch64inlinenode.first_sqrt_real : tnode;
  71. begin
  72. expectloc:=LOC_MMREGISTER;
  73. result:=nil;
  74. end;
  75. function taarch64inlinenode.first_round_real: tnode;
  76. begin
  77. expectloc:=LOC_MMREGISTER;
  78. result:=nil;
  79. end;
  80. function taarch64inlinenode.first_trunc_real: tnode;
  81. begin
  82. expectloc:=LOC_MMREGISTER;
  83. result:=nil;
  84. end;
  85. function taarch64inlinenode.first_fma : tnode;
  86. begin
  87. if ((is_double(resultdef)) or (is_single(resultdef))) then
  88. begin
  89. expectloc:=LOC_MMREGISTER;
  90. Result:=nil;
  91. end
  92. else
  93. Result:=inherited first_fma;
  94. end;
  95. procedure taarch64inlinenode.second_abs_real;
  96. begin
  97. load_fpu_location;
  98. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FABS,location.register,left.location.register));
  99. cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
  100. end;
  101. procedure taarch64inlinenode.second_sqr_real;
  102. begin
  103. load_fpu_location;
  104. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_FMUL,location.register,left.location.register,left.location.register));
  105. cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
  106. end;
  107. procedure taarch64inlinenode.second_sqrt_real;
  108. begin
  109. load_fpu_location;
  110. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FSQRT,location.register,left.location.register));
  111. cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
  112. end;
  113. procedure taarch64inlinenode.second_abs_long;
  114. var
  115. opsize : tcgsize;
  116. begin
  117. secondpass(left);
  118. opsize:=def_cgsize(left.resultdef);
  119. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
  120. location:=left.location;
  121. location.register:=cg.getintregister(current_asmdata.CurrAsmList,opsize);
  122. current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_NEG,location.register,left.location.register),PF_S));
  123. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_cond(A_CSEL,location.register,location.register,left.location.register,C_GE));
  124. end;
  125. procedure taarch64inlinenode.second_round_real;
  126. var
  127. hreg: tregister;
  128. begin
  129. secondpass(left);
  130. hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
  131. location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
  132. location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
  133. hreg:=cg.getmmregister(current_asmdata.CurrAsmList,left.location.size);
  134. { round as floating point using current rounding mode }
  135. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FRINTX,hreg,left.location.register));
  136. { convert to signed integer rounding towards zero (there's no "round to
  137. integer using current rounding mode") }
  138. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FCVTZS,location.register,hreg));
  139. cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
  140. end;
  141. procedure taarch64inlinenode.second_trunc_real;
  142. begin
  143. secondpass(left);
  144. hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
  145. location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
  146. location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
  147. { convert to signed integer rounding towards zero }
  148. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FCVTZS,location.register,left.location.register));
  149. end;
  150. procedure taarch64inlinenode.second_get_frame;
  151. begin
  152. location_reset(location,LOC_CREGISTER,OS_ADDR);
  153. { this routine is used to get the frame pointer for backtracing
  154. purposes. current_procinfo.framepointer is set to SP because that one
  155. is used to access temps. On most platforms these two frame pointers
  156. are the same, but not on AArch64. }
  157. location.register:=NR_FRAME_POINTER_REG;
  158. end;
  159. procedure taarch64inlinenode.second_fma;
  160. const
  161. op : array[false..true,false..true] of TAsmOp =
  162. { positive product }
  163. (
  164. { positive third operand }
  165. (A_FMADD,
  166. { negative third operand }
  167. A_FNMSUB),
  168. { negative product }
  169. { positive third operand }
  170. (A_FMSUB,
  171. A_FNMADD)
  172. );
  173. var
  174. paraarray : array[1..3] of tnode;
  175. i : integer;
  176. negop3,
  177. negproduct : boolean;
  178. begin
  179. negop3:=false;
  180. negproduct:=false;
  181. paraarray[1]:=tcallparanode(tcallparanode(tcallparanode(parameters).nextpara).nextpara).paravalue;
  182. paraarray[2]:=tcallparanode(tcallparanode(parameters).nextpara).paravalue;
  183. paraarray[3]:=tcallparanode(parameters).paravalue;
  184. { check if a neg. node can be removed
  185. this is possible because changing the sign of
  186. a floating point number does not affect its absolute
  187. value in any way
  188. }
  189. if paraarray[1].nodetype=unaryminusn then
  190. begin
  191. paraarray[1]:=tunarynode(paraarray[1]).left;
  192. { do not release the unused unary minus node, it is kept and release together with the other nodes,
  193. only no code is generated for it }
  194. negproduct:=not(negproduct);
  195. end;
  196. if paraarray[2].nodetype=unaryminusn then
  197. begin
  198. paraarray[2]:=tunarynode(paraarray[2]).left;
  199. { do not release the unused unary minus node, it is kept and release together with the other nodes,
  200. only no code is generated for it }
  201. negproduct:=not(negproduct);
  202. end;
  203. if paraarray[3].nodetype=unaryminusn then
  204. begin
  205. paraarray[3]:=tunarynode(paraarray[3]).left;
  206. { do not release the unused unary minus node, it is kept and release together with the other nodes,
  207. only no code is generated for it }
  208. negop3:=true;
  209. end;
  210. for i:=1 to 3 do
  211. secondpass(paraarray[i]);
  212. { no memory operand is allowed }
  213. for i:=1 to 3 do
  214. begin
  215. if not(paraarray[i].location.loc in [LOC_MMREGISTER,LOC_CMMREGISTER]) then
  216. hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,paraarray[i].location,paraarray[i].resultdef,true);
  217. end;
  218. location_reset(location,LOC_MMREGISTER,paraarray[1].location.size);
  219. location.register:=cg.getmmregister(current_asmdata.CurrAsmList,location.size);
  220. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_reg(op[negproduct,negop3],
  221. location.register,paraarray[1].location.register,paraarray[2].location.register,paraarray[3].location.register));
  222. cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
  223. end;
  224. procedure taarch64inlinenode.second_prefetch;
  225. var
  226. ref : treference;
  227. r : tregister;
  228. checkpointer_used : boolean;
  229. begin
  230. { do not call Checkpointer for left node }
  231. checkpointer_used:=(cs_checkpointer in current_settings.localswitches);
  232. if checkpointer_used then
  233. node_change_local_switch(left,cs_checkpointer,false);
  234. secondpass(left);
  235. if checkpointer_used then
  236. node_change_local_switch(left,cs_checkpointer,false);
  237. case left.location.loc of
  238. LOC_CREFERENCE,
  239. LOC_REFERENCE:
  240. begin
  241. r:=cg.getintregister(current_asmdata.CurrAsmList,OS_ADDR);
  242. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,left.location.reference,r);
  243. reference_reset_base(ref,r,0,location.reference.temppos,left.location.reference.alignment,location.reference.volatility);
  244. current_asmdata.CurrAsmList.concat(taicpu.op_const_ref(A_PRFM,0,ref));
  245. end;
  246. else
  247. { nothing to prefetch };
  248. end;
  249. end;
  250. begin
  251. cinlinenode:=taarch64inlinenode;
  252. end.