ncpumat.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  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. node, nmat, ncgmat, cgbase;
  24. type
  25. tMIPSELmoddivnode = class(tmoddivnode)
  26. procedure pass_generate_code;override;
  27. end;
  28. tMIPSELshlshrnode = class(tshlshrnode)
  29. procedure pass_generate_code;override;
  30. { everything will be handled in pass_2 }
  31. function first_shlshr64bitint: tnode; override;
  32. end;
  33. tMIPSELnotnode = class(tcgnotnode)
  34. procedure second_boolean; override;
  35. end;
  36. TMIPSunaryminusnode = class(tcgunaryminusnode)
  37. procedure emit_float_sign_change(r: tregister; _size : tcgsize);override;
  38. end;
  39. implementation
  40. uses
  41. globtype, systems,
  42. cutils, verbose, globals,
  43. symconst, symdef,
  44. aasmbase, aasmcpu, aasmtai, aasmdata,
  45. defutil,
  46. procinfo,
  47. cgobj, hlcgobj, pass_2,
  48. ncon,
  49. cpubase,
  50. ncgutil, cgcpu, cgutils;
  51. {*****************************************************************************
  52. TMipselMODDIVNODE
  53. *****************************************************************************}
  54. const
  55. ops_div: array[boolean] of tasmop = (A_DIVU, A_DIV);
  56. procedure tMIPSELmoddivnode.pass_generate_code;
  57. var
  58. power: longint;
  59. tmpreg, numerator, divider: tregister;
  60. hl,hl2: tasmlabel;
  61. begin
  62. secondpass(left);
  63. secondpass(right);
  64. location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
  65. location.register:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_INT);
  66. { put numerator in register }
  67. hlcg.location_force_reg(current_asmdata.CurrAsmList, left.location, left.resultdef, left.resultdef, True);
  68. numerator := left.location.Register;
  69. if (nodetype = divn) and
  70. (right.nodetype = ordconstn) and
  71. ispowerof2(tordconstnode(right).Value.svalue, power) then
  72. begin
  73. tmpreg := cg.GetIntRegister(current_asmdata.CurrAsmList, OS_INT);
  74. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SAR, OS_INT, 31, numerator, tmpreg);
  75. { if signed, tmpreg=right value-1, otherwise 0 }
  76. cg.a_op_const_reg(current_asmdata.CurrAsmList, OP_AND, OS_INT, tordconstnode(right).Value.svalue - 1, tmpreg);
  77. { add left value }
  78. cg.a_op_reg_reg(current_asmdata.CurrAsmList, OP_ADD, OS_INT, numerator, tmpreg);
  79. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SAR, OS_INT, aword(power), tmpreg, location.register);
  80. end
  81. else
  82. begin
  83. { load divider in a register if necessary }
  84. hlcg.location_force_reg(current_asmdata.CurrAsmList, right.location,
  85. right.resultdef, right.resultdef, True);
  86. divider := right.location.Register;
  87. { GAS performs division in delay slot:
  88. bne denom,$zero,.L1
  89. div $zero,numerator,denom
  90. break 7
  91. .L1:
  92. mflo result
  93. We can't yet do the same without prior fixing the spilling code:
  94. if registers require spilling, loads can be inserted before 'div',
  95. resulting in invalid code.
  96. }
  97. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(ops_div[is_signed(resultdef)],NR_R0,numerator,divider));
  98. { Check for zero denominator, omit if dividing by constant (constants are checked earlier) }
  99. if (right.nodetype<>ordconstn) then
  100. begin
  101. current_asmdata.getjumplabel(hl);
  102. cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,divider,NR_R0,hl);
  103. current_asmdata.CurrAsmList.Concat(taicpu.op_const(A_BREAK,7));
  104. cg.a_label(current_asmdata.CurrAsmList,hl);
  105. end;
  106. { Dividing low(longint) by -1 will overflow }
  107. if is_signed(right.resultdef) and (cs_check_overflow in current_settings.localswitches) then
  108. begin
  109. current_asmdata.getjumplabel(hl2);
  110. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_ADDIU,NR_R1,NR_R0,-1));
  111. cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,divider,NR_R1,hl2);
  112. current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LUI,NR_R1,$8000));
  113. cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,numerator,NR_R1,hl2);
  114. current_asmdata.CurrAsmList.concat(taicpu.op_const(A_BREAK,6));
  115. cg.a_label(current_asmdata.CurrAsmList,hl2);
  116. end;
  117. if (nodetype=modn) then
  118. current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_MFHI,location.register))
  119. else
  120. current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_MFLO,location.register));
  121. end;
  122. end;
  123. {*****************************************************************************
  124. TMIPSelSHLRSHRNODE
  125. *****************************************************************************}
  126. function TMIPSELShlShrNode.first_shlshr64bitint: TNode;
  127. begin
  128. { 64bit without constants need a helper }
  129. if is_64bit(left.resultdef) and
  130. (right.nodetype <> ordconstn) then
  131. begin
  132. Result := inherited first_shlshr64bitint;
  133. exit;
  134. end;
  135. Result := nil;
  136. end;
  137. procedure tMIPSELshlshrnode.pass_generate_code;
  138. var
  139. hregister, hreg64hi, hreg64lo: tregister;
  140. op: topcg;
  141. shiftval: aword;
  142. begin
  143. { 64bit without constants need a helper, and is
  144. already replaced in pass1 }
  145. if is_64bit(left.resultdef) and
  146. (right.nodetype <> ordconstn) then
  147. internalerror(200405301);
  148. secondpass(left);
  149. secondpass(right);
  150. if is_64bit(left.resultdef) then
  151. begin
  152. location_reset(location, LOC_REGISTER, OS_64);
  153. { load left operator in a register }
  154. hlcg.location_force_reg(current_asmdata.CurrAsmList, left.location, left.resultdef, u64inttype, False);
  155. hreg64hi := left.location.register64.reghi;
  156. hreg64lo := left.location.register64.reglo;
  157. shiftval := tordconstnode(right).Value.svalue and 63;
  158. if shiftval > 31 then
  159. begin
  160. if nodetype = shln then
  161. begin
  162. cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_32, 0, hreg64hi);
  163. if (shiftval and 31) <> 0 then
  164. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHL, OS_32, shiftval and 31, hreg64lo, hreg64lo);
  165. end
  166. else
  167. begin
  168. cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_32, 0, hreg64lo);
  169. if (shiftval and 31) <> 0 then
  170. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHR, OS_32, shiftval and 31, hreg64hi, hreg64hi);
  171. end;
  172. location.register64.reglo := hreg64hi;
  173. location.register64.reghi := hreg64lo;
  174. end
  175. else
  176. begin
  177. if shiftval <> 0 then
  178. begin
  179. hregister := cg.getintregister(current_asmdata.CurrAsmList, OS_32);
  180. if nodetype = shln then
  181. begin
  182. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHR, OS_32, 32 - shiftval, hreg64lo, hregister);
  183. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHL, OS_32, shiftval, hreg64hi, hreg64hi);
  184. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_OR, OS_32, hregister, hreg64hi, hreg64hi);
  185. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHL, OS_32, shiftval, hreg64lo, hreg64lo);
  186. end
  187. else
  188. begin
  189. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHL, OS_32, 32 - shiftval, hreg64hi, hregister);
  190. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHR, OS_32, shiftval, hreg64lo, hreg64lo);
  191. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_OR, OS_32, hregister, hreg64lo, hreg64lo);
  192. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHR, OS_32, shiftval, hreg64hi, hreg64hi);
  193. end;
  194. end;
  195. location.register64.reghi := hreg64hi;
  196. location.register64.reglo := hreg64lo;
  197. end;
  198. end
  199. else
  200. begin
  201. { load left operators in a register }
  202. hlcg.location_force_reg(current_asmdata.CurrAsmList, left.location, left.resultdef, left.resultdef, True);
  203. location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
  204. location.register:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_INT);
  205. { determine operator }
  206. if nodetype = shln then
  207. op := OP_SHL
  208. else
  209. op := OP_SHR;
  210. { shifting by a constant directly coded: }
  211. if (right.nodetype = ordconstn) then
  212. begin
  213. if tordconstnode(right).Value.svalue and 31 <> 0 then
  214. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, op, OS_32, tordconstnode(right).Value.svalue and 31, left.location.register, location.register);
  215. end
  216. else
  217. begin
  218. { load shift count in a register if necessary }
  219. hlcg.location_force_reg(current_asmdata.CurrAsmList, right.location, right.resultdef, right.resultdef, True);
  220. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, op, OS_32, right.location.Register, left.location.register, location.register);
  221. end;
  222. end;
  223. end;
  224. {*****************************************************************************
  225. TMIPSelNOTNODE
  226. *****************************************************************************}
  227. procedure tMIPSELnotnode.second_boolean;
  228. var
  229. hl: tasmlabel;
  230. tmpreg : TRegister;
  231. r64: TRegister64;
  232. begin
  233. { if the location is LOC_JUMP, we do the secondpass after the
  234. labels are allocated
  235. }
  236. if left.expectloc = LOC_JUMP then
  237. begin
  238. hl := current_procinfo.CurrTrueLabel;
  239. current_procinfo.CurrTrueLabel := current_procinfo.CurrFalseLabel;
  240. current_procinfo.CurrFalseLabel := hl;
  241. secondpass(left);
  242. maketojumpbool(current_asmdata.CurrAsmList, left, lr_load_regvars);
  243. hl := current_procinfo.CurrTrueLabel;
  244. current_procinfo.CurrTrueLabel := current_procinfo.CurrFalseLabel;
  245. current_procinfo.CurrFalseLabel := hl;
  246. location.loc := LOC_JUMP;
  247. end
  248. else
  249. begin
  250. secondpass(left);
  251. case left.location.loc of
  252. LOC_REGISTER, LOC_CREGISTER, LOC_REFERENCE, LOC_CREFERENCE,
  253. LOC_SUBSETREG,LOC_CSUBSETREG,LOC_SUBSETREF,LOC_CSUBSETREF:
  254. begin
  255. hlcg.location_force_reg(current_asmdata.CurrAsmList, left.location, left.resultdef, left.resultdef, True);
  256. location_reset(location,LOC_FLAGS,OS_NO);
  257. location.resflags.reg2:=NR_R0;
  258. location.resflags.cond:=OC_EQ;
  259. if is_64bit(resultdef) then
  260. begin
  261. tmpreg:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_INT);
  262. { OR low and high parts together }
  263. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_OR,tmpreg,left.location.register64.reglo,left.location.register64.reghi));
  264. location.resflags.reg1:=tmpreg;
  265. end
  266. else
  267. location.resflags.reg1:=left.location.register;
  268. end;
  269. else
  270. internalerror(2003042401);
  271. end;
  272. end;
  273. end;
  274. {*****************************************************************************
  275. TMIPSunaryminusnode
  276. *****************************************************************************}
  277. procedure TMIPSunaryminusnode.emit_float_sign_change(r: tregister; _size : tcgsize);
  278. begin
  279. case _size of
  280. OS_F32:
  281. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_NEG_s,r,r));
  282. OS_F64:
  283. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_NEG_d,r,r));
  284. else
  285. internalerror(2013030501);
  286. end;
  287. end;
  288. begin
  289. cmoddivnode := tMIPSELmoddivnode;
  290. cshlshrnode := tMIPSELshlshrnode;
  291. cnotnode := tMIPSELnotnode;
  292. cunaryminusnode := TMIPSunaryminusnode;
  293. end.