ncpumat.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. {
  2. David Zhang 2007/01/15
  3. $Id: ncpumat.pas,v 1.23 2005/02/14 17:13:10 peter Exp $
  4. Copyright (c) 1998-2002 by Florian Klaempfl
  5. Generate MIPSel assembler for math nodes
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. unit ncpumat;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. symtype,
  24. node, nmat, ncgmat, cgbase;
  25. type
  26. tMIPSELmoddivnode = class(tmoddivnode)
  27. procedure pass_generate_code;override;
  28. end;
  29. tMIPSELshlshrnode = class(tcgshlshrnode)
  30. {$ifdef cpu32bit}
  31. procedure second_64bit;override;
  32. { everything will be handled in pass_2 }
  33. function first_shlshr64bitint: tnode; override;
  34. {$endif cpu32bit}
  35. end;
  36. tMIPSELnotnode = class(tcgnotnode)
  37. procedure second_boolean; override;
  38. end;
  39. TMIPSunaryminusnode = class(tcgunaryminusnode)
  40. procedure second_float; override;
  41. end;
  42. implementation
  43. uses
  44. globtype, systems,
  45. cutils, verbose, globals,
  46. symconst, symdef,
  47. aasmbase, aasmcpu, aasmtai, aasmdata,
  48. defutil,
  49. procinfo,
  50. cgobj, hlcgobj, pass_2,
  51. ncon,
  52. cpubase,
  53. ncgutil, cgcpu, cgutils;
  54. {*****************************************************************************
  55. TMipselMODDIVNODE
  56. *****************************************************************************}
  57. const
  58. ops_div: array[boolean] of tasmop = (A_DIVU, A_DIV);
  59. procedure tMIPSELmoddivnode.pass_generate_code;
  60. var
  61. power: longint;
  62. tmpreg, numerator, divider: tregister;
  63. hl,hl2: tasmlabel;
  64. begin
  65. secondpass(left);
  66. secondpass(right);
  67. location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
  68. location.register:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_INT);
  69. { put numerator in register }
  70. hlcg.location_force_reg(current_asmdata.CurrAsmList, left.location, left.resultdef, left.resultdef, True);
  71. numerator := left.location.Register;
  72. if (nodetype = divn) and
  73. (right.nodetype = ordconstn) then
  74. begin
  75. if ispowerof2(tordconstnode(right).Value.svalue, power) then
  76. begin
  77. tmpreg := cg.GetIntRegister(current_asmdata.CurrAsmList, OS_INT);
  78. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SAR, OS_INT, 31, numerator, tmpreg);
  79. { if signed, tmpreg=right value-1, otherwise 0 }
  80. cg.a_op_const_reg(current_asmdata.CurrAsmList, OP_AND, OS_INT, tordconstnode(right).Value.svalue - 1, tmpreg);
  81. { add left value }
  82. cg.a_op_reg_reg(current_asmdata.CurrAsmList, OP_ADD, OS_INT, numerator, tmpreg);
  83. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SAR, OS_INT, aword(power), tmpreg, location.register);
  84. end
  85. else
  86. cg.g_div_const_reg_reg(current_asmdata.CurrAsmList,def_cgsize(resultdef),
  87. tordconstnode(right).value.svalue,numerator,location.register);
  88. end
  89. else
  90. begin
  91. { load divider in a register if necessary }
  92. hlcg.location_force_reg(current_asmdata.CurrAsmList, right.location,
  93. right.resultdef, right.resultdef, True);
  94. divider := right.location.Register;
  95. { GAS performs division in delay slot:
  96. bne denom,$zero,.L1
  97. div $zero,numerator,denom
  98. break 7
  99. .L1:
  100. mflo result
  101. We can't yet do the same without prior fixing the spilling code:
  102. if registers require spilling, loads can be inserted before 'div',
  103. resulting in invalid code.
  104. }
  105. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(ops_div[is_signed(resultdef)],NR_R0,numerator,divider));
  106. { Check for zero denominator, omit if dividing by constant (constants are checked earlier) }
  107. if (right.nodetype<>ordconstn) then
  108. begin
  109. current_asmdata.getjumplabel(hl);
  110. cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,divider,NR_R0,hl);
  111. current_asmdata.CurrAsmList.Concat(taicpu.op_const(A_BREAK,7));
  112. cg.a_label(current_asmdata.CurrAsmList,hl);
  113. end;
  114. { Dividing low(longint) by -1 will overflow }
  115. if is_signed(right.resultdef) and (cs_check_overflow in current_settings.localswitches) then
  116. begin
  117. current_asmdata.getjumplabel(hl2);
  118. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_ADDIU,NR_R1,NR_R0,-1));
  119. cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,divider,NR_R1,hl2);
  120. current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LUI,NR_R1,$8000));
  121. cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,numerator,NR_R1,hl2);
  122. current_asmdata.CurrAsmList.concat(taicpu.op_const(A_BREAK,6));
  123. cg.a_label(current_asmdata.CurrAsmList,hl2);
  124. end;
  125. if (nodetype=modn) then
  126. current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_MFHI,location.register))
  127. else
  128. current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_MFLO,location.register));
  129. end;
  130. end;
  131. {*****************************************************************************
  132. TMIPSelSHLRSHRNODE
  133. *****************************************************************************}
  134. {$ifdef cpu32bit}
  135. function TMIPSELShlShrNode.first_shlshr64bitint: TNode;
  136. begin
  137. { 64bit without constants need a helper }
  138. if is_64bit(left.resultdef) and
  139. (right.nodetype <> ordconstn) then
  140. begin
  141. Result := inherited first_shlshr64bitint;
  142. exit;
  143. end;
  144. Result := nil;
  145. end;
  146. procedure tMIPSELshlshrnode.second_64bit;
  147. var
  148. hregister, hreg64hi, hreg64lo: tregister;
  149. op: topcg;
  150. shiftval: aword;
  151. const
  152. ops: array [boolean] of topcg = (OP_SHR,OP_SHL);
  153. begin
  154. { 64bit without constants need a helper, and is
  155. already replaced in pass1 }
  156. if (right.nodetype <> ordconstn) then
  157. internalerror(200405301);
  158. location_reset(location, LOC_REGISTER, def_cgsize(resultdef));
  159. { load left operator in a register }
  160. hlcg.location_force_reg(current_asmdata.CurrAsmList, left.location, left.resultdef, resultdef, true);
  161. hreg64hi := left.location.register64.reghi;
  162. hreg64lo := left.location.register64.reglo;
  163. shiftval := tordconstnode(right).Value.svalue and 63;
  164. op := ops[nodetype=shln];
  165. if shiftval > 31 then
  166. begin
  167. if nodetype = shln then
  168. begin
  169. location.register64.reglo:=NR_R0;
  170. location.register64.reghi:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_32);
  171. { if shiftval and 31 = 0, it will optimize to MOVE }
  172. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHL, OS_32, shiftval and 31, hreg64lo, location.register64.reghi);
  173. end
  174. else
  175. begin
  176. location.register64.reghi:=NR_R0;
  177. location.register64.reglo:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_32);
  178. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHR, OS_32, shiftval and 31, hreg64hi, location.register64.reglo);
  179. end;
  180. end
  181. else
  182. begin
  183. location.register64.reglo:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_32);
  184. location.register64.reghi:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_32);
  185. hregister := cg.getintregister(current_asmdata.CurrAsmList, OS_32);
  186. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, op, OS_32, shiftval, hreg64hi, location.register64.reghi);
  187. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, op, OS_32, shiftval, hreg64lo, location.register64.reglo);
  188. if shiftval <> 0 then
  189. begin
  190. if nodetype = shln then
  191. begin
  192. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHR, OS_32, 32-shiftval, hreg64lo, hregister);
  193. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_OR, OS_32, hregister, location.register64.reghi, location.register64.reghi);
  194. end
  195. else
  196. begin
  197. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHL, OS_32, 32-shiftval, hreg64hi, hregister);
  198. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_OR, OS_32, hregister, location.register64.reglo, location.register64.reglo);
  199. end;
  200. end;
  201. end;
  202. end;
  203. {$endif cpu32bit}
  204. {*****************************************************************************
  205. TMIPSelNOTNODE
  206. *****************************************************************************}
  207. procedure tMIPSELnotnode.second_boolean;
  208. var
  209. tmpreg : TRegister;
  210. begin
  211. secondpass(left);
  212. if not handle_locjump then
  213. begin
  214. case left.location.loc of
  215. LOC_REGISTER, LOC_CREGISTER, LOC_REFERENCE, LOC_CREFERENCE,
  216. LOC_SUBSETREG,LOC_CSUBSETREG,LOC_SUBSETREF,LOC_CSUBSETREF:
  217. begin
  218. hlcg.location_force_reg(current_asmdata.CurrAsmList, left.location, left.resultdef, left.resultdef, True);
  219. location_reset(location,LOC_FLAGS,OS_NO);
  220. location.resflags.reg2:=NR_R0;
  221. location.resflags.cond:=OC_EQ;
  222. {$ifdef cpu32bit}
  223. if is_64bit(resultdef) then
  224. begin
  225. tmpreg:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_INT);
  226. { OR low and high parts together }
  227. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_OR,tmpreg,left.location.register64.reglo,left.location.register64.reghi));
  228. location.resflags.reg1:=tmpreg;
  229. end
  230. else
  231. {$endif cpu32bit}
  232. location.resflags.reg1:=left.location.register;
  233. end;
  234. else
  235. internalerror(2003042401);
  236. end;
  237. end;
  238. end;
  239. {*****************************************************************************
  240. TMIPSunaryminusnode
  241. *****************************************************************************}
  242. procedure TMIPSunaryminusnode.second_float;
  243. begin
  244. secondpass(left);
  245. hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
  246. location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
  247. location.register:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
  248. case location.size of
  249. OS_F32:
  250. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_NEG_s,location.register,left.location.register));
  251. OS_F64:
  252. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_NEG_d,location.register,left.location.register));
  253. else
  254. internalerror(2013030501);
  255. end;
  256. end;
  257. begin
  258. cmoddivnode := tMIPSELmoddivnode;
  259. cshlshrnode := tMIPSELshlshrnode;
  260. cnotnode := tMIPSELnotnode;
  261. cunaryminusnode := TMIPSunaryminusnode;
  262. end.