ncpumat.pas 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Generate Xtensa 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 ncpumat;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. cgbase,node,nmat,ncgmat;
  22. type
  23. tcpumoddivnode = class(tcgmoddivnode)
  24. function first_moddivint: tnode; override;
  25. procedure emit_div_reg_reg(signed: boolean; denum, num: tregister); override;
  26. procedure emit_mod_reg_reg(signed: boolean; denum, num: tregister); override;
  27. end;
  28. tcpunotnode = class(tcgnotnode)
  29. procedure second_boolean;override;
  30. end;
  31. tcpuunaryminusnode = class(tcgunaryminusnode)
  32. function pass_1: tnode; override;
  33. procedure second_float;override;
  34. end;
  35. tcpushlshrnode = class(tcgshlshrnode)
  36. procedure second_64bit;override;
  37. function pass_1: tnode;override;
  38. end;
  39. implementation
  40. uses
  41. globtype,compinnr,
  42. cutils,verbose,globals,constexp,
  43. aasmbase,aasmcpu,aasmtai,aasmdata,
  44. defutil,
  45. symtype,symconst,symtable,
  46. cgobj,hlcgobj,cgutils,
  47. pass_2,procinfo,
  48. ncon,ncnv,ncal,ninl,
  49. cpubase,cpuinfo,
  50. ncgutil,
  51. nadd,pass_1,symdef;
  52. {*****************************************************************************
  53. TCPUMODDIVNODE
  54. *****************************************************************************}
  55. procedure tcpumoddivnode.emit_div_reg_reg(signed: boolean; denum, num: tregister);
  56. var
  57. op: TAsmOp;
  58. begin
  59. if signed then
  60. op:=A_QUOS
  61. else
  62. op:=A_QUOU;
  63. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,num,num,denum));
  64. end;
  65. procedure tcpumoddivnode.emit_mod_reg_reg(signed: boolean; denum, num: tregister);
  66. var
  67. op: TAsmOp;
  68. begin
  69. if signed then
  70. op:=A_REMS
  71. else
  72. op:=A_REMU;
  73. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,num,num,denum));
  74. end;
  75. function tcpumoddivnode.first_moddivint: tnode;
  76. begin
  77. if (not is_64bitint(resultdef)) and
  78. (CPUXTENSA_HAS_DIV in cpu_capabilities[current_settings.cputype]) then
  79. Result:=nil
  80. else
  81. result:=inherited;
  82. end;
  83. {*****************************************************************************
  84. TCPUNOTNODE
  85. *****************************************************************************}
  86. procedure tcpunotnode.second_boolean;
  87. var
  88. tmpreg : TRegister;
  89. begin
  90. secondpass(left);
  91. location:=left.location;
  92. hlcg.location_force_reg(current_asmdata.CurrAsmList,location,resultdef,resultdef,false);
  93. { not supported yet }
  94. if is_64bit(resultdef) then
  95. Internalerror(2020031701);
  96. if is_cbool(resultdef) then
  97. cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_NOT,def_cgsize(resultdef), location.register, location.register)
  98. else
  99. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_XOR,def_cgsize(resultdef),1, location.register, location.register)
  100. end;
  101. {*****************************************************************************
  102. TXTENSAUNARYMINUSNODE
  103. *****************************************************************************}
  104. function tcpuunaryminusnode.pass_1: tnode;
  105. var
  106. procname: string[31];
  107. fdef : tdef;
  108. begin
  109. Result:=nil;
  110. if (current_settings.fputype=fpu_soft) and
  111. (left.resultdef.typ=floatdef) then
  112. begin
  113. result:=nil;
  114. firstpass(left);
  115. expectloc:=LOC_REGISTER;
  116. exit;
  117. end;
  118. result:=nil;
  119. firstpass(left);
  120. if codegenerror then
  121. exit;
  122. expectloc:=LOC_REGISTER;
  123. end;
  124. procedure tcpuunaryminusnode.second_float;
  125. var
  126. ai : taicpu;
  127. begin
  128. secondpass(left);
  129. if (current_settings.fputype=fpu_soft) or (tfloatdef(left.resultdef).floattype<>s32real) or
  130. not(FPUXTENSA_SINGLE in fpu_capabilities[current_settings.fputype]) then
  131. begin
  132. if not(left.location.loc in [LOC_CREGISTER,LOC_REGISTER]) then
  133. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
  134. location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
  135. if location.size in [OS_64,OS_S64,OS_F64] then
  136. begin
  137. location.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  138. location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  139. end
  140. else
  141. location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
  142. case location.size of
  143. OS_32:
  144. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_XOR,OS_32,tcgint($80000000),left.location.register,location.register);
  145. OS_64:
  146. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_XOR,OS_32,tcgint($80000000),left.location.registerhi,location.registerhi);
  147. else
  148. internalerror(2014033101);
  149. end;
  150. end
  151. else
  152. begin
  153. if not(left.location.loc in [LOC_CFPUREGISTER,LOC_FPUREGISTER]) then
  154. hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,false);
  155. location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
  156. location.register:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
  157. ai:=taicpu.op_reg_reg(A_NEG,location.register,left.location.register);
  158. ai.oppostfix := PF_S;
  159. current_asmdata.CurrAsmList.Concat(ai);
  160. end;
  161. end;
  162. function tcpushlshrnode.pass_1 : tnode;
  163. begin
  164. { the xtensa code generator can handle 64 bit shifts by constants directly }
  165. if is_constintnode(right) and is_64bit(resultdef) and
  166. (((nodetype=shln) and (tordconstnode(right).value>=0) and (tordconstnode(right).value<=16)) or
  167. ((nodetype=shrn) and (tordconstnode(right).value>0) and (tordconstnode(right).value<16)) or
  168. (tordconstnode(right).value=32)) then
  169. begin
  170. result:=nil;
  171. firstpass(left);
  172. firstpass(right);
  173. if codegenerror then
  174. exit;
  175. expectloc:=LOC_REGISTER;
  176. end
  177. else
  178. Result:=inherited pass_1;
  179. end;
  180. procedure tcpushlshrnode.second_64bit;
  181. var
  182. op: topcg;
  183. opsize: TCgSize;
  184. opdef: tdef;
  185. shiftval: longint;
  186. hcountreg: TRegister;
  187. begin
  188. { determine operator }
  189. case nodetype of
  190. shln: op:=OP_SHL;
  191. shrn: op:=OP_SHR;
  192. else
  193. internalerror(2020082208);
  194. end;
  195. opsize:=left.location.size;
  196. opdef:=left.resultdef;
  197. if not(left.location.loc in [LOC_CREGISTER,LOC_REGISTER]) or
  198. { location_force_reg can be also used to change the size of a register }
  199. (left.location.size<>opsize) then
  200. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,opdef,true);
  201. location_reset(location,LOC_REGISTER,opsize);
  202. location.register:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  203. location.registerhi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  204. { shifting by a constant directly coded: }
  205. if right.nodetype=ordconstn then
  206. begin
  207. { shl/shr must "wrap around", so use ... and 31 }
  208. { In TP, "byte/word shl 16 = 0", so no "and 15" in case of
  209. a 16 bit ALU }
  210. if tcgsize2size[opsize]<=4 then
  211. shiftval:=tordconstnode(right).value.uvalue and 31
  212. else
  213. shiftval:=tordconstnode(right).value.uvalue and 63;
  214. cg64.a_op64_const_reg_reg(current_asmdata.CurrAsmList,op,location.size,
  215. shiftval,left.location.register64,location.register64)
  216. end
  217. else
  218. begin
  219. internalerror(2020082209);
  220. { load right operators in a register - this
  221. is done since most target cpu which will use this
  222. node do not support a shift count in a mem. location (cec)
  223. }
  224. hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,sinttype,true);
  225. hlcg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,op,opdef,right.location.register,left.location.register,location.register);
  226. end;
  227. { shl/shr nodes return the same type as left, which can be different
  228. from opdef }
  229. if opdef<>resultdef then
  230. begin
  231. hcountreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
  232. hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,opdef,resultdef,location.register,hcountreg);
  233. location.register:=hcountreg;
  234. end;
  235. end;
  236. begin
  237. cmoddivnode:=tcpumoddivnode;
  238. cnotnode:=tcpunotnode;
  239. cunaryminusnode:=tcpuunaryminusnode;
  240. cshlshrnode:=tcpushlshrnode;
  241. end.