ncpumat.pas 13 KB

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