nppcadd.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. {
  2. Copyright (c) 2000-2002 by Florian Klaempfl and Jonas Maebe
  3. Code generation for add nodes on the PowerPC64
  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 nppcadd;
  18. {$I fpcdefs.inc}
  19. interface
  20. uses
  21. node, nadd, ncgadd, ngppcadd, cpubase;
  22. type
  23. tppcaddnode = class(tgenppcaddnode)
  24. procedure pass_generate_code override;
  25. private
  26. procedure emit_compare(unsigned: boolean); override;
  27. end;
  28. implementation
  29. uses
  30. sysutils,
  31. globtype, systems,
  32. cutils, verbose, globals,
  33. symconst, symdef, paramgr,
  34. aasmbase, aasmtai,aasmdata, aasmcpu, defutil, htypechk,
  35. cgbase, cpuinfo, pass_1, pass_2, regvars,
  36. cpupara, cgcpu, cgutils,procinfo,
  37. ncon, nset,
  38. ncgutil, tgobj, rgobj, rgcpu, cgobj;
  39. {*****************************************************************************
  40. Helpers
  41. *****************************************************************************}
  42. procedure tppcaddnode.emit_compare(unsigned: boolean);
  43. const
  44. { unsigned useconst 32bit-op }
  45. cmpop_table : array[boolean, boolean, boolean] of TAsmOp = (
  46. ((A_CMPD, A_CMPW), (A_CMPDI, A_CMPWI)),
  47. ((A_CMPLD, A_CMPLW), (A_CMPLDI, A_CMPLWI))
  48. );
  49. var
  50. op: TAsmOp;
  51. tmpreg: TRegister;
  52. useconst: boolean;
  53. opsize : TCgSize;
  54. begin
  55. { get the constant on the right if there is one }
  56. if (left.location.loc = LOC_CONSTANT) then
  57. swapleftright;
  58. opsize := def_cgsize(left.resultdef);
  59. {$IFDEF EXTDEBUG}
  60. current_asmdata.CurrAsmList.concat(tai_comment.create(strpnew('tppcaddnode.emit_compare ' + inttostr(ord(opsize)) + ' ' + inttostr(tcgsize2size[opsize]))));
  61. {$ENDIF EXTDEBUG}
  62. { can we use a signed comparison or not? In case of equal/unequal comparison
  63. we can check whether this is possible because it does not matter. }
  64. if (right.location.loc = LOC_CONSTANT) then
  65. if (nodetype in [equaln,unequaln]) then
  66. if (unsigned and (aword(right.location.value) > high(word))) or
  67. (not unsigned and (aint(right.location.value) < low(smallint)) or
  68. (aint(right.location.value) > high(smallint))) then
  69. { we can then maybe use a constant in the 'othersigned' case
  70. (the sign doesn't matter for equal/unequal) }
  71. unsigned := not unsigned;
  72. { calculate the size of the comparison because ppc64 only has 32 and 64
  73. bit comparison opcodes; prefer 32 bits }
  74. if (not (opsize in [OS_32, OS_S32, OS_64, OS_S64])) then begin
  75. if (unsigned) then
  76. opsize := OS_32
  77. else
  78. opsize := OS_S32;
  79. cg.a_load_reg_reg(current_asmdata.CurrAsmList, def_cgsize(left.resultdef), opsize,
  80. left.location.register, left.location.register);
  81. end;
  82. { can we use an immediate, or do we have to load the
  83. constant in a register first? }
  84. if (right.location.loc = LOC_CONSTANT) then begin
  85. if (unsigned and
  86. (aword(right.location.value) <= high(word))) or
  87. (not (unsigned) and
  88. (aint(right.location.value) >= low(smallint)) and (aint(right.location.value) <= high(smallint))) then
  89. useconst := true
  90. else begin
  91. useconst := false;
  92. tmpreg := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
  93. cg.a_load_const_reg(current_asmdata.CurrAsmList, opsize, right.location.value, tmpreg);
  94. end
  95. end else
  96. useconst := false;
  97. location.loc := LOC_FLAGS;
  98. location.resflags := getresflags;
  99. op := cmpop_table[unsigned, useconst, opsize in [OS_S32, OS_32]];
  100. { actually do the operation }
  101. if (right.location.loc = LOC_CONSTANT) then begin
  102. if useconst then
  103. current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(op, left.location.register,
  104. longint(right.location.value)))
  105. else
  106. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op, left.location.register, tmpreg));
  107. end else
  108. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op, left.location.register,
  109. right.location.register));
  110. end;
  111. {*****************************************************************************
  112. pass_2
  113. *****************************************************************************}
  114. procedure tppcaddnode.pass_generate_code;
  115. { is also being used for xor, and "mul", "sub, or and comparative }
  116. { operators }
  117. var
  118. cgop: topcg;
  119. op: tasmop;
  120. tmpreg: tregister;
  121. hl: tasmlabel;
  122. cmpop: boolean;
  123. { true, if unsigned types are compared }
  124. unsigned: boolean;
  125. begin
  126. { to make it more readable, string and set (not smallset!) have their
  127. own procedures }
  128. case left.resultdef.typ of
  129. orddef:
  130. begin
  131. { handling boolean expressions }
  132. if is_boolean(left.resultdef) and
  133. is_boolean(right.resultdef) then
  134. begin
  135. second_addboolean;
  136. exit;
  137. end;
  138. end;
  139. stringdef:
  140. begin
  141. internalerror(2002072402);
  142. exit;
  143. end;
  144. setdef:
  145. begin
  146. { normalsets are already handled in pass1 }
  147. if (tsetdef(left.resultdef).settype <> smallset) then
  148. internalerror(200109041);
  149. second_addsmallset;
  150. exit;
  151. end;
  152. arraydef:
  153. begin
  154. {$IFDEF SUPPORT_MMX}
  155. if is_mmx_able_array(left.resultdef) then
  156. begin
  157. second_addmmx;
  158. exit;
  159. end;
  160. {$ENDIF SUPPORT_MMX}
  161. end;
  162. floatdef:
  163. begin
  164. second_addfloat;
  165. exit;
  166. end;
  167. end;
  168. { defaults }
  169. cmpop := nodetype in [ltn, lten, gtn, gten, equaln, unequaln];
  170. unsigned := not (is_signed(left.resultdef)) or
  171. not (is_signed(right.resultdef));
  172. pass_left_and_right;
  173. { Convert flags to register first }
  174. { can any of these things be in the flags actually?? (JM) }
  175. if (left.location.loc = LOC_FLAGS) or
  176. (right.location.loc = LOC_FLAGS) then
  177. internalerror(2002072602);
  178. { set result location }
  179. if not cmpop then
  180. location_reset(location, LOC_REGISTER, def_cgsize(resultdef))
  181. else
  182. location_reset(location, LOC_FLAGS, OS_NO);
  183. load_left_right(cmpop, (cs_check_overflow in current_settings.localswitches) and
  184. (nodetype in [addn, subn, muln]));
  185. if not (cmpop) then
  186. location.register := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
  187. if not (cs_check_overflow in current_settings.localswitches) or (cmpop) or
  188. (nodetype in [orn, andn, xorn]) then begin
  189. case nodetype of
  190. addn, muln, xorn, orn, andn:
  191. begin
  192. case nodetype of
  193. addn:
  194. cgop := OP_ADD;
  195. muln:
  196. if unsigned then
  197. cgop := OP_MUL
  198. else
  199. cgop := OP_IMUL;
  200. xorn:
  201. cgop := OP_XOR;
  202. orn:
  203. cgop := OP_OR;
  204. andn:
  205. cgop := OP_AND;
  206. end;
  207. if (left.location.loc = LOC_CONSTANT) then
  208. swapleftright;
  209. if (right.location.loc <> LOC_CONSTANT) then
  210. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, cgop, OS_INT,
  211. left.location.register, right.location.register,
  212. location.register)
  213. else
  214. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, cgop, OS_INT,
  215. right.location.value, left.location.register,
  216. location.register);
  217. end;
  218. subn:
  219. begin
  220. if (nf_swapped in flags) then
  221. swapleftright;
  222. if left.location.loc <> LOC_CONSTANT then
  223. if right.location.loc <> LOC_CONSTANT then begin
  224. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_SUB, OS_INT,
  225. right.location.register, left.location.register,
  226. location.register);
  227. end else begin
  228. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SUB, OS_INT,
  229. right.location.value, left.location.register,
  230. location.register);
  231. end
  232. else
  233. begin
  234. tmpreg := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
  235. cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_INT,
  236. left.location.value, tmpreg);
  237. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_SUB, OS_INT,
  238. right.location.register, tmpreg, location.register);
  239. end;
  240. end;
  241. ltn, lten, gtn, gten, equaln, unequaln:
  242. begin
  243. {$ifdef extdebug}
  244. current_asmdata.CurrAsmList.concat(tai_comment.create('tppcaddnode.pass2'));
  245. {$endif extdebug}
  246. emit_compare(unsigned);
  247. end;
  248. end;
  249. end
  250. else
  251. // overflow checking is on and we have an addn, subn or muln
  252. begin
  253. if is_signed(resultdef) then
  254. begin
  255. case nodetype of
  256. addn:
  257. op := A_ADDO;
  258. subn:
  259. begin
  260. op := A_SUBO;
  261. if (nf_swapped in flags) then
  262. swapleftright;
  263. end;
  264. muln:
  265. op := A_MULLDO;
  266. else
  267. internalerror(2002072601);
  268. end;
  269. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op, location.register,
  270. left.location.register, right.location.register));
  271. cg.g_overflowcheck(current_asmdata.CurrAsmList, location, resultdef);
  272. end
  273. else
  274. begin
  275. case nodetype of
  276. addn:
  277. begin
  278. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_ADD, location.register,
  279. left.location.register, right.location.register));
  280. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMPLD, location.register,
  281. left.location.register));
  282. cg.g_overflowcheck(current_asmdata.CurrAsmList, location, resultdef);
  283. end;
  284. subn:
  285. begin
  286. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SUB, location.register,
  287. left.location.register, right.location.register));
  288. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMPLD,
  289. left.location.register, location.register));
  290. cg.g_overflowcheck(current_asmdata.CurrAsmList, location, resultdef);
  291. end;
  292. muln:
  293. begin
  294. { calculate the upper 64 bits of the product, = 0 if no overflow }
  295. cg.a_reg_alloc(current_asmdata.CurrAsmList, NR_R0);
  296. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_MULHDU_, NR_R0,
  297. left.location.register, right.location.register));
  298. cg.a_reg_dealloc(current_asmdata.CurrAsmList, NR_R0);
  299. { calculate the real result }
  300. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_MULLD, location.register,
  301. left.location.register, right.location.register));
  302. { g_overflowcheck generates a OC_AE instead of OC_EQ :/ }
  303. current_asmdata.getjumplabel(hl);
  304. tcgppc(cg).a_jmp_cond(current_asmdata.CurrAsmList, OC_EQ, hl);
  305. cg.a_call_name(current_asmdata.CurrAsmList, 'FPC_OVERFLOW');
  306. cg.a_label(current_asmdata.CurrAsmList, hl);
  307. end;
  308. end;
  309. end;
  310. end;
  311. end;
  312. begin
  313. caddnode := tppcaddnode;
  314. end.