nppcadd.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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. checkoverflow: boolean;
  124. { true, if unsigned types are compared }
  125. unsigned: boolean;
  126. begin
  127. { to make it more readable, string and set (not smallset!) have their
  128. own procedures }
  129. case left.resultdef.typ of
  130. orddef:
  131. begin
  132. { handling boolean expressions }
  133. if is_boolean(left.resultdef) and
  134. is_boolean(right.resultdef) then
  135. begin
  136. second_addboolean;
  137. exit;
  138. end;
  139. end;
  140. stringdef:
  141. begin
  142. internalerror(2002072402);
  143. exit;
  144. end;
  145. setdef:
  146. begin
  147. { normalsets are already handled in pass1 }
  148. if not is_smallset(left.resultdef) then
  149. internalerror(200109041);
  150. second_addsmallset;
  151. exit;
  152. end;
  153. arraydef:
  154. begin
  155. {$IFDEF SUPPORT_MMX}
  156. if is_mmx_able_array(left.resultdef) then
  157. begin
  158. second_addmmx;
  159. exit;
  160. end;
  161. {$ENDIF SUPPORT_MMX}
  162. end;
  163. floatdef:
  164. begin
  165. second_addfloat;
  166. exit;
  167. end;
  168. end;
  169. { defaults }
  170. cmpop := nodetype in [ltn, lten, gtn, gten, equaln, unequaln];
  171. unsigned := not (is_signed(left.resultdef)) or
  172. not (is_signed(right.resultdef));
  173. pass_left_and_right;
  174. { Convert flags to register first }
  175. { can any of these things be in the flags actually?? (JM) }
  176. if (left.location.loc = LOC_FLAGS) or
  177. (right.location.loc = LOC_FLAGS) then
  178. internalerror(2002072602);
  179. { set result location }
  180. if not cmpop then
  181. location_reset(location, LOC_REGISTER, def_cgsize(resultdef))
  182. else
  183. location_reset(location, LOC_FLAGS, OS_NO);
  184. checkoverflow:=
  185. (nodetype in [addn,subn,muln]) and
  186. (cs_check_overflow in current_settings.localswitches) and
  187. (left.resultdef.typ<>pointerdef) and
  188. (right.resultdef.typ<>pointerdef);
  189. load_left_right(cmpop, checkoverflow);
  190. if not (cmpop) then
  191. location.register := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
  192. if not (checkoverflow) then begin
  193. case nodetype of
  194. addn, muln, xorn, orn, andn:
  195. begin
  196. case nodetype of
  197. addn:
  198. cgop := OP_ADD;
  199. muln:
  200. if unsigned then
  201. cgop := OP_MUL
  202. else
  203. cgop := OP_IMUL;
  204. xorn:
  205. cgop := OP_XOR;
  206. orn:
  207. cgop := OP_OR;
  208. andn:
  209. cgop := OP_AND;
  210. end;
  211. if (left.location.loc = LOC_CONSTANT) then
  212. swapleftright;
  213. if (right.location.loc <> LOC_CONSTANT) then
  214. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, cgop, OS_INT,
  215. left.location.register, right.location.register,
  216. location.register)
  217. else
  218. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, cgop, OS_INT,
  219. right.location.value, left.location.register,
  220. location.register);
  221. end;
  222. subn:
  223. begin
  224. if (nf_swapped in flags) then
  225. swapleftright;
  226. if left.location.loc <> LOC_CONSTANT then
  227. if right.location.loc <> LOC_CONSTANT then begin
  228. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_SUB, OS_INT,
  229. right.location.register, left.location.register,
  230. location.register);
  231. end else begin
  232. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SUB, OS_INT,
  233. right.location.value, left.location.register,
  234. location.register);
  235. end
  236. else
  237. begin
  238. tmpreg := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
  239. cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_INT,
  240. left.location.value, tmpreg);
  241. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList, OP_SUB, OS_INT,
  242. right.location.register, tmpreg, location.register);
  243. end;
  244. end;
  245. ltn, lten, gtn, gten, equaln, unequaln:
  246. begin
  247. {$ifdef extdebug}
  248. current_asmdata.CurrAsmList.concat(tai_comment.create('tppcaddnode.pass2'));
  249. {$endif extdebug}
  250. emit_compare(unsigned);
  251. end;
  252. end;
  253. end
  254. else
  255. // overflow checking is on and we have an addn, subn or muln
  256. begin
  257. if is_signed(resultdef) then
  258. begin
  259. case nodetype of
  260. addn:
  261. op := A_ADDO;
  262. subn:
  263. begin
  264. op := A_SUBO;
  265. if (nf_swapped in flags) then
  266. swapleftright;
  267. end;
  268. muln:
  269. op := A_MULLDO;
  270. else
  271. internalerror(2002072601);
  272. end;
  273. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op, location.register,
  274. left.location.register, right.location.register));
  275. cg.g_overflowcheck(current_asmdata.CurrAsmList, location, resultdef);
  276. end
  277. else
  278. begin
  279. case nodetype of
  280. addn:
  281. begin
  282. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_ADD, location.register,
  283. left.location.register, right.location.register));
  284. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMPLD, location.register,
  285. left.location.register));
  286. cg.g_overflowcheck(current_asmdata.CurrAsmList, location, resultdef);
  287. end;
  288. subn:
  289. begin
  290. if (nf_swapped in flags) then
  291. swapleftright;
  292. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SUB, location.register,
  293. left.location.register, right.location.register));
  294. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMPLD,
  295. left.location.register, location.register));
  296. cg.g_overflowcheck(current_asmdata.CurrAsmList, location, resultdef);
  297. end;
  298. muln:
  299. begin
  300. { calculate the upper 64 bits of the product, = 0 if no overflow }
  301. cg.a_reg_alloc(current_asmdata.CurrAsmList, NR_R0);
  302. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_MULHDU_, NR_R0,
  303. left.location.register, right.location.register));
  304. cg.a_reg_dealloc(current_asmdata.CurrAsmList, NR_R0);
  305. { calculate the real result }
  306. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_MULLD, location.register,
  307. left.location.register, right.location.register));
  308. { g_overflowcheck generates a OC_AE instead of OC_EQ :/ }
  309. current_asmdata.getjumplabel(hl);
  310. tcgppc(cg).a_jmp_cond(current_asmdata.CurrAsmList, OC_EQ, hl);
  311. cg.a_call_name(current_asmdata.CurrAsmList, 'FPC_OVERFLOW',false);
  312. cg.a_label(current_asmdata.CurrAsmList, hl);
  313. end;
  314. end;
  315. end;
  316. end;
  317. end;
  318. begin
  319. caddnode := tppcaddnode;
  320. end.