nppcadd.pas 12 KB

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