ncpumat.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  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, resultreg: tregister;
  60. hl,hl2: tasmlabel;
  61. begin
  62. secondpass(left);
  63. secondpass(right);
  64. location_copy(location, left.location);
  65. { put numerator in register }
  66. hlcg.location_force_reg(current_asmdata.CurrAsmList, left.location, left.resultdef, left.resultdef, True);
  67. location_copy(location, left.location);
  68. numerator := location.Register;
  69. if (nodetype = modn) then
  70. resultreg := cg.GetIntRegister(current_asmdata.CurrAsmList, OS_INT)
  71. else
  72. begin
  73. if (location.loc = LOC_CREGISTER) then
  74. begin
  75. location.loc := LOC_REGISTER;
  76. location.Register := cg.GetIntRegister(current_asmdata.CurrAsmList, OS_INT);
  77. end;
  78. resultreg := location.Register;
  79. end;
  80. if (nodetype = divn) and
  81. (right.nodetype = ordconstn) and
  82. ispowerof2(tordconstnode(right).Value.svalue, power) then
  83. begin
  84. tmpreg := cg.GetIntRegister(current_asmdata.CurrAsmList, OS_INT);
  85. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SAR, OS_INT, 31, numerator, tmpreg);
  86. { if signed, tmpreg=right value-1, otherwise 0 }
  87. cg.a_op_const_reg(current_asmdata.CurrAsmList, OP_AND, OS_INT, tordconstnode(right).Value.svalue - 1, tmpreg);
  88. { add to the left value }
  89. cg.a_op_reg_reg(current_asmdata.CurrAsmList, OP_ADD, OS_INT, tmpreg, numerator);
  90. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SAR, OS_INT, aword(power), numerator, resultreg);
  91. end
  92. else
  93. begin
  94. { load divider in a register if necessary }
  95. hlcg.location_force_reg(current_asmdata.CurrAsmList, right.location,
  96. right.resultdef, right.resultdef, True);
  97. divider := right.location.Register;
  98. { GAS performs division in delay slot:
  99. bne denom,$zero,.L1
  100. div $zero,numerator,denom
  101. break 7
  102. .L1:
  103. mflo result
  104. We can't yet do the same without prior fixing the spilling code:
  105. if registers require spilling, loads can be inserted before 'div',
  106. resulting in invalid code.
  107. }
  108. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(ops_div[is_signed(resultdef)],NR_R0,numerator,divider));
  109. { Check for zero denominator, omit if dividing by constant (constants are checked earlier) }
  110. if (right.nodetype<>ordconstn) then
  111. begin
  112. current_asmdata.getjumplabel(hl);
  113. cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,divider,NR_R0,hl);
  114. current_asmdata.CurrAsmList.Concat(taicpu.op_const(A_BREAK,7));
  115. cg.a_label(current_asmdata.CurrAsmList,hl);
  116. end;
  117. { Dividing low(longint) by -1 will overflow }
  118. if is_signed(right.resultdef) and (cs_check_overflow in current_settings.localswitches) then
  119. begin
  120. current_asmdata.getjumplabel(hl2);
  121. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_ADDIU,NR_R1,NR_R0,-1));
  122. cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,divider,NR_R1,hl2);
  123. current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_LUI,NR_R1,$8000));
  124. cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,numerator,NR_R1,hl2);
  125. current_asmdata.CurrAsmList.concat(taicpu.op_const(A_BREAK,6));
  126. cg.a_label(current_asmdata.CurrAsmList,hl2);
  127. end;
  128. if (nodetype=modn) then
  129. current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_MFHI,resultreg))
  130. else
  131. current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_MFLO,resultreg));
  132. end;
  133. { set result location }
  134. location.loc := LOC_REGISTER;
  135. location.Register := resultreg;
  136. end;
  137. {*****************************************************************************
  138. TMIPSelSHLRSHRNODE
  139. *****************************************************************************}
  140. function TMIPSELShlShrNode.first_shlshr64bitint: TNode;
  141. begin
  142. { 64bit without constants need a helper }
  143. if is_64bit(left.resultdef) and
  144. (right.nodetype <> ordconstn) then
  145. begin
  146. Result := inherited first_shlshr64bitint;
  147. exit;
  148. end;
  149. Result := nil;
  150. end;
  151. procedure tMIPSELshlshrnode.pass_generate_code;
  152. var
  153. hregister, resultreg, hregister1, hreg64hi, hreg64lo: tregister;
  154. op: topcg;
  155. shiftval: aword;
  156. begin
  157. { 64bit without constants need a helper, and is
  158. already replaced in pass1 }
  159. if is_64bit(left.resultdef) and
  160. (right.nodetype <> ordconstn) then
  161. internalerror(200405301);
  162. secondpass(left);
  163. secondpass(right);
  164. if is_64bit(left.resultdef) then
  165. begin
  166. location_reset(location, LOC_REGISTER, OS_64);
  167. { load left operator in a register }
  168. hlcg.location_force_reg(current_asmdata.CurrAsmList, left.location, left.resultdef, u64inttype, False);
  169. hreg64hi := left.location.register64.reghi;
  170. hreg64lo := left.location.register64.reglo;
  171. shiftval := tordconstnode(right).Value.svalue and 63;
  172. if shiftval > 31 then
  173. begin
  174. if nodetype = shln then
  175. begin
  176. cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_32, 0, hreg64hi);
  177. if (shiftval and 31) <> 0 then
  178. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHL, OS_32, shiftval and 31, hreg64lo, hreg64lo);
  179. end
  180. else
  181. begin
  182. cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_32, 0, hreg64lo);
  183. if (shiftval and 31) <> 0 then
  184. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHR, OS_32, shiftval and 31, hreg64hi, hreg64hi);
  185. end;
  186. location.register64.reglo := hreg64hi;
  187. location.register64.reghi := hreg64lo;
  188. end
  189. else
  190. begin
  191. if shiftval <> 0 then
  192. begin
  193. hregister := cg.getintregister(current_asmdata.CurrAsmList, OS_32);
  194. if nodetype = shln then
  195. begin
  196. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHR, OS_32, 32 - shiftval, hreg64lo, hregister);
  197. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHL, OS_32, shiftval, hreg64hi, hreg64hi);
  198. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_OR, OS_32, hregister, hreg64hi, hreg64hi);
  199. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHL, OS_32, shiftval, hreg64lo, hreg64lo);
  200. end
  201. else
  202. begin
  203. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHL, OS_32, 32 - shiftval, hreg64hi, hregister);
  204. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHR, OS_32, shiftval, hreg64lo, hreg64lo);
  205. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_OR, OS_32, hregister, hreg64lo, hreg64lo);
  206. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SHR, OS_32, shiftval, hreg64hi, hreg64hi);
  207. end;
  208. end;
  209. location.register64.reghi := hreg64hi;
  210. location.register64.reglo := hreg64lo;
  211. end;
  212. end
  213. else
  214. begin
  215. { load left operators in a register }
  216. hlcg.location_force_reg(current_asmdata.CurrAsmList, left.location, left.resultdef, left.resultdef, True);
  217. location_copy(location, left.location);
  218. resultreg := location.Register;
  219. hregister1 := location.Register;
  220. if (location.loc = LOC_CREGISTER) then
  221. begin
  222. location.loc := LOC_REGISTER;
  223. resultreg := cg.GetIntRegister(current_asmdata.CurrAsmList, OS_INT);
  224. location.Register := resultreg;
  225. end;
  226. { determine operator }
  227. if nodetype = shln then
  228. op := OP_SHL
  229. else
  230. op := OP_SHR;
  231. { shifting by a constant directly coded: }
  232. if (right.nodetype = ordconstn) then
  233. begin
  234. if tordconstnode(right).Value.svalue and 31 <> 0 then
  235. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, op, OS_32, tordconstnode(right).Value.svalue and 31, hregister1, resultreg);
  236. end
  237. else
  238. begin
  239. { load shift count in a register if necessary }
  240. hlcg.location_force_reg(current_asmdata.CurrAsmList, right.location, right.resultdef, right.resultdef, True);
  241. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, op, OS_32, right.location.Register, hregister1, resultreg);
  242. end;
  243. end;
  244. end;
  245. {*****************************************************************************
  246. TMIPSelNOTNODE
  247. *****************************************************************************}
  248. procedure tMIPSELnotnode.second_boolean;
  249. var
  250. hl: tasmlabel;
  251. tmpreg : TRegister;
  252. r64: TRegister64;
  253. begin
  254. { if the location is LOC_JUMP, we do the secondpass after the
  255. labels are allocated
  256. }
  257. if left.expectloc = LOC_JUMP then
  258. begin
  259. hl := current_procinfo.CurrTrueLabel;
  260. current_procinfo.CurrTrueLabel := current_procinfo.CurrFalseLabel;
  261. current_procinfo.CurrFalseLabel := hl;
  262. secondpass(left);
  263. maketojumpbool(current_asmdata.CurrAsmList, left, lr_load_regvars);
  264. hl := current_procinfo.CurrTrueLabel;
  265. current_procinfo.CurrTrueLabel := current_procinfo.CurrFalseLabel;
  266. current_procinfo.CurrFalseLabel := hl;
  267. location.loc := LOC_JUMP;
  268. end
  269. else
  270. begin
  271. secondpass(left);
  272. case left.location.loc of
  273. LOC_REGISTER, LOC_CREGISTER, LOC_REFERENCE, LOC_CREFERENCE,
  274. LOC_SUBSETREG,LOC_CSUBSETREG,LOC_SUBSETREF,LOC_CSUBSETREF:
  275. begin
  276. hlcg.location_force_reg(current_asmdata.CurrAsmList, left.location, left.resultdef, left.resultdef, True);
  277. if is_64bit(resultdef) then
  278. begin
  279. r64.reglo:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_INT);
  280. r64.reghi:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_INT);
  281. { OR low and high parts together }
  282. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_OR,r64.reglo,left.location.register64.reglo,left.location.register64.reghi));
  283. { x=0 <=> unsigned(x)<1 }
  284. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_SLTIU,r64.reglo,r64.reglo,1));
  285. if is_cbool(resultdef) then
  286. begin
  287. cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_NEG,OS_S32,r64.reglo,r64.reglo);
  288. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,r64.reglo,r64.reghi);
  289. end
  290. else
  291. cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_32,0,r64.reghi);
  292. location_reset(location,LOC_REGISTER,OS_64);
  293. location.Register64:=r64;
  294. end
  295. else
  296. begin
  297. tmpreg := cg.GetIntRegister(current_asmdata.CurrAsmList, OS_INT);
  298. { x=0 <=> unsigned(x)<1 }
  299. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_SLTIU, tmpreg, left.location.Register, 1));
  300. if is_cbool(resultdef) then
  301. cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_NEG,OS_S32,tmpreg,tmpreg);
  302. location_reset(location, LOC_REGISTER, OS_INT);
  303. location.Register := tmpreg;
  304. end;
  305. end;
  306. else
  307. internalerror(2003042401);
  308. end;
  309. end;
  310. end;
  311. {*****************************************************************************
  312. TMIPSunaryminusnode
  313. *****************************************************************************}
  314. procedure TMIPSunaryminusnode.emit_float_sign_change(r: tregister; _size : tcgsize);
  315. begin
  316. case _size of
  317. OS_F32:
  318. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_NEG_s,r,r));
  319. OS_F64:
  320. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_NEG_d,r,r));
  321. else
  322. internalerror(2013030501);
  323. end;
  324. end;
  325. begin
  326. cmoddivnode := tMIPSELmoddivnode;
  327. cshlshrnode := tMIPSELshlshrnode;
  328. cnotnode := tMIPSELnotnode;
  329. cunaryminusnode := TMIPSunaryminusnode;
  330. end.