nx86add.pas 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841
  1. {
  2. $Id$
  3. Copyright (c) 2000-2002 by Florian Klaempfl
  4. Common code generation for add nodes on the i386 and x86
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. {
  19. Common code generation for add nodes on the i386 and x86
  20. }
  21. unit nx86add;
  22. {$i fpcdefs.inc}
  23. interface
  24. uses
  25. cgbase,
  26. cpubase,
  27. node,nadd,ncgadd;
  28. type
  29. tx86addnode = class(tcgaddnode)
  30. function getresflags(unsigned : boolean) : tresflags;
  31. procedure set_result_location(cmpop,unsigned:boolean);
  32. procedure left_must_be_reg(opsize:TCGSize;noswap:boolean);
  33. procedure emit_op_right_left(op:TAsmOp;opsize:TOpSize);
  34. procedure emit_generic_code(op:TAsmOp;opsize:TCgSize;unsigned,extra_not,mboverflow:boolean);
  35. function first_addstring : tnode; override;
  36. procedure pass_2;override;
  37. procedure second_addfloat;override;
  38. procedure second_addfloatsse;
  39. procedure second_addstring;
  40. procedure second_mul;virtual;abstract;
  41. procedure pass_left_and_right(var pushedfpu:boolean);
  42. end;
  43. implementation
  44. uses
  45. globtype,globals,
  46. verbose,
  47. cutils,
  48. aasmbase,aasmtai,aasmcpu,
  49. cpuinfo,
  50. symconst,symdef,
  51. cgobj,cgx86,cga,
  52. paramgr,
  53. htypechk,
  54. pass_2,ncgutil,
  55. ncon,
  56. defutil;
  57. {*****************************************************************************
  58. Helpers
  59. *****************************************************************************}
  60. procedure tx86addnode.emit_generic_code(op:TAsmOp;opsize:TCGSize;unsigned,extra_not,mboverflow:boolean);
  61. var
  62. power : longint;
  63. hl4 : tasmlabel;
  64. r : Tregister;
  65. begin
  66. { at this point, left.location.loc should be LOC_REGISTER }
  67. if right.location.loc=LOC_REGISTER then
  68. begin
  69. { right.location is a LOC_REGISTER }
  70. { when swapped another result register }
  71. if (nodetype=subn) and (nf_swaped in flags) then
  72. begin
  73. if extra_not then
  74. emit_reg(A_NOT,TCGSize2Opsize[opsize],left.location.register);
  75. emit_reg_reg(op,TCGSize2Opsize[opsize],left.location.register,right.location.register);
  76. { newly swapped also set swapped flag }
  77. location_swap(left.location,right.location);
  78. toggleflag(nf_swaped);
  79. end
  80. else
  81. begin
  82. if extra_not then
  83. emit_reg(A_NOT,TCGSize2Opsize[opsize],right.location.register);
  84. if (op=A_ADD) or (op=A_OR) or (op=A_AND) or (op=A_XOR) or (op=A_IMUL) then
  85. location_swap(left.location,right.location);
  86. emit_reg_reg(op,TCGSize2Opsize[opsize],right.location.register,left.location.register);
  87. end;
  88. end
  89. else
  90. begin
  91. { right.location is not a LOC_REGISTER }
  92. if (nodetype=subn) and (nf_swaped in flags) then
  93. begin
  94. if extra_not then
  95. emit_reg(A_NOT,TCGSize2Opsize[opsize],left.location.register);
  96. r:=cg.getintregister(exprasmlist,OS_INT);
  97. cg.a_load_loc_reg(exprasmlist,OS_INT,right.location,r);
  98. emit_reg_reg(op,TCGSize2Opsize[opsize],left.location.register,r);
  99. emit_reg_reg(A_MOV,TCGSize2Opsize[opsize],r,left.location.register);
  100. cg.ungetregister(exprasmlist,r);
  101. end
  102. else
  103. begin
  104. { Optimizations when right.location is a constant value }
  105. if (op=A_CMP) and
  106. (nodetype in [equaln,unequaln]) and
  107. (right.location.loc=LOC_CONSTANT) and
  108. (right.location.value=0) then
  109. begin
  110. emit_reg_reg(A_TEST,TCGSize2Opsize[opsize],left.location.register,left.location.register);
  111. end
  112. else
  113. if (op=A_ADD) and
  114. (right.location.loc=LOC_CONSTANT) and
  115. (right.location.value=1) and
  116. not(cs_check_overflow in aktlocalswitches) then
  117. begin
  118. emit_reg(A_INC,TCGSize2Opsize[opsize],left.location.register);
  119. end
  120. else
  121. if (op=A_SUB) and
  122. (right.location.loc=LOC_CONSTANT) and
  123. (right.location.value=1) and
  124. not(cs_check_overflow in aktlocalswitches) then
  125. begin
  126. emit_reg(A_DEC,TCGSize2Opsize[opsize],left.location.register);
  127. end
  128. else
  129. if (op=A_IMUL) and
  130. (right.location.loc=LOC_CONSTANT) and
  131. (ispowerof2(right.location.value,power)) and
  132. not(cs_check_overflow in aktlocalswitches) then
  133. begin
  134. emit_const_reg(A_SHL,TCGSize2Opsize[opsize],power,left.location.register);
  135. end
  136. else
  137. begin
  138. if extra_not then
  139. begin
  140. r:=cg.getintregister(exprasmlist,OS_INT);
  141. cg.a_load_loc_reg(exprasmlist,OS_INT,right.location,r);
  142. emit_reg(A_NOT,TCGSize2Opsize[opsize],r);
  143. emit_reg_reg(A_AND,TCGSize2Opsize[opsize],r,left.location.register);
  144. cg.ungetregister(exprasmlist,r);
  145. end
  146. else
  147. begin
  148. emit_op_right_left(op,TCGSize2Opsize[opsize]);
  149. end;
  150. end;
  151. end;
  152. end;
  153. { only in case of overflow operations }
  154. { produce overflow code }
  155. { we must put it here directly, because sign of operation }
  156. { is in unsigned VAR!! }
  157. if mboverflow then
  158. begin
  159. if cs_check_overflow in aktlocalswitches then
  160. begin
  161. objectlibrary.getlabel(hl4);
  162. if unsigned then
  163. cg.a_jmp_flags(exprasmlist,F_AE,hl4)
  164. else
  165. cg.a_jmp_flags(exprasmlist,F_NO,hl4);
  166. cg.a_call_name(exprasmlist,'FPC_OVERFLOW');
  167. cg.a_label(exprasmlist,hl4);
  168. end;
  169. end;
  170. end;
  171. procedure tx86addnode.left_must_be_reg(opsize:TCGSize;noswap:boolean);
  172. begin
  173. { left location is not a register? }
  174. if (left.location.loc<>LOC_REGISTER) then
  175. begin
  176. { if right is register then we can swap the locations }
  177. if (not noswap) and
  178. (right.location.loc=LOC_REGISTER) then
  179. begin
  180. location_swap(left.location,right.location);
  181. toggleflag(nf_swaped);
  182. end
  183. else
  184. begin
  185. { maybe we can reuse a constant register when the
  186. operation is a comparison that doesn't change the
  187. value of the register }
  188. location_force_reg(exprasmlist,left.location,opsize,(nodetype in [ltn,lten,gtn,gten,equaln,unequaln]));
  189. end;
  190. end;
  191. end;
  192. procedure tx86addnode.emit_op_right_left(op:TAsmOp;opsize:TOpsize);
  193. begin
  194. { left must be a register }
  195. case right.location.loc of
  196. LOC_REGISTER,
  197. LOC_CREGISTER :
  198. exprasmlist.concat(taicpu.op_reg_reg(op,opsize,right.location.register,left.location.register));
  199. LOC_REFERENCE,
  200. LOC_CREFERENCE :
  201. exprasmlist.concat(taicpu.op_ref_reg(op,opsize,right.location.reference,left.location.register));
  202. LOC_CONSTANT :
  203. exprasmlist.concat(taicpu.op_const_reg(op,opsize,right.location.value,left.location.register));
  204. else
  205. internalerror(200203232);
  206. end;
  207. end;
  208. procedure tx86addnode.set_result_location(cmpop,unsigned:boolean);
  209. begin
  210. if cmpop then
  211. begin
  212. location_reset(location,LOC_FLAGS,OS_NO);
  213. location.resflags:=getresflags(unsigned);
  214. end
  215. else
  216. location_copy(location,left.location);
  217. end;
  218. function tx86addnode.getresflags(unsigned : boolean) : tresflags;
  219. begin
  220. case nodetype of
  221. equaln : getresflags:=F_E;
  222. unequaln : getresflags:=F_NE;
  223. else
  224. if not(unsigned) then
  225. begin
  226. if nf_swaped in flags then
  227. case nodetype of
  228. ltn : getresflags:=F_G;
  229. lten : getresflags:=F_GE;
  230. gtn : getresflags:=F_L;
  231. gten : getresflags:=F_LE;
  232. end
  233. else
  234. case nodetype of
  235. ltn : getresflags:=F_L;
  236. lten : getresflags:=F_LE;
  237. gtn : getresflags:=F_G;
  238. gten : getresflags:=F_GE;
  239. end;
  240. end
  241. else
  242. begin
  243. if nf_swaped in flags then
  244. case nodetype of
  245. ltn : getresflags:=F_A;
  246. lten : getresflags:=F_AE;
  247. gtn : getresflags:=F_B;
  248. gten : getresflags:=F_BE;
  249. end
  250. else
  251. case nodetype of
  252. ltn : getresflags:=F_B;
  253. lten : getresflags:=F_BE;
  254. gtn : getresflags:=F_A;
  255. gten : getresflags:=F_AE;
  256. end;
  257. end;
  258. end;
  259. end;
  260. {*****************************************************************************
  261. AddFloat
  262. *****************************************************************************}
  263. procedure tx86addnode.pass_left_and_right(var pushedfpu:boolean);
  264. begin
  265. { calculate the operator which is more difficult }
  266. firstcomplex(self);
  267. { in case of constant put it to the left }
  268. if (left.nodetype=ordconstn) then
  269. swapleftright;
  270. secondpass(left);
  271. { are too few registers free? }
  272. if location.loc=LOC_FPUREGISTER then
  273. pushedfpu:=maybe_pushfpu(exprasmlist,right.registersfpu,left.location)
  274. else
  275. pushedfpu:=false;
  276. secondpass(right);
  277. end;
  278. procedure tx86addnode.second_addfloat;
  279. var
  280. op : TAsmOp;
  281. resflags : tresflags;
  282. pushedfpu,
  283. cmpop : boolean;
  284. begin
  285. if use_sse(resulttype.def) then
  286. begin
  287. second_addfloatsse;
  288. exit;
  289. end;
  290. pass_left_and_right(pushedfpu);
  291. cmpop:=false;
  292. case nodetype of
  293. addn :
  294. op:=A_FADDP;
  295. muln :
  296. op:=A_FMULP;
  297. subn :
  298. op:=A_FSUBP;
  299. slashn :
  300. op:=A_FDIVP;
  301. ltn,lten,gtn,gten,
  302. equaln,unequaln :
  303. begin
  304. op:=A_FCOMPP;
  305. cmpop:=true;
  306. end;
  307. else
  308. internalerror(2003042214);
  309. end;
  310. if (right.location.loc<>LOC_FPUREGISTER) then
  311. begin
  312. cg.a_loadfpu_loc_reg(exprasmlist,right.location,NR_ST);
  313. if (right.location.loc <> LOC_CFPUREGISTER) and
  314. pushedfpu then
  315. location_freetemp(exprasmlist,left.location);
  316. if (left.location.loc<>LOC_FPUREGISTER) then
  317. begin
  318. cg.a_loadfpu_loc_reg(exprasmlist,left.location,NR_ST);
  319. if (left.location.loc <> LOC_CFPUREGISTER) and
  320. pushedfpu then
  321. location_freetemp(exprasmlist,left.location);
  322. end
  323. else
  324. begin
  325. { left was on the stack => swap }
  326. toggleflag(nf_swaped);
  327. end;
  328. { releases the right reference }
  329. location_release(exprasmlist,right.location);
  330. end
  331. { the nominator in st0 }
  332. else if (left.location.loc<>LOC_FPUREGISTER) then
  333. begin
  334. cg.a_loadfpu_loc_reg(exprasmlist,left.location,NR_ST);
  335. if (left.location.loc <> LOC_CFPUREGISTER) and
  336. pushedfpu then
  337. location_freetemp(exprasmlist,left.location);
  338. end
  339. else
  340. begin
  341. { fpu operands are always in the wrong order on the stack }
  342. toggleflag(nf_swaped);
  343. end;
  344. { releases the left reference }
  345. if (left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  346. location_release(exprasmlist,left.location);
  347. { if we swaped the tree nodes, then use the reverse operator }
  348. if nf_swaped in flags then
  349. begin
  350. if (nodetype=slashn) then
  351. op:=A_FDIVRP
  352. else if (nodetype=subn) then
  353. op:=A_FSUBRP;
  354. end;
  355. { to avoid the pentium bug
  356. if (op=FDIVP) and (opt_processors=pentium) then
  357. cg.a_call_name(exprasmlist,'EMUL_FDIVP')
  358. else
  359. }
  360. { the Intel assemblers want operands }
  361. if op<>A_FCOMPP then
  362. begin
  363. emit_reg_reg(op,S_NO,NR_ST,NR_ST1);
  364. tcgx86(cg).dec_fpu_stack;
  365. end
  366. else
  367. begin
  368. emit_none(op,S_NO);
  369. tcgx86(cg).dec_fpu_stack;
  370. tcgx86(cg).dec_fpu_stack;
  371. end;
  372. { on comparison load flags }
  373. if cmpop then
  374. begin
  375. cg.getexplicitregister(exprasmlist,NR_AX);
  376. emit_reg(A_FNSTSW,S_NO,NR_AX);
  377. emit_none(A_SAHF,S_NO);
  378. cg.ungetregister(exprasmlist,NR_AX);
  379. if nf_swaped in flags then
  380. begin
  381. case nodetype of
  382. equaln : resflags:=F_E;
  383. unequaln : resflags:=F_NE;
  384. ltn : resflags:=F_A;
  385. lten : resflags:=F_AE;
  386. gtn : resflags:=F_B;
  387. gten : resflags:=F_BE;
  388. end;
  389. end
  390. else
  391. begin
  392. case nodetype of
  393. equaln : resflags:=F_E;
  394. unequaln : resflags:=F_NE;
  395. ltn : resflags:=F_B;
  396. lten : resflags:=F_BE;
  397. gtn : resflags:=F_A;
  398. gten : resflags:=F_AE;
  399. end;
  400. end;
  401. location_reset(location,LOC_FLAGS,OS_NO);
  402. location.resflags:=resflags;
  403. end
  404. else
  405. begin
  406. location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
  407. location.register:=NR_ST;
  408. end;
  409. end;
  410. procedure tx86addnode.second_addfloatsse;
  411. var
  412. op : topcg;
  413. begin
  414. pass_left_right;
  415. if (nf_swaped in flags) then
  416. swapleftright;
  417. case nodetype of
  418. addn :
  419. op:=OP_ADD;
  420. muln :
  421. op:=OP_MUL;
  422. subn :
  423. op:=OP_SUB;
  424. slashn :
  425. op:=OP_DIV;
  426. else
  427. internalerror(200312231);
  428. end;
  429. location_reset(location,LOC_MMREGISTER,def_cgsize(resulttype.def));
  430. { we can use only right as left operand if the operation is commutative }
  431. if (right.location.loc=LOC_MMREGISTER) and (op in [OP_ADD,OP_MUL]) then
  432. begin
  433. location.register:=right.location.register;
  434. { force floating point reg. location to be written to memory,
  435. we don't force it to mm register because writing to memory
  436. allows probably shorter code because there is no direct fpu->mm register
  437. copy instruction
  438. }
  439. if left.location.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER] then
  440. location_force_mem(exprasmlist,left.location);
  441. cg.a_opmm_loc_reg(exprasmlist,op,location.size,left.location,location.register,mms_movescalar);
  442. location_release(exprasmlist,left.location);
  443. end
  444. else
  445. begin
  446. location_force_mmregscalar(exprasmlist,left.location,false);
  447. location.register:=left.location.register;
  448. { force floating point reg. location to be written to memory,
  449. we don't force it to mm register because writing to memory
  450. allows probably shorter code because there is no direct fpu->mm register
  451. copy instruction
  452. }
  453. if right.location.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER] then
  454. location_force_mem(exprasmlist,right.location);
  455. cg.a_opmm_loc_reg(exprasmlist,op,location.size,right.location,location.register,mms_movescalar);
  456. location_release(exprasmlist,right.location);
  457. end;
  458. end;
  459. {*****************************************************************************
  460. Addstring
  461. *****************************************************************************}
  462. { note: if you implemented an fpc_shortstr_concat similar to the }
  463. { one in i386.inc, you have to override first_addstring like in }
  464. { ti386addnode.first_string and implement the shortstring concat }
  465. { manually! The generic routine is different from the i386 one (JM) }
  466. function tx86addnode.first_addstring : tnode;
  467. begin
  468. { special cases for shortstrings, handled in pass_2 (JM) }
  469. { can't handle fpc_shortstr_compare with compilerproc either because it }
  470. { returns its results in the flags instead of in eax }
  471. if (nodetype in [ltn,lten,gtn,gten,equaln,unequaln]) and
  472. is_shortstring(left.resulttype.def) and
  473. not(((left.nodetype=stringconstn) and (str_length(left)=0)) or
  474. ((right.nodetype=stringconstn) and (str_length(right)=0))) then
  475. begin
  476. expectloc:=LOC_FLAGS;
  477. calcregisters(self,0,0,0);
  478. result := nil;
  479. exit;
  480. end;
  481. { otherwise, use the generic code }
  482. result := inherited first_addstring;
  483. end;
  484. procedure tx86addnode.second_addstring;
  485. var
  486. paraloc1,
  487. paraloc2 : tparalocation;
  488. hregister1,
  489. hregister2 : tregister;
  490. begin
  491. { string operations are not commutative }
  492. if nf_swaped in flags then
  493. swapleftright;
  494. case tstringdef(left.resulttype.def).string_typ of
  495. st_shortstring:
  496. begin
  497. case nodetype of
  498. ltn,lten,gtn,gten,equaln,unequaln :
  499. begin
  500. paraloc1:=paramanager.getintparaloc(pocall_default,1);
  501. paraloc2:=paramanager.getintparaloc(pocall_default,2);
  502. { process parameters }
  503. secondpass(left);
  504. location_release(exprasmlist,left.location);
  505. if paraloc2.loc=LOC_REGISTER then
  506. begin
  507. hregister2:=cg.getaddressregister(exprasmlist);
  508. cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,hregister2);
  509. end
  510. else
  511. begin
  512. paramanager.allocparaloc(exprasmlist,paraloc2);
  513. cg.a_paramaddr_ref(exprasmlist,left.location.reference,paraloc2);
  514. end;
  515. secondpass(right);
  516. location_release(exprasmlist,right.location);
  517. if paraloc1.loc=LOC_REGISTER then
  518. begin
  519. hregister1:=cg.getaddressregister(exprasmlist);
  520. cg.a_loadaddr_ref_reg(exprasmlist,right.location.reference,hregister1);
  521. end
  522. else
  523. begin
  524. paramanager.allocparaloc(exprasmlist,paraloc1);
  525. cg.a_paramaddr_ref(exprasmlist,right.location.reference,paraloc1);
  526. end;
  527. { push parameters }
  528. if paraloc1.loc=LOC_REGISTER then
  529. begin
  530. cg.ungetregister(exprasmlist,hregister2);
  531. paramanager.allocparaloc(exprasmlist,paraloc2);
  532. cg.a_param_reg(exprasmlist,OS_ADDR,hregister2,paraloc2);
  533. end;
  534. if paraloc2.loc=LOC_REGISTER then
  535. begin
  536. cg.ungetregister(exprasmlist,hregister1);
  537. paramanager.allocparaloc(exprasmlist,paraloc1);
  538. cg.a_param_reg(exprasmlist,OS_ADDR,hregister1,paraloc1);
  539. end;
  540. paramanager.freeparaloc(exprasmlist,paraloc1);
  541. paramanager.freeparaloc(exprasmlist,paraloc2);
  542. cg.allocexplicitregisters(exprasmlist,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  543. cg.a_call_name(exprasmlist,'FPC_SHORTSTR_COMPARE');
  544. cg.deallocexplicitregisters(exprasmlist,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  545. location_freetemp(exprasmlist,left.location);
  546. location_freetemp(exprasmlist,right.location);
  547. end;
  548. end;
  549. set_result_location(true,true);
  550. end;
  551. else
  552. { rest should be handled in first pass (JM) }
  553. internalerror(200108303);
  554. end;
  555. end;
  556. {*****************************************************************************
  557. pass_2
  558. *****************************************************************************}
  559. procedure tx86addnode.pass_2;
  560. { is also being used for xor, and "mul", "sub, or and comparative }
  561. { operators }
  562. var
  563. pushedfpu,
  564. mboverflow,cmpop : boolean;
  565. op : tasmop;
  566. opsize : tcgsize;
  567. { true, if unsigned types are compared }
  568. unsigned : boolean;
  569. { is_in_dest if the result is put directly into }
  570. { the resulting refernce or varregister }
  571. {is_in_dest : boolean;}
  572. { true, if for sets subtractions the extra not should generated }
  573. extra_not : boolean;
  574. begin
  575. { to make it more readable, string and set have their own procedures }
  576. case left.resulttype.def.deftype of
  577. orddef :
  578. begin
  579. { handling boolean expressions }
  580. if is_boolean(left.resulttype.def) and
  581. is_boolean(right.resulttype.def) then
  582. begin
  583. second_addboolean;
  584. exit;
  585. end
  586. {$ifndef x86_64}
  587. { 64bit operations }
  588. else if is_64bit(left.resulttype.def) then
  589. begin
  590. second_add64bit;
  591. exit;
  592. end
  593. {$endif x86_64}
  594. ;
  595. end;
  596. stringdef :
  597. begin
  598. second_addstring;
  599. exit;
  600. end;
  601. setdef :
  602. begin
  603. {Normalsets are already handled in pass1 if mmx
  604. should not be used.}
  605. if (tsetdef(left.resulttype.def).settype<>smallset) then
  606. begin
  607. {$ifdef MMXSET}
  608. if cs_mmx in aktlocalswitches then
  609. second_addmmxset
  610. else
  611. {$endif MMXSET}
  612. internalerror(200109041);
  613. end
  614. else
  615. second_addsmallset;
  616. exit;
  617. end;
  618. arraydef :
  619. begin
  620. {$ifdef SUPPORT_MMX}
  621. if is_mmx_able_array(left.resulttype.def) then
  622. begin
  623. second_addmmx;
  624. exit;
  625. end;
  626. {$endif SUPPORT_MMX}
  627. end;
  628. floatdef :
  629. begin
  630. second_addfloat;
  631. exit;
  632. end;
  633. end;
  634. { defaults }
  635. {is_in_dest:=false;}
  636. extra_not:=false;
  637. mboverflow:=false;
  638. cmpop:=false;
  639. unsigned:=not(is_signed(left.resulttype.def)) or
  640. not(is_signed(right.resulttype.def));
  641. opsize:=def_cgsize(left.resulttype.def);
  642. pass_left_and_right(pushedfpu);
  643. if (left.resulttype.def.deftype=pointerdef) or
  644. (right.resulttype.def.deftype=pointerdef) or
  645. (is_class_or_interface(right.resulttype.def) and is_class_or_interface(left.resulttype.def)) or
  646. (left.resulttype.def.deftype=classrefdef) or
  647. (left.resulttype.def.deftype=procvardef) or
  648. {$ifdef x86_64}
  649. ((left.resulttype.def.deftype=enumdef) and
  650. (left.resulttype.def.size in [4,8])) or
  651. ((left.resulttype.def.deftype=orddef) and
  652. (torddef(left.resulttype.def).typ in [s32bit,u32bit,s64bit,u64bit])) or
  653. ((right.resulttype.def.deftype=orddef) and
  654. (torddef(right.resulttype.def).typ in [s32bit,u32bit,s64bit,u64bit])) then
  655. {$else x86_64}
  656. ((left.resulttype.def.deftype=enumdef) and
  657. (left.resulttype.def.size=4)) or
  658. ((left.resulttype.def.deftype=orddef) and
  659. (torddef(left.resulttype.def).typ in [s32bit,u32bit])) or
  660. ((right.resulttype.def.deftype=orddef) and
  661. (torddef(right.resulttype.def).typ in [s32bit,u32bit])) then
  662. {$endif x86_64}
  663. begin
  664. case nodetype of
  665. addn :
  666. begin
  667. op:=A_ADD;
  668. mboverflow:=true;
  669. end;
  670. muln :
  671. begin
  672. if unsigned then
  673. op:=A_MUL
  674. else
  675. op:=A_IMUL;
  676. mboverflow:=true;
  677. end;
  678. subn :
  679. begin
  680. op:=A_SUB;
  681. mboverflow:=true;
  682. end;
  683. ltn,lten,
  684. gtn,gten,
  685. equaln,unequaln :
  686. begin
  687. op:=A_CMP;
  688. cmpop:=true;
  689. end;
  690. xorn :
  691. op:=A_XOR;
  692. orn :
  693. op:=A_OR;
  694. andn :
  695. op:=A_AND;
  696. else
  697. internalerror(200304229);
  698. end;
  699. { filter MUL, which requires special handling }
  700. if op=A_MUL then
  701. begin
  702. second_mul;
  703. exit;
  704. end;
  705. { Convert flags to register first }
  706. if (left.location.loc=LOC_FLAGS) then
  707. location_force_reg(exprasmlist,left.location,opsize,false);
  708. if (right.location.loc=LOC_FLAGS) then
  709. location_force_reg(exprasmlist,right.location,opsize,false);
  710. left_must_be_reg(opsize,false);
  711. emit_generic_code(op,opsize,unsigned,extra_not,mboverflow);
  712. location_freetemp(exprasmlist,right.location);
  713. location_release(exprasmlist,right.location);
  714. if cmpop and
  715. (left.location.loc<>LOC_CREGISTER) then
  716. begin
  717. location_freetemp(exprasmlist,left.location);
  718. location_release(exprasmlist,left.location);
  719. end;
  720. set_result_location(cmpop,unsigned);
  721. end
  722. { 8/16 bit enum,char,wchar types }
  723. else
  724. if ((left.resulttype.def.deftype=orddef) and
  725. (torddef(left.resulttype.def).typ in [uchar,uwidechar])) or
  726. ((left.resulttype.def.deftype=enumdef) and
  727. ((left.resulttype.def.size=1) or
  728. (left.resulttype.def.size=2))) then
  729. begin
  730. case nodetype of
  731. ltn,lten,gtn,gten,
  732. equaln,unequaln :
  733. cmpop:=true;
  734. else
  735. internalerror(2003042210);
  736. end;
  737. left_must_be_reg(opsize,false);
  738. emit_op_right_left(A_CMP,TCGSize2Opsize[opsize]);
  739. location_freetemp(exprasmlist,right.location);
  740. location_release(exprasmlist,right.location);
  741. if left.location.loc<>LOC_CREGISTER then
  742. begin
  743. location_freetemp(exprasmlist,left.location);
  744. location_release(exprasmlist,left.location);
  745. end;
  746. set_result_location(true,true);
  747. end
  748. else
  749. internalerror(2003042211);
  750. end;
  751. begin
  752. caddnode:=tx86addnode;
  753. end.
  754. {
  755. $Log$
  756. Revision 1.6 2004-01-20 12:59:37 florian
  757. * common addnode code for x86-64 and i386
  758. Revision 1.5 2003/12/26 13:19:16 florian
  759. * rtl and compiler compile with -Cfsse2
  760. Revision 1.4 2003/12/26 00:32:22 florian
  761. + fpu<->mm register conversion
  762. Revision 1.3 2003/12/25 01:07:09 florian
  763. + $fputype directive support
  764. + single data type operations with sse unit
  765. * fixed more x86-64 stuff
  766. Revision 1.2 2003/12/23 14:38:07 florian
  767. + second_floataddsse implemented
  768. Revision 1.1 2003/10/13 01:58:04 florian
  769. * some ideas for mm support implemented
  770. }