nppcadd.pas 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429
  1. {
  2. Copyright (c) 2000-2002 by Florian Klaempfl and Jonas Maebe
  3. Code generation for add nodes on the PowerPC
  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,cpubase;
  22. type
  23. tppcaddnode = class(tcgaddnode)
  24. function pass_1: tnode; override;
  25. procedure pass_2;override;
  26. protected
  27. function use_generic_mul32to64: boolean; override;
  28. private
  29. procedure pass_left_and_right;
  30. procedure load_left_right(cmpop, load_constants: boolean);
  31. function getresflags : tresflags;
  32. procedure emit_compare(unsigned : boolean);
  33. procedure second_addfloat;override;
  34. procedure second_addboolean;override;
  35. procedure second_addsmallset;override;
  36. {$ifdef SUPPORT_MMX}
  37. procedure second_addmmx;override;
  38. {$endif SUPPORT_MMX}
  39. procedure second_add64bit;override;
  40. end;
  41. implementation
  42. uses
  43. globtype,systems,
  44. cutils,verbose,globals,
  45. symconst,symdef,paramgr,
  46. aasmbase,aasmtai,aasmdata,aasmcpu,defutil,htypechk,
  47. cgbase,cpuinfo,pass_1,pass_2,regvars,
  48. cpupara,cgcpu,cgutils,procinfo,
  49. ncon,nset,
  50. ncgutil,tgobj,rgobj,rgcpu,cgobj,cg64f32;
  51. {*****************************************************************************
  52. Pass 1
  53. *****************************************************************************}
  54. function tppcaddnode.pass_1: tnode;
  55. begin
  56. resulttypepass(left);
  57. if (nodetype in [equaln,unequaln]) and
  58. (left.resulttype.def.deftype = orddef) and
  59. is_64bit(left.resulttype.def) then
  60. begin
  61. result := nil;
  62. firstpass(left);
  63. firstpass(right);
  64. expectloc := LOC_FLAGS;
  65. calcregisters(self,2,0,0);
  66. exit;
  67. end;
  68. result := inherited pass_1;
  69. end;
  70. function tppcaddnode.use_generic_mul32to64: boolean;
  71. begin
  72. result := false;
  73. end;
  74. {*****************************************************************************
  75. Helpers
  76. *****************************************************************************}
  77. procedure tppcaddnode.pass_left_and_right;
  78. begin
  79. { calculate the operator which is more difficult }
  80. firstcomplex(self);
  81. { in case of constant put it to the left }
  82. if (left.nodetype=ordconstn) then
  83. swapleftright;
  84. secondpass(left);
  85. secondpass(right);
  86. end;
  87. procedure tppcaddnode.load_left_right(cmpop, load_constants: boolean);
  88. procedure load_node(var n: tnode);
  89. begin
  90. case n.location.loc of
  91. LOC_REGISTER,
  92. LOC_CREGISTER:
  93. ;
  94. LOC_REFERENCE,LOC_CREFERENCE:
  95. location_force_reg(current_asmdata.CurrAsmList,n.location,def_cgsize(n.resulttype.def),false);
  96. LOC_CONSTANT:
  97. begin
  98. if load_constants then
  99. location_force_reg(current_asmdata.CurrAsmList,n.location,def_cgsize(n.resulttype.def),false);
  100. end;
  101. else
  102. location_force_reg(current_asmdata.CurrAsmList,n.location,def_cgsize(n.resulttype.def),false);
  103. end;
  104. end;
  105. begin
  106. load_node(left);
  107. load_node(right);
  108. if not(cmpop) then
  109. begin
  110. location.register := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  111. if is_64bit(resulttype.def) then
  112. location.register64.reghi := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  113. end;
  114. end;
  115. function tppcaddnode.getresflags : tresflags;
  116. begin
  117. if (left.resulttype.def.deftype <> floatdef) then
  118. result.cr := RS_CR0
  119. else
  120. result.cr := RS_CR1;
  121. case nodetype of
  122. equaln : result.flag:=F_EQ;
  123. unequaln : result.flag:=F_NE;
  124. else
  125. if nf_swaped in flags then
  126. case nodetype of
  127. ltn : result.flag:=F_GT;
  128. lten : result.flag:=F_GE;
  129. gtn : result.flag:=F_LT;
  130. gten : result.flag:=F_LE;
  131. end
  132. else
  133. case nodetype of
  134. ltn : result.flag:=F_LT;
  135. lten : result.flag:=F_LE;
  136. gtn : result.flag:=F_GT;
  137. gten : result.flag:=F_GE;
  138. end;
  139. end
  140. end;
  141. procedure tppcaddnode.emit_compare(unsigned: boolean);
  142. var
  143. op : tasmop;
  144. tmpreg : tregister;
  145. useconst : boolean;
  146. begin
  147. // get the constant on the right if there is one
  148. if (left.location.loc = LOC_CONSTANT) then
  149. swapleftright;
  150. // can we use an immediate, or do we have to load the
  151. // constant in a register first?
  152. if (right.location.loc = LOC_CONSTANT) then
  153. begin
  154. {$ifdef dummy}
  155. if (right.location.size in [OS_64,OS_S64]) and (hi(right.location.value64)<>0) and ((hi(right.location.value64)<>$ffffffff) or unsigned) then
  156. internalerror(2002080301);
  157. {$endif extdebug}
  158. if (nodetype in [equaln,unequaln]) then
  159. if (unsigned and
  160. (aword(right.location.value) > high(word))) or
  161. (not unsigned and
  162. (aint(right.location.value) < low(smallint)) or
  163. (aint(right.location.value) > high(smallint))) then
  164. { we can then maybe use a constant in the 'othersigned' case
  165. (the sign doesn't matter for // equal/unequal)}
  166. unsigned := not unsigned;
  167. if (unsigned and
  168. (aword(right.location.value) <= high(word))) or
  169. (not(unsigned) and
  170. (aint(right.location.value) >= low(smallint)) and
  171. (aint(right.location.value) <= high(smallint))) then
  172. useconst := true
  173. else
  174. begin
  175. useconst := false;
  176. tmpreg := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  177. cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,
  178. right.location.value,tmpreg);
  179. end
  180. end
  181. else
  182. useconst := false;
  183. location.loc := LOC_FLAGS;
  184. location.resflags := getresflags;
  185. if not unsigned then
  186. if useconst then
  187. op := A_CMPWI
  188. else
  189. op := A_CMPW
  190. else
  191. if useconst then
  192. op := A_CMPLWI
  193. else
  194. op := A_CMPLW;
  195. if (right.location.loc = LOC_CONSTANT) then
  196. begin
  197. if useconst then
  198. current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(op,left.location.register,longint(right.location.value)))
  199. else
  200. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op,left.location.register,tmpreg));
  201. end
  202. else
  203. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op,
  204. left.location.register,right.location.register));
  205. end;
  206. {*****************************************************************************
  207. AddBoolean
  208. *****************************************************************************}
  209. procedure tppcaddnode.second_addboolean;
  210. var
  211. cgop : TOpCg;
  212. cgsize : TCgSize;
  213. cmpop,
  214. isjump : boolean;
  215. otl,ofl : tasmlabel;
  216. begin
  217. { calculate the operator which is more difficult }
  218. firstcomplex(self);
  219. cmpop:=false;
  220. if (torddef(left.resulttype.def).typ=bool8bit) or
  221. (torddef(right.resulttype.def).typ=bool8bit) then
  222. cgsize:=OS_8
  223. else
  224. if (torddef(left.resulttype.def).typ=bool16bit) or
  225. (torddef(right.resulttype.def).typ=bool16bit) then
  226. cgsize:=OS_16
  227. else
  228. cgsize:=OS_32;
  229. if ((cs_full_boolean_eval in aktlocalswitches) and
  230. not(nf_short_bool in flags)) or
  231. (nodetype in [unequaln,ltn,lten,gtn,gten,equaln,xorn]) then
  232. begin
  233. if left.nodetype in [ordconstn,realconstn] then
  234. swapleftright;
  235. isjump:=(left.expectloc=LOC_JUMP);
  236. if isjump then
  237. begin
  238. otl:=current_procinfo.CurrTrueLabel;
  239. current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel);
  240. ofl:=current_procinfo.CurrFalseLabel;
  241. current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel);
  242. end;
  243. secondpass(left);
  244. if left.location.loc in [LOC_FLAGS,LOC_JUMP] then
  245. location_force_reg(current_asmdata.CurrAsmList,left.location,cgsize,false);
  246. if isjump then
  247. begin
  248. current_procinfo.CurrTrueLabel:=otl;
  249. current_procinfo.CurrFalseLabel:=ofl;
  250. end
  251. else if left.location.loc=LOC_JUMP then
  252. internalerror(2003122901);
  253. isjump:=(right.expectloc=LOC_JUMP);
  254. if isjump then
  255. begin
  256. otl:=current_procinfo.CurrTrueLabel;
  257. current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel);
  258. ofl:=current_procinfo.CurrFalseLabel;
  259. current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel);
  260. end;
  261. secondpass(right);
  262. if right.location.loc in [LOC_FLAGS,LOC_JUMP] then
  263. location_force_reg(current_asmdata.CurrAsmList,right.location,cgsize,false);
  264. if isjump then
  265. begin
  266. current_procinfo.CurrTrueLabel:=otl;
  267. current_procinfo.CurrFalseLabel:=ofl;
  268. end
  269. else if right.location.loc=LOC_JUMP then
  270. internalerror(200312292);
  271. cmpop := nodetype in [ltn,lten,gtn,gten,equaln,unequaln];
  272. { set result location }
  273. if not cmpop then
  274. location_reset(location,LOC_REGISTER,def_cgsize(resulttype.def))
  275. else
  276. location_reset(location,LOC_FLAGS,OS_NO);
  277. load_left_right(cmpop,false);
  278. if (left.location.loc = LOC_CONSTANT) then
  279. swapleftright;
  280. { compare the }
  281. case nodetype of
  282. ltn,lten,gtn,gten,
  283. equaln,unequaln :
  284. begin
  285. if (right.location.loc <> LOC_CONSTANT) then
  286. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMPLW,
  287. left.location.register,right.location.register))
  288. else
  289. current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_CMPLWI,
  290. left.location.register,longint(right.location.value)));
  291. location.resflags := getresflags;
  292. end;
  293. else
  294. begin
  295. case nodetype of
  296. xorn :
  297. cgop:=OP_XOR;
  298. orn :
  299. cgop:=OP_OR;
  300. andn :
  301. cgop:=OP_AND;
  302. else
  303. internalerror(200203247);
  304. end;
  305. if right.location.loc <> LOC_CONSTANT then
  306. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,cgop,OS_INT,
  307. left.location.register,right.location.register,
  308. location.register)
  309. else
  310. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,cgop,OS_INT,
  311. right.location.value,left.location.register,
  312. location.register);
  313. end;
  314. end;
  315. end
  316. else
  317. inherited second_addboolean;
  318. end;
  319. {*****************************************************************************
  320. AddFloat
  321. *****************************************************************************}
  322. procedure tppcaddnode.second_addfloat;
  323. var
  324. op : TAsmOp;
  325. cmpop,
  326. singleprec : boolean;
  327. begin
  328. pass_left_and_right;
  329. cmpop:=false;
  330. singleprec:=tfloatdef(left.resulttype.def).typ=s32real;
  331. case nodetype of
  332. addn :
  333. if singleprec then
  334. op:=A_FADDS
  335. else
  336. op:=A_FADD;
  337. muln :
  338. if singleprec then
  339. op:=A_FMULS
  340. else
  341. op:=A_FMUL;
  342. subn :
  343. if singleprec then
  344. op:=A_FSUBS
  345. else
  346. op:=A_FSUB;
  347. slashn :
  348. if singleprec then
  349. op:=A_FDIVS
  350. else
  351. op:=A_FDIV;
  352. ltn,lten,gtn,gten,
  353. equaln,unequaln :
  354. begin
  355. op:=A_FCMPO;
  356. cmpop:=true;
  357. end;
  358. else
  359. internalerror(200403182);
  360. end;
  361. // get the operands in the correct order, there are no special cases
  362. // here, everything is register-based
  363. if nf_swaped in flags then
  364. swapleftright;
  365. // put both operands in a register
  366. location_force_fpureg(current_asmdata.CurrAsmList,right.location,true);
  367. location_force_fpureg(current_asmdata.CurrAsmList,left.location,true);
  368. // initialize de result
  369. if not cmpop then
  370. begin
  371. location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
  372. location.register := cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
  373. end
  374. else
  375. begin
  376. location_reset(location,LOC_FLAGS,OS_NO);
  377. location.resflags := getresflags;
  378. end;
  379. // emit the actual operation
  380. if not cmpop then
  381. begin
  382. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,
  383. location.register,left.location.register,
  384. right.location.register))
  385. end
  386. else
  387. begin
  388. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,
  389. newreg(R_SPECIALREGISTER,location.resflags.cr,R_SUBNONE),left.location.register,right.location.register))
  390. end;
  391. end;
  392. {*****************************************************************************
  393. AddSmallSet
  394. *****************************************************************************}
  395. procedure tppcaddnode.second_addsmallset;
  396. var
  397. cgop : TOpCg;
  398. tmpreg : tregister;
  399. opdone,
  400. cmpop : boolean;
  401. begin
  402. pass_left_and_right;
  403. { when a setdef is passed, it has to be a smallset }
  404. if ((left.resulttype.def.deftype=setdef) and
  405. (tsetdef(left.resulttype.def).settype<>smallset)) or
  406. ((right.resulttype.def.deftype=setdef) and
  407. (tsetdef(right.resulttype.def).settype<>smallset)) then
  408. internalerror(200203301);
  409. opdone := false;
  410. cmpop:=nodetype in [equaln,unequaln,lten,gten];
  411. { set result location }
  412. if not cmpop then
  413. location_reset(location,LOC_REGISTER,def_cgsize(resulttype.def))
  414. else
  415. location_reset(location,LOC_FLAGS,OS_NO);
  416. load_left_right(cmpop,false);
  417. if not(cmpop) then
  418. location.register := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  419. case nodetype of
  420. addn :
  421. begin
  422. if (nf_swaped in flags) and (left.nodetype=setelementn) then
  423. swapleftright;
  424. { are we adding set elements ? }
  425. if right.nodetype=setelementn then
  426. begin
  427. { no range support for smallsets! }
  428. if assigned(tsetelementnode(right).right) then
  429. internalerror(43244);
  430. if (right.location.loc = LOC_CONSTANT) then
  431. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_OR,OS_INT,
  432. aint(aword(1) shl aword(right.location.value)),
  433. left.location.register,location.register)
  434. else
  435. begin
  436. tmpreg := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  437. cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,1,tmpreg);
  438. cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_SHL,OS_INT,
  439. right.location.register,tmpreg);
  440. if left.location.loc <> LOC_CONSTANT then
  441. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_OR,OS_INT,tmpreg,
  442. left.location.register,location.register)
  443. else
  444. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_OR,OS_INT,
  445. left.location.value,tmpreg,location.register);
  446. end;
  447. opdone := true;
  448. end
  449. else
  450. cgop := OP_OR;
  451. end;
  452. symdifn :
  453. cgop:=OP_XOR;
  454. muln :
  455. cgop:=OP_AND;
  456. subn :
  457. begin
  458. cgop:=OP_AND;
  459. if (not(nf_swaped in flags)) then
  460. if (right.location.loc=LOC_CONSTANT) then
  461. right.location.value := not(right.location.value)
  462. else
  463. opdone := true
  464. else if (left.location.loc=LOC_CONSTANT) then
  465. left.location.value := not(left.location.value)
  466. else
  467. begin
  468. swapleftright;
  469. opdone := true;
  470. end;
  471. if opdone then
  472. begin
  473. if left.location.loc = LOC_CONSTANT then
  474. begin
  475. tmpreg := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  476. cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,
  477. left.location.value,tmpreg);
  478. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_ANDC,
  479. location.register,tmpreg,right.location.register));
  480. end
  481. else
  482. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_ANDC,
  483. location.register,left.location.register,
  484. right.location.register));
  485. end;
  486. end;
  487. equaln,
  488. unequaln :
  489. begin
  490. emit_compare(true);
  491. opdone := true;
  492. end;
  493. lten,gten:
  494. begin
  495. If (not(nf_swaped in flags) and
  496. (nodetype = lten)) or
  497. ((nf_swaped in flags) and
  498. (nodetype = gten)) then
  499. swapleftright;
  500. // now we have to check whether left >= right
  501. tmpreg := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  502. if left.location.loc = LOC_CONSTANT then
  503. begin
  504. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_AND,OS_INT,
  505. not(left.location.value),right.location.register,tmpreg);
  506. current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_CMPWI,tmpreg,0));
  507. // the two instructions above should be folded together by
  508. // the peepholeoptimizer
  509. end
  510. else
  511. begin
  512. if right.location.loc = LOC_CONSTANT then
  513. begin
  514. cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,
  515. right.location.value,tmpreg);
  516. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_ANDC_,tmpreg,
  517. tmpreg,left.location.register));
  518. end
  519. else
  520. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_ANDC_,tmpreg,
  521. right.location.register,left.location.register));
  522. end;
  523. location.resflags.cr := RS_CR0;
  524. location.resflags.flag := F_EQ;
  525. opdone := true;
  526. end;
  527. else
  528. internalerror(2002072701);
  529. end;
  530. if not opdone then
  531. begin
  532. // these are all commutative operations
  533. if (left.location.loc = LOC_CONSTANT) then
  534. swapleftright;
  535. if (right.location.loc = LOC_CONSTANT) then
  536. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,cgop,OS_INT,
  537. right.location.value,left.location.register,
  538. location.register)
  539. else
  540. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,cgop,OS_INT,
  541. right.location.register,left.location.register,
  542. location.register);
  543. end;
  544. end;
  545. {*****************************************************************************
  546. Add64bit
  547. *****************************************************************************}
  548. procedure tppcaddnode.second_add64bit;
  549. var
  550. op : TOpCG;
  551. op1,op2 : TAsmOp;
  552. cmpop,
  553. unsigned : boolean;
  554. procedure emit_cmp64_hi;
  555. var
  556. oldleft, oldright: tlocation;
  557. begin
  558. // put the high part of the location in the low part
  559. location_copy(oldleft,left.location);
  560. location_copy(oldright,right.location);
  561. if left.location.loc = LOC_CONSTANT then
  562. left.location.value64 := left.location.value64 shr 32
  563. else
  564. left.location.register64.reglo := left.location.register64.reghi;
  565. if right.location.loc = LOC_CONSTANT then
  566. right.location.value64 := right.location.value64 shr 32
  567. else
  568. right.location.register64.reglo := right.location.register64.reghi;
  569. // and call the normal emit_compare
  570. emit_compare(unsigned);
  571. location_copy(left.location,oldleft);
  572. location_copy(right.location,oldright);
  573. end;
  574. procedure emit_cmp64_lo;
  575. begin
  576. emit_compare(true);
  577. end;
  578. procedure firstjmp64bitcmp;
  579. var
  580. oldnodetype: tnodetype;
  581. begin
  582. {$ifdef OLDREGVARS}
  583. load_all_regvars(current_asmdata.CurrAsmList);
  584. {$endif OLDREGVARS}
  585. { the jump the sequence is a little bit hairy }
  586. case nodetype of
  587. ltn,gtn:
  588. begin
  589. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags,current_procinfo.CurrTrueLabel);
  590. { cheat a little bit for the negative test }
  591. toggleflag(nf_swaped);
  592. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags,current_procinfo.CurrFalseLabel);
  593. toggleflag(nf_swaped);
  594. end;
  595. lten,gten:
  596. begin
  597. oldnodetype:=nodetype;
  598. if nodetype=lten then
  599. nodetype:=ltn
  600. else
  601. nodetype:=gtn;
  602. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags,current_procinfo.CurrTrueLabel);
  603. { cheat for the negative test }
  604. if nodetype=ltn then
  605. nodetype:=gtn
  606. else
  607. nodetype:=ltn;
  608. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags,current_procinfo.CurrFalseLabel);
  609. nodetype:=oldnodetype;
  610. end;
  611. equaln:
  612. begin
  613. nodetype := unequaln;
  614. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags,current_procinfo.CurrFalseLabel);
  615. nodetype := equaln;
  616. end;
  617. unequaln:
  618. begin
  619. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags,current_procinfo.CurrTrueLabel);
  620. end;
  621. end;
  622. end;
  623. procedure secondjmp64bitcmp;
  624. begin
  625. { the jump the sequence is a little bit hairy }
  626. case nodetype of
  627. ltn,gtn,lten,gten:
  628. begin
  629. { the comparison of the low dword always has }
  630. { to be always unsigned! }
  631. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags,current_procinfo.CurrTrueLabel);
  632. cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
  633. end;
  634. equaln:
  635. begin
  636. nodetype := unequaln;
  637. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags,current_procinfo.CurrFalseLabel);
  638. cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrTrueLabel);
  639. nodetype := equaln;
  640. end;
  641. unequaln:
  642. begin
  643. cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags,current_procinfo.CurrTrueLabel);
  644. cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
  645. end;
  646. end;
  647. end;
  648. var
  649. tempreg64: tregister64;
  650. begin
  651. firstcomplex(self);
  652. pass_left_and_right;
  653. cmpop:=false;
  654. unsigned:=((left.resulttype.def.deftype=orddef) and
  655. (torddef(left.resulttype.def).typ=u64bit)) or
  656. ((right.resulttype.def.deftype=orddef) and
  657. (torddef(right.resulttype.def).typ=u64bit));
  658. case nodetype of
  659. addn :
  660. begin
  661. op:=OP_ADD;
  662. end;
  663. subn :
  664. begin
  665. op:=OP_SUB;
  666. if (nf_swaped in flags) then
  667. swapleftright;
  668. end;
  669. ltn,lten,
  670. gtn,gten,
  671. equaln,unequaln:
  672. begin
  673. op:=OP_NONE;
  674. cmpop:=true;
  675. end;
  676. xorn:
  677. op:=OP_XOR;
  678. orn:
  679. op:=OP_OR;
  680. andn:
  681. op:=OP_AND;
  682. muln:
  683. begin
  684. { should be handled in pass_1 (JM) }
  685. if not(torddef(left.resulttype.def).typ in [U32bit,s32bit]) or
  686. (torddef(left.resulttype.def).typ <> torddef(right.resulttype.def).typ) then
  687. internalerror(200109051);
  688. { handled separately }
  689. op := OP_NONE;
  690. end;
  691. else
  692. internalerror(2002072705);
  693. end;
  694. if not cmpop then
  695. location_reset(location,LOC_REGISTER,def_cgsize(resulttype.def));
  696. load_left_right(cmpop,((cs_check_overflow in aktlocalswitches) and
  697. (nodetype in [addn,subn])) or (nodetype = muln));
  698. if (nodetype <> muln) and
  699. (not(cs_check_overflow in aktlocalswitches) or
  700. not(nodetype in [addn,subn])) then
  701. begin
  702. case nodetype of
  703. ltn,lten,
  704. gtn,gten:
  705. begin
  706. emit_cmp64_hi;
  707. firstjmp64bitcmp;
  708. emit_cmp64_lo;
  709. secondjmp64bitcmp;
  710. end;
  711. equaln,unequaln:
  712. begin
  713. // instead of doing a complicated compare, do
  714. // (left.hi xor right.hi) or (left.lo xor right.lo)
  715. // (somewhate optimized so that no superfluous 'mr's are
  716. // generated)
  717. if (left.location.loc = LOC_CONSTANT) then
  718. swapleftright;
  719. if (right.location.loc = LOC_CONSTANT) then
  720. begin
  721. if left.location.loc = LOC_REGISTER then
  722. begin
  723. tempreg64.reglo := left.location.register64.reglo;
  724. tempreg64.reghi := left.location.register64.reghi;
  725. end
  726. else
  727. begin
  728. if (aint(right.location.value64) <> 0) then
  729. tempreg64.reglo := cg.getintregister(current_asmdata.CurrAsmList,OS_32)
  730. else
  731. tempreg64.reglo := left.location.register64.reglo;
  732. if ((right.location.value64 shr 32) <> 0) then
  733. tempreg64.reghi := cg.getintregister(current_asmdata.CurrAsmList,OS_32)
  734. else
  735. tempreg64.reghi := left.location.register64.reghi;
  736. end;
  737. if (aint(right.location.value64) <> 0) then
  738. { negative values can be handled using SUB, }
  739. { positive values < 65535 using XOR. }
  740. if (longint(right.location.value64) >= -32767) and
  741. (longint(right.location.value64) < 0) then
  742. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SUB,OS_INT,
  743. aint(right.location.value64),
  744. left.location.register64.reglo,tempreg64.reglo)
  745. else
  746. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_XOR,OS_INT,
  747. aint(right.location.value64),
  748. left.location.register64.reglo,tempreg64.reglo);
  749. if ((right.location.value64 shr 32) <> 0) then
  750. if (longint(right.location.value64 shr 32) >= -32767) and
  751. (longint(right.location.value64 shr 32) < 0) then
  752. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SUB,OS_INT,
  753. aint(right.location.value64 shr 32),
  754. left.location.register64.reghi,tempreg64.reghi)
  755. else
  756. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_XOR,OS_INT,
  757. aint(right.location.value64 shr 32),
  758. left.location.register64.reghi,tempreg64.reghi);
  759. end
  760. else
  761. begin
  762. tempreg64.reglo := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  763. tempreg64.reghi := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  764. cg64.a_op64_reg_reg_reg(current_asmdata.CurrAsmList,OP_XOR,location.size,
  765. left.location.register64,right.location.register64,
  766. tempreg64);
  767. end;
  768. cg.a_reg_alloc(current_asmdata.CurrAsmList,NR_R0);
  769. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_OR_,NR_R0,
  770. tempreg64.reglo,tempreg64.reghi));
  771. cg.a_reg_dealloc(current_asmdata.CurrAsmList,NR_R0);
  772. location_reset(location,LOC_FLAGS,OS_NO);
  773. location.resflags := getresflags;
  774. end;
  775. xorn,orn,andn,addn:
  776. begin
  777. location.register64.reglo := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  778. location.register64.reghi := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  779. if (left.location.loc = LOC_CONSTANT) then
  780. swapleftright;
  781. if (right.location.loc = LOC_CONSTANT) then
  782. cg64.a_op64_const_reg_reg(current_asmdata.CurrAsmList,op,location.size,right.location.value64,
  783. left.location.register64,location.register64)
  784. else
  785. cg64.a_op64_reg_reg_reg(current_asmdata.CurrAsmList,op,location.size,right.location.register64,
  786. left.location.register64,location.register64);
  787. end;
  788. subn:
  789. begin
  790. location.register64.reglo := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  791. location.register64.reghi := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  792. if left.location.loc <> LOC_CONSTANT then
  793. begin
  794. if right.location.loc <> LOC_CONSTANT then
  795. // reg64 - reg64
  796. cg64.a_op64_reg_reg_reg(current_asmdata.CurrAsmList,OP_SUB,location.size,
  797. right.location.register64,left.location.register64,
  798. location.register64)
  799. else
  800. // reg64 - const64
  801. cg64.a_op64_const_reg_reg(current_asmdata.CurrAsmList,OP_SUB,location.size,
  802. right.location.value64,left.location.register64,
  803. location.register64)
  804. end
  805. else if ((left.location.value64 shr 32) = 0) then
  806. begin
  807. if (int64(left.location.value64) >= low(smallint)) and
  808. (int64(left.location.value64) <= high(smallint)) then
  809. begin
  810. // consts16 - reg64
  811. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_SUBFIC,
  812. location.register64.reglo,right.location.register64.reglo,
  813. left.location.value));
  814. end
  815. else
  816. begin
  817. // const32 - reg64
  818. location_force_reg(current_asmdata.CurrAsmList,left.location,
  819. OS_32,true);
  820. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SUBC,
  821. location.register64.reglo,left.location.register64.reglo,
  822. right.location.register64.reglo));
  823. end;
  824. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_SUBFZE,
  825. location.register64.reghi,right.location.register64.reghi));
  826. end
  827. else if (aint(left.location.value64) = 0) then
  828. begin
  829. // (const32 shl 32) - reg64
  830. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_SUBFIC,
  831. location.register64.reglo,right.location.register64.reglo,0));
  832. left.location.value64 := left.location.value64 shr 32;
  833. location_force_reg(current_asmdata.CurrAsmList,left.location,OS_32,true);
  834. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SUBFE,
  835. location.register64.reghi,right.location.register64.reghi,
  836. left.location.register));
  837. end
  838. else
  839. begin
  840. // const64 - reg64
  841. location_force_reg(current_asmdata.CurrAsmList,left.location,
  842. def_cgsize(left.resulttype.def),false);
  843. cg64.a_op64_reg_reg_reg(current_asmdata.CurrAsmList,OP_SUB,location.size,
  844. right.location.register64,left.location.register64,
  845. location.register64);
  846. end;
  847. end;
  848. else
  849. internalerror(2002072803);
  850. end;
  851. end
  852. else
  853. begin
  854. if is_signed(resulttype.def) then
  855. begin
  856. case nodetype of
  857. addn:
  858. begin
  859. op1 := A_ADDC;
  860. op2 := A_ADDEO;
  861. end;
  862. subn:
  863. begin
  864. op1 := A_SUBC;
  865. op2 := A_SUBFEO;
  866. end;
  867. muln:
  868. begin
  869. op1 := A_MULLW;
  870. op2 := A_MULHW
  871. end;
  872. else
  873. internalerror(2002072806);
  874. end
  875. end
  876. else
  877. begin
  878. case nodetype of
  879. addn:
  880. begin
  881. op1 := A_ADDC;
  882. op2 := A_ADDE;
  883. end;
  884. subn:
  885. begin
  886. op1 := A_SUBC;
  887. op2 := A_SUBFE;
  888. end;
  889. muln:
  890. begin
  891. op1 := A_MULLW;
  892. op2 := A_MULHWU
  893. end;
  894. end;
  895. end;
  896. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op1,location.register64.reglo,
  897. left.location.register64.reglo,right.location.register64.reglo));
  898. if (nodetype <> muln) then
  899. begin
  900. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op2,location.register64.reghi,
  901. right.location.register64.reghi,left.location.register64.reghi));
  902. if not(is_signed(resulttype.def)) then
  903. if nodetype = addn then
  904. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMPLW,location.register64.reghi,left.location.register64.reghi))
  905. else
  906. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMPLW,left.location.register64.reghi,location.register64.reghi));
  907. cg.g_overflowcheck(current_asmdata.CurrAsmList,location,resulttype.def);
  908. end
  909. else
  910. begin
  911. { 32 * 32 -> 64 cannot overflow }
  912. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op2,location.register64.reghi,
  913. left.location.register64.reglo,right.location.register64.reglo));
  914. end
  915. end;
  916. { set result location }
  917. { (emit_compare sets it to LOC_FLAGS for compares, so set the }
  918. { real location only now) (JM) }
  919. if cmpop and
  920. not(nodetype in [equaln,unequaln]) then
  921. location_reset(location,LOC_JUMP,OS_NO);
  922. end;
  923. {*****************************************************************************
  924. AddMMX
  925. *****************************************************************************}
  926. {$ifdef SUPPORT_MMX}
  927. procedure ti386addnode.second_addmmx;
  928. var
  929. op : TAsmOp;
  930. cmpop : boolean;
  931. mmxbase : tmmxtype;
  932. hregister : tregister;
  933. begin
  934. pass_left_and_right;
  935. cmpop:=false;
  936. mmxbase:=mmx_type(left.resulttype.def);
  937. case nodetype of
  938. addn :
  939. begin
  940. if (cs_mmx_saturation in aktlocalswitches) then
  941. begin
  942. case mmxbase of
  943. mmxs8bit:
  944. op:=A_PADDSB;
  945. mmxu8bit:
  946. op:=A_PADDUSB;
  947. mmxs16bit,mmxfixed16:
  948. op:=A_PADDSB;
  949. mmxu16bit:
  950. op:=A_PADDUSW;
  951. end;
  952. end
  953. else
  954. begin
  955. case mmxbase of
  956. mmxs8bit,mmxu8bit:
  957. op:=A_PADDB;
  958. mmxs16bit,mmxu16bit,mmxfixed16:
  959. op:=A_PADDW;
  960. mmxs32bit,mmxu32bit:
  961. op:=A_PADDD;
  962. end;
  963. end;
  964. end;
  965. muln :
  966. begin
  967. case mmxbase of
  968. mmxs16bit,mmxu16bit:
  969. op:=A_PMULLW;
  970. mmxfixed16:
  971. op:=A_PMULHW;
  972. end;
  973. end;
  974. subn :
  975. begin
  976. if (cs_mmx_saturation in aktlocalswitches) then
  977. begin
  978. case mmxbase of
  979. mmxs8bit:
  980. op:=A_PSUBSB;
  981. mmxu8bit:
  982. op:=A_PSUBUSB;
  983. mmxs16bit,mmxfixed16:
  984. op:=A_PSUBSB;
  985. mmxu16bit:
  986. op:=A_PSUBUSW;
  987. end;
  988. end
  989. else
  990. begin
  991. case mmxbase of
  992. mmxs8bit,mmxu8bit:
  993. op:=A_PSUBB;
  994. mmxs16bit,mmxu16bit,mmxfixed16:
  995. op:=A_PSUBW;
  996. mmxs32bit,mmxu32bit:
  997. op:=A_PSUBD;
  998. end;
  999. end;
  1000. end;
  1001. xorn:
  1002. op:=A_PXOR;
  1003. orn:
  1004. op:=A_POR;
  1005. andn:
  1006. op:=A_PAND;
  1007. else
  1008. internalerror(200403183);
  1009. end;
  1010. { left and right no register? }
  1011. { then one must be demanded }
  1012. if (left.location.loc<>LOC_MMXREGISTER) then
  1013. begin
  1014. if (right.location.loc=LOC_MMXREGISTER) then
  1015. begin
  1016. location_swap(left.location,right.location);
  1017. toggleflag(nf_swaped);
  1018. end
  1019. else
  1020. begin
  1021. { register variable ? }
  1022. if (left.location.loc=LOC_CMMXREGISTER) then
  1023. begin
  1024. hregister:=rg.getregistermm(current_asmdata.CurrAsmList);
  1025. emit_reg_reg(A_MOVQ,S_NO,left.location.register,hregister);
  1026. end
  1027. else
  1028. begin
  1029. if not(left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  1030. internalerror(200203245);
  1031. location_release(current_asmdata.CurrAsmList,left.location);
  1032. hregister:=rg.getregistermm(current_asmdata.CurrAsmList);
  1033. emit_ref_reg(A_MOVQ,S_NO,left.location.reference,hregister);
  1034. end;
  1035. location_reset(left.location,LOC_MMXREGISTER,OS_NO);
  1036. left.location.register:=hregister;
  1037. end;
  1038. end;
  1039. { at this point, left.location.loc should be LOC_MMXREGISTER }
  1040. if right.location.loc<>LOC_MMXREGISTER then
  1041. begin
  1042. if (nodetype=subn) and (nf_swaped in flags) then
  1043. begin
  1044. if right.location.loc=LOC_CMMXREGISTER then
  1045. begin
  1046. emit_reg_reg(A_MOVQ,S_NO,right.location.register,R_MM7);
  1047. emit_reg_reg(op,S_NO,left.location.register,R_MM7);
  1048. emit_reg_reg(A_MOVQ,S_NO,R_MM7,left.location.register);
  1049. end
  1050. else
  1051. begin
  1052. if not(left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  1053. internalerror(200203247);
  1054. emit_ref_reg(A_MOVQ,S_NO,right.location.reference,R_MM7);
  1055. emit_reg_reg(op,S_NO,left.location.register,R_MM7);
  1056. emit_reg_reg(A_MOVQ,S_NO,R_MM7,left.location.register);
  1057. location_release(current_asmdata.CurrAsmList,right.location);
  1058. end;
  1059. end
  1060. else
  1061. begin
  1062. if (right.location.loc=LOC_CMMXREGISTER) then
  1063. begin
  1064. emit_reg_reg(op,S_NO,right.location.register,left.location.register);
  1065. end
  1066. else
  1067. begin
  1068. if not(right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  1069. internalerror(200203246);
  1070. emit_ref_reg(op,S_NO,right.location.reference,left.location.register);
  1071. location_release(current_asmdata.CurrAsmList,right.location);
  1072. end;
  1073. end;
  1074. end
  1075. else
  1076. begin
  1077. { right.location=LOC_MMXREGISTER }
  1078. if (nodetype=subn) and (nf_swaped in flags) then
  1079. begin
  1080. emit_reg_reg(op,S_NO,left.location.register,right.location.register);
  1081. location_swap(left.location,right.location);
  1082. toggleflag(nf_swaped);
  1083. end
  1084. else
  1085. begin
  1086. emit_reg_reg(op,S_NO,right.location.register,left.location.register);
  1087. end;
  1088. end;
  1089. location_freetemp(current_asmdata.CurrAsmList,right.location);
  1090. location_release(current_asmdata.CurrAsmList,right.location);
  1091. if cmpop then
  1092. begin
  1093. location_freetemp(current_asmdata.CurrAsmList,left.location);
  1094. location_release(current_asmdata.CurrAsmList,left.location);
  1095. end;
  1096. set_result_location(cmpop,true);
  1097. end;
  1098. {$endif SUPPORT_MMX}
  1099. {*****************************************************************************
  1100. pass_2
  1101. *****************************************************************************}
  1102. procedure tppcaddnode.pass_2;
  1103. { is also being used for xor, and "mul", "sub, or and comparative }
  1104. { operators }
  1105. var
  1106. cgop : topcg;
  1107. op : tasmop;
  1108. tmpreg : tregister;
  1109. hl : tasmlabel;
  1110. cmpop : boolean;
  1111. { true, if unsigned types are compared }
  1112. unsigned : boolean;
  1113. begin
  1114. { to make it more readable, string and set (not smallset!) have their
  1115. own procedures }
  1116. case left.resulttype.def.deftype of
  1117. orddef :
  1118. begin
  1119. { handling boolean expressions }
  1120. if is_boolean(left.resulttype.def) and
  1121. is_boolean(right.resulttype.def) then
  1122. begin
  1123. second_addboolean;
  1124. exit;
  1125. end
  1126. { 64bit operations }
  1127. else if is_64bit(resulttype.def) or
  1128. is_64bit(left.resulttype.def) then
  1129. begin
  1130. second_add64bit;
  1131. exit;
  1132. end;
  1133. end;
  1134. stringdef :
  1135. begin
  1136. internalerror(2002072402);
  1137. exit;
  1138. end;
  1139. setdef :
  1140. begin
  1141. { normalsets are already handled in pass1 }
  1142. if (tsetdef(left.resulttype.def).settype<>smallset) then
  1143. internalerror(200109041);
  1144. second_addsmallset;
  1145. exit;
  1146. end;
  1147. arraydef :
  1148. begin
  1149. {$ifdef SUPPORT_MMX}
  1150. if is_mmx_able_array(left.resulttype.def) then
  1151. begin
  1152. second_addmmx;
  1153. exit;
  1154. end;
  1155. {$endif SUPPORT_MMX}
  1156. end;
  1157. floatdef :
  1158. begin
  1159. second_addfloat;
  1160. exit;
  1161. end;
  1162. end;
  1163. { defaults }
  1164. cmpop:=nodetype in [ltn,lten,gtn,gten,equaln,unequaln];
  1165. unsigned:=not(is_signed(left.resulttype.def)) or
  1166. not(is_signed(right.resulttype.def));
  1167. pass_left_and_right;
  1168. { Convert flags to register first }
  1169. { can any of these things be in the flags actually?? (JM) }
  1170. if (left.location.loc = LOC_FLAGS) or
  1171. (right.location.loc = LOC_FLAGS) then
  1172. internalerror(2002072602);
  1173. { set result location }
  1174. if not cmpop then
  1175. location_reset(location,LOC_REGISTER,def_cgsize(resulttype.def))
  1176. else
  1177. location_reset(location,LOC_FLAGS,OS_NO);
  1178. load_left_right(cmpop, (cs_check_overflow in aktlocalswitches) and
  1179. (nodetype in [addn,subn,muln]));
  1180. if not(cmpop) then
  1181. location.register := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  1182. if not(cs_check_overflow in aktlocalswitches) or
  1183. (cmpop) or
  1184. (nodetype in [orn,andn,xorn]) then
  1185. begin
  1186. case nodetype of
  1187. addn, muln, xorn, orn, andn:
  1188. begin
  1189. case nodetype of
  1190. addn:
  1191. cgop := OP_ADD;
  1192. muln:
  1193. if unsigned then
  1194. cgop := OP_MUL
  1195. else
  1196. cgop := OP_IMUL;
  1197. xorn:
  1198. cgop := OP_XOR;
  1199. orn:
  1200. cgop := OP_OR;
  1201. andn:
  1202. cgop := OP_AND;
  1203. end;
  1204. if (left.location.loc = LOC_CONSTANT) then
  1205. swapleftright;
  1206. if (right.location.loc <> LOC_CONSTANT) then
  1207. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,cgop,OS_INT,
  1208. left.location.register,right.location.register,
  1209. location.register)
  1210. else
  1211. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,cgop,OS_INT,
  1212. right.location.value,left.location.register,
  1213. location.register);
  1214. end;
  1215. subn:
  1216. begin
  1217. if (nf_swaped in flags) then
  1218. swapleftright;
  1219. if left.location.loc <> LOC_CONSTANT then
  1220. if right.location.loc <> LOC_CONSTANT then
  1221. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_SUB,OS_INT,
  1222. right.location.register,left.location.register,
  1223. location.register)
  1224. else
  1225. cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SUB,OS_INT,
  1226. right.location.value,left.location.register,
  1227. location.register)
  1228. else
  1229. if (longint(left.location.value) >= low(smallint)) and
  1230. (longint(left.location.value) <= high(smallint)) then
  1231. begin
  1232. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_SUBFIC,
  1233. location.register,right.location.register,
  1234. longint(left.location.value)));
  1235. end
  1236. else
  1237. begin
  1238. tmpreg := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  1239. cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,
  1240. left.location.value,tmpreg);
  1241. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_SUB,OS_INT,
  1242. right.location.register,tmpreg,location.register);
  1243. end;
  1244. end;
  1245. ltn,lten,gtn,gten,equaln,unequaln :
  1246. begin
  1247. emit_compare(unsigned);
  1248. end;
  1249. end;
  1250. end
  1251. else
  1252. // overflow checking is on and we have an addn, subn or muln
  1253. begin
  1254. if is_signed(resulttype.def) then
  1255. begin
  1256. case nodetype of
  1257. addn:
  1258. op := A_ADDO;
  1259. subn:
  1260. begin
  1261. op := A_SUBO;
  1262. if (nf_swaped in flags) then
  1263. swapleftright;
  1264. end;
  1265. muln:
  1266. op := A_MULLWO;
  1267. else
  1268. internalerror(2002072601);
  1269. end;
  1270. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,
  1271. left.location.register,right.location.register));
  1272. cg.g_overflowcheck(current_asmdata.CurrAsmList,location,resulttype.def);
  1273. end
  1274. else
  1275. begin
  1276. case nodetype of
  1277. addn:
  1278. begin
  1279. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_ADD,location.register,
  1280. left.location.register,right.location.register));
  1281. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMPLW,location.register,left.location.register));
  1282. cg.g_overflowcheck(current_asmdata.CurrAsmList,location,resulttype.def);
  1283. end;
  1284. subn:
  1285. begin
  1286. if nf_swaped in flags then
  1287. swapleftright;
  1288. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SUB,location.register,
  1289. left.location.register,right.location.register));
  1290. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMPLW,left.location.register,location.register));
  1291. cg.g_overflowcheck(current_asmdata.CurrAsmList,location,resulttype.def);
  1292. end;
  1293. muln:
  1294. begin
  1295. { calculate the upper 32 bits of the product, = 0 if no overflow }
  1296. cg.a_reg_alloc(current_asmdata.CurrAsmList,NR_R0);
  1297. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_MULHWU_,NR_R0,
  1298. left.location.register,right.location.register));
  1299. cg.a_reg_dealloc(current_asmdata.CurrAsmList,NR_R0);
  1300. { calculate the real result }
  1301. current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_MULLW,location.register,
  1302. left.location.register,right.location.register));
  1303. { g_overflowcheck generates a OC_AE instead of OC_EQ :/ }
  1304. current_asmdata.getjumplabel(hl);
  1305. tcgppc(cg).a_jmp_cond(current_asmdata.CurrAsmList,OC_EQ,hl);
  1306. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_OVERFLOW');
  1307. cg.a_label(current_asmdata.CurrAsmList,hl);
  1308. end;
  1309. end;
  1310. end;
  1311. end;
  1312. end;
  1313. begin
  1314. caddnode:=tppcaddnode;
  1315. end.