nx86add.pas 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  1. {
  2. Copyright (c) 2000-2002 by Florian Klaempfl
  3. Common code generation for add nodes on the i386 and x86
  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 nx86add;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. cgbase,
  22. cpubase,
  23. node,nadd,ncgadd;
  24. type
  25. tx86addnode = class(tcgaddnode)
  26. protected
  27. function getresflags(unsigned : boolean) : tresflags;
  28. procedure left_must_be_reg(opsize:TCGSize;noswap:boolean);
  29. procedure left_and_right_must_be_fpureg;
  30. procedure emit_op_right_left(op:TAsmOp;opsize:TCgSize);
  31. procedure emit_generic_code(op:TAsmOp;opsize:TCgSize;unsigned,extra_not,mboverflow:boolean);
  32. procedure second_cmpfloatsse;
  33. procedure second_addfloatsse;
  34. procedure second_mul;virtual;abstract;
  35. public
  36. procedure second_addfloat;override;
  37. procedure second_addsmallset;override;
  38. procedure second_add64bit;override;
  39. procedure second_addordinal;override;
  40. procedure second_cmpfloat;override;
  41. procedure second_cmpsmallset;override;
  42. procedure second_cmp64bit;override;
  43. procedure second_cmpordinal;override;
  44. end;
  45. implementation
  46. uses
  47. globtype,globals,
  48. verbose,cutils,
  49. cpuinfo,
  50. aasmbase,aasmtai,aasmcpu,
  51. symconst,symdef,
  52. cgobj,cgx86,cga,cgutils,
  53. paramgr,tgobj,ncgutil,
  54. ncon,nset,
  55. defutil;
  56. {*****************************************************************************
  57. Helpers
  58. *****************************************************************************}
  59. procedure tx86addnode.emit_generic_code(op:TAsmOp;opsize:TCGSize;unsigned,extra_not,mboverflow:boolean);
  60. var
  61. power : longint;
  62. hl4 : tasmlabel;
  63. r : Tregister;
  64. begin
  65. { at this point, left.location.loc should be LOC_REGISTER }
  66. if right.location.loc=LOC_REGISTER then
  67. begin
  68. { right.location is a LOC_REGISTER }
  69. { when swapped another result register }
  70. if (nodetype=subn) and (nf_swaped in flags) then
  71. begin
  72. if extra_not then
  73. emit_reg(A_NOT,TCGSize2Opsize[opsize],left.location.register);
  74. emit_reg_reg(op,TCGSize2Opsize[opsize],left.location.register,right.location.register);
  75. { newly swapped also set swapped flag }
  76. location_swap(left.location,right.location);
  77. toggleflag(nf_swaped);
  78. end
  79. else
  80. begin
  81. if extra_not then
  82. emit_reg(A_NOT,TCGSize2Opsize[opsize],right.location.register);
  83. if (op=A_ADD) or (op=A_OR) or (op=A_AND) or (op=A_XOR) or (op=A_IMUL) then
  84. location_swap(left.location,right.location);
  85. emit_reg_reg(op,TCGSize2Opsize[opsize],right.location.register,left.location.register);
  86. end;
  87. end
  88. else
  89. begin
  90. { right.location is not a LOC_REGISTER }
  91. if (nodetype=subn) and (nf_swaped in flags) then
  92. begin
  93. if extra_not then
  94. cg.a_op_reg_reg(exprasmlist,OP_NOT,opsize,left.location.register,left.location.register);
  95. r:=cg.getintregister(exprasmlist,opsize);
  96. cg.a_load_loc_reg(exprasmlist,opsize,right.location,r);
  97. emit_reg_reg(op,TCGSize2Opsize[opsize],left.location.register,r);
  98. cg.a_load_reg_reg(exprasmlist,opsize,opsize,r,left.location.register);
  99. end
  100. else
  101. begin
  102. { Optimizations when right.location is a constant value }
  103. if (op=A_CMP) and
  104. (nodetype in [equaln,unequaln]) and
  105. (right.location.loc=LOC_CONSTANT) and
  106. (right.location.value=0) then
  107. begin
  108. emit_reg_reg(A_TEST,TCGSize2Opsize[opsize],left.location.register,left.location.register);
  109. end
  110. else
  111. if (op=A_ADD) and
  112. (right.location.loc=LOC_CONSTANT) and
  113. (right.location.value=1) and
  114. not(cs_check_overflow in aktlocalswitches) then
  115. begin
  116. emit_reg(A_INC,TCGSize2Opsize[opsize],left.location.register);
  117. end
  118. else
  119. if (op=A_SUB) and
  120. (right.location.loc=LOC_CONSTANT) and
  121. (right.location.value=1) and
  122. not(cs_check_overflow in aktlocalswitches) then
  123. begin
  124. emit_reg(A_DEC,TCGSize2Opsize[opsize],left.location.register);
  125. end
  126. else
  127. if (op=A_IMUL) and
  128. (right.location.loc=LOC_CONSTANT) and
  129. (ispowerof2(int64(right.location.value),power)) and
  130. not(cs_check_overflow in aktlocalswitches) then
  131. begin
  132. emit_const_reg(A_SHL,TCGSize2Opsize[opsize],power,left.location.register);
  133. end
  134. else
  135. begin
  136. if extra_not then
  137. begin
  138. r:=cg.getintregister(exprasmlist,opsize);
  139. cg.a_load_loc_reg(exprasmlist,opsize,right.location,r);
  140. emit_reg(A_NOT,TCGSize2Opsize[opsize],r);
  141. emit_reg_reg(A_AND,TCGSize2Opsize[opsize],r,left.location.register);
  142. end
  143. else
  144. begin
  145. emit_op_right_left(op,opsize);
  146. end;
  147. end;
  148. end;
  149. end;
  150. { only in case of overflow operations }
  151. { produce overflow code }
  152. { we must put it here directly, because sign of operation }
  153. { is in unsigned VAR!! }
  154. if mboverflow then
  155. begin
  156. if cs_check_overflow in aktlocalswitches then
  157. begin
  158. objectlibrary.getlabel(hl4);
  159. if unsigned then
  160. cg.a_jmp_flags(exprasmlist,F_AE,hl4)
  161. else
  162. cg.a_jmp_flags(exprasmlist,F_NO,hl4);
  163. cg.a_call_name(exprasmlist,'FPC_OVERFLOW');
  164. cg.a_label(exprasmlist,hl4);
  165. end;
  166. end;
  167. end;
  168. procedure tx86addnode.left_must_be_reg(opsize:TCGSize;noswap:boolean);
  169. begin
  170. { left location is not a register? }
  171. if (left.location.loc<>LOC_REGISTER) then
  172. begin
  173. { if right is register then we can swap the locations }
  174. if (not noswap) and
  175. (right.location.loc=LOC_REGISTER) then
  176. begin
  177. location_swap(left.location,right.location);
  178. toggleflag(nf_swaped);
  179. end
  180. else
  181. begin
  182. { maybe we can reuse a constant register when the
  183. operation is a comparison that doesn't change the
  184. value of the register }
  185. location_force_reg(exprasmlist,left.location,opsize,(nodetype in [ltn,lten,gtn,gten,equaln,unequaln]));
  186. end;
  187. end;
  188. end;
  189. procedure tx86addnode.left_and_right_must_be_fpureg;
  190. begin
  191. if (right.location.loc<>LOC_FPUREGISTER) then
  192. begin
  193. cg.a_loadfpu_loc_reg(exprasmlist,right.location,NR_ST);
  194. if (right.location.loc <> LOC_CFPUREGISTER) then
  195. location_freetemp(exprasmlist,left.location);
  196. if (left.location.loc<>LOC_FPUREGISTER) then
  197. begin
  198. cg.a_loadfpu_loc_reg(exprasmlist,left.location,NR_ST);
  199. if (left.location.loc <> LOC_CFPUREGISTER) then
  200. location_freetemp(exprasmlist,left.location);
  201. end
  202. else
  203. begin
  204. { left was on the stack => swap }
  205. toggleflag(nf_swaped);
  206. end;
  207. end
  208. { the nominator in st0 }
  209. else if (left.location.loc<>LOC_FPUREGISTER) then
  210. begin
  211. cg.a_loadfpu_loc_reg(exprasmlist,left.location,NR_ST);
  212. if (left.location.loc <> LOC_CFPUREGISTER) then
  213. location_freetemp(exprasmlist,left.location);
  214. end
  215. else
  216. begin
  217. { fpu operands are always in the wrong order on the stack }
  218. toggleflag(nf_swaped);
  219. end;
  220. end;
  221. procedure tx86addnode.emit_op_right_left(op:TAsmOp;opsize:TCgsize);
  222. {$ifdef x86_64}
  223. var
  224. tmpreg : tregister;
  225. {$endif x86_64}
  226. begin
  227. { left must be a register }
  228. case right.location.loc of
  229. LOC_REGISTER,
  230. LOC_CREGISTER :
  231. exprasmlist.concat(taicpu.op_reg_reg(op,TCGSize2Opsize[opsize],right.location.register,left.location.register));
  232. LOC_REFERENCE,
  233. LOC_CREFERENCE :
  234. begin
  235. tcgx86(cg).make_simple_ref(exprasmlist,right.location.reference);
  236. exprasmlist.concat(taicpu.op_ref_reg(op,TCGSize2Opsize[opsize],right.location.reference,left.location.register));
  237. end;
  238. LOC_CONSTANT :
  239. begin
  240. {$ifdef x86_64}
  241. { x86_64 only supports signed 32 bits constants directly }
  242. if (opsize in [OS_S64,OS_64]) and
  243. ((right.location.value<low(longint)) or (right.location.value>high(longint))) then
  244. begin
  245. tmpreg:=cg.getintregister(exprasmlist,opsize);
  246. cg.a_load_const_reg(exprasmlist,opsize,right.location.value,tmpreg);
  247. exprasmlist.concat(taicpu.op_reg_reg(op,TCGSize2Opsize[opsize],tmpreg,left.location.register));
  248. end
  249. else
  250. {$endif x86_64}
  251. exprasmlist.concat(taicpu.op_const_reg(op,TCGSize2Opsize[opsize],right.location.value,left.location.register));
  252. end;
  253. else
  254. internalerror(200203232);
  255. end;
  256. end;
  257. function tx86addnode.getresflags(unsigned : boolean) : tresflags;
  258. begin
  259. case nodetype of
  260. equaln : getresflags:=F_E;
  261. unequaln : getresflags:=F_NE;
  262. else
  263. if not(unsigned) then
  264. begin
  265. if nf_swaped in flags then
  266. case nodetype of
  267. ltn : getresflags:=F_G;
  268. lten : getresflags:=F_GE;
  269. gtn : getresflags:=F_L;
  270. gten : getresflags:=F_LE;
  271. end
  272. else
  273. case nodetype of
  274. ltn : getresflags:=F_L;
  275. lten : getresflags:=F_LE;
  276. gtn : getresflags:=F_G;
  277. gten : getresflags:=F_GE;
  278. end;
  279. end
  280. else
  281. begin
  282. if nf_swaped in flags then
  283. case nodetype of
  284. ltn : getresflags:=F_A;
  285. lten : getresflags:=F_AE;
  286. gtn : getresflags:=F_B;
  287. gten : getresflags:=F_BE;
  288. end
  289. else
  290. case nodetype of
  291. ltn : getresflags:=F_B;
  292. lten : getresflags:=F_BE;
  293. gtn : getresflags:=F_A;
  294. gten : getresflags:=F_AE;
  295. end;
  296. end;
  297. end;
  298. end;
  299. {*****************************************************************************
  300. AddSmallSet
  301. *****************************************************************************}
  302. procedure tx86addnode.second_addsmallset;
  303. var
  304. opsize : TCGSize;
  305. op : TAsmOp;
  306. extra_not,
  307. noswap : boolean;
  308. begin
  309. pass_left_right;
  310. noswap:=false;
  311. extra_not:=false;
  312. opsize:=OS_32;
  313. case nodetype of
  314. addn :
  315. begin
  316. { this is a really ugly hack!!!!!!!!!! }
  317. { this could be done later using EDI }
  318. { as it is done for subn }
  319. { instead of two registers!!!! }
  320. { adding elements is not commutative }
  321. if (nf_swaped in flags) and (left.nodetype=setelementn) then
  322. swapleftright;
  323. { are we adding set elements ? }
  324. if right.nodetype=setelementn then
  325. begin
  326. { no range support for smallsets! }
  327. if assigned(tsetelementnode(right).right) then
  328. internalerror(43244);
  329. { bts requires both elements to be registers }
  330. location_force_reg(exprasmlist,left.location,opsize,false);
  331. location_force_reg(exprasmlist,right.location,opsize,true);
  332. op:=A_BTS;
  333. noswap:=true;
  334. end
  335. else
  336. op:=A_OR;
  337. end;
  338. symdifn :
  339. op:=A_XOR;
  340. muln :
  341. op:=A_AND;
  342. subn :
  343. begin
  344. op:=A_AND;
  345. if (not(nf_swaped in flags)) and
  346. (right.location.loc=LOC_CONSTANT) then
  347. right.location.value := not(right.location.value)
  348. else if (nf_swaped in flags) and
  349. (left.location.loc=LOC_CONSTANT) then
  350. left.location.value := not(left.location.value)
  351. else
  352. extra_not:=true;
  353. end;
  354. xorn :
  355. op:=A_XOR;
  356. orn :
  357. op:=A_OR;
  358. andn :
  359. op:=A_AND;
  360. else
  361. internalerror(2003042215);
  362. end;
  363. { left must be a register }
  364. left_must_be_reg(opsize,noswap);
  365. emit_generic_code(op,opsize,true,extra_not,false);
  366. location_freetemp(exprasmlist,right.location);
  367. set_result_location_reg;
  368. end;
  369. procedure tx86addnode.second_cmpsmallset;
  370. var
  371. opsize : TCGSize;
  372. op : TAsmOp;
  373. begin
  374. pass_left_right;
  375. opsize:=OS_32;
  376. case nodetype of
  377. equaln,
  378. unequaln :
  379. op:=A_CMP;
  380. lten,gten:
  381. begin
  382. if (not(nf_swaped in flags) and (nodetype = lten)) or
  383. ((nf_swaped in flags) and (nodetype = gten)) then
  384. swapleftright;
  385. location_force_reg(exprasmlist,left.location,opsize,true);
  386. emit_op_right_left(A_AND,opsize);
  387. op:=A_CMP;
  388. { warning: ugly hack, we need a JE so change the node to equaln }
  389. nodetype:=equaln;
  390. end;
  391. else
  392. internalerror(2003042215);
  393. end;
  394. { left must be a register }
  395. left_must_be_reg(opsize,false);
  396. emit_generic_code(op,opsize,true,false,false);
  397. location_freetemp(exprasmlist,right.location);
  398. location_freetemp(exprasmlist,left.location);
  399. location_reset(location,LOC_FLAGS,OS_NO);
  400. location.resflags:=getresflags(true);
  401. end;
  402. {*****************************************************************************
  403. AddFloat
  404. *****************************************************************************}
  405. procedure tx86addnode.second_addfloatsse;
  406. var
  407. op : topcg;
  408. begin
  409. pass_left_right;
  410. if (nf_swaped in flags) then
  411. swapleftright;
  412. case nodetype of
  413. addn :
  414. op:=OP_ADD;
  415. muln :
  416. op:=OP_MUL;
  417. subn :
  418. op:=OP_SUB;
  419. slashn :
  420. op:=OP_DIV;
  421. else
  422. internalerror(200312231);
  423. end;
  424. location_reset(location,LOC_MMREGISTER,def_cgsize(resulttype.def));
  425. { we can use only right as left operand if the operation is commutative }
  426. if (right.location.loc=LOC_MMREGISTER) and (op in [OP_ADD,OP_MUL]) then
  427. begin
  428. location.register:=right.location.register;
  429. { force floating point reg. location to be written to memory,
  430. we don't force it to mm register because writing to memory
  431. allows probably shorter code because there is no direct fpu->mm register
  432. copy instruction
  433. }
  434. if left.location.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER] then
  435. location_force_mem(exprasmlist,left.location);
  436. cg.a_opmm_loc_reg(exprasmlist,op,location.size,left.location,location.register,mms_movescalar);
  437. end
  438. else
  439. begin
  440. location_force_mmregscalar(exprasmlist,left.location,false);
  441. location.register:=left.location.register;
  442. { force floating point reg. location to be written to memory,
  443. we don't force it to mm register because writing to memory
  444. allows probably shorter code because there is no direct fpu->mm register
  445. copy instruction
  446. }
  447. if right.location.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER] then
  448. location_force_mem(exprasmlist,right.location);
  449. cg.a_opmm_loc_reg(exprasmlist,op,location.size,right.location,location.register,mms_movescalar);
  450. end;
  451. end;
  452. procedure tx86addnode.second_cmpfloatsse;
  453. var
  454. op : tasmop;
  455. begin
  456. if is_single(left.resulttype.def) then
  457. op:=A_COMISS
  458. else if is_double(left.resulttype.def) then
  459. op:=A_COMISD
  460. else
  461. internalerror(200402222);
  462. pass_left_right;
  463. location_reset(location,LOC_FLAGS,def_cgsize(resulttype.def));
  464. { we can use only right as left operand if the operation is commutative }
  465. if (right.location.loc=LOC_MMREGISTER) then
  466. begin
  467. { force floating point reg. location to be written to memory,
  468. we don't force it to mm register because writing to memory
  469. allows probably shorter code because there is no direct fpu->mm register
  470. copy instruction
  471. }
  472. if left.location.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER] then
  473. location_force_mem(exprasmlist,left.location);
  474. case left.location.loc of
  475. LOC_REFERENCE,LOC_CREFERENCE:
  476. begin
  477. tcgx86(cg).make_simple_ref(exprasmlist,left.location.reference);
  478. exprasmlist.concat(taicpu.op_ref_reg(op,S_NO,left.location.reference,right.location.register));
  479. end;
  480. LOC_MMREGISTER,LOC_CMMREGISTER:
  481. exprasmlist.concat(taicpu.op_reg_reg(op,S_NO,left.location.register,right.location.register));
  482. else
  483. internalerror(200402221);
  484. end;
  485. if nf_swaped in flags then
  486. exclude(flags,nf_swaped)
  487. else
  488. include(flags,nf_swaped)
  489. end
  490. else
  491. begin
  492. location_force_mmregscalar(exprasmlist,left.location,false);
  493. { force floating point reg. location to be written to memory,
  494. we don't force it to mm register because writing to memory
  495. allows probably shorter code because there is no direct fpu->mm register
  496. copy instruction
  497. }
  498. if right.location.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER] then
  499. location_force_mem(exprasmlist,right.location);
  500. case right.location.loc of
  501. LOC_REFERENCE,LOC_CREFERENCE:
  502. begin
  503. tcgx86(cg).make_simple_ref(exprasmlist,right.location.reference);
  504. exprasmlist.concat(taicpu.op_ref_reg(op,S_NO,right.location.reference,left.location.register));
  505. end;
  506. LOC_MMREGISTER,LOC_CMMREGISTER:
  507. exprasmlist.concat(taicpu.op_reg_reg(op,S_NO,right.location.register,left.location.register));
  508. else
  509. internalerror(200402223);
  510. end;
  511. end;
  512. location.resflags:=getresflags(true);
  513. end;
  514. procedure tx86addnode.second_addfloat;
  515. var
  516. op : TAsmOp;
  517. begin
  518. if use_sse(resulttype.def) then
  519. begin
  520. second_addfloatsse;
  521. exit;
  522. end;
  523. pass_left_right;
  524. case nodetype of
  525. addn :
  526. op:=A_FADDP;
  527. muln :
  528. op:=A_FMULP;
  529. subn :
  530. op:=A_FSUBP;
  531. slashn :
  532. op:=A_FDIVP;
  533. else
  534. internalerror(2003042214);
  535. end;
  536. left_and_right_must_be_fpureg;
  537. { if we swaped the tree nodes, then use the reverse operator }
  538. if nf_swaped in flags then
  539. begin
  540. if (nodetype=slashn) then
  541. op:=A_FDIVRP
  542. else if (nodetype=subn) then
  543. op:=A_FSUBRP;
  544. end;
  545. emit_reg_reg(op,S_NO,NR_ST,NR_ST1);
  546. tcgx86(cg).dec_fpu_stack;
  547. location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
  548. location.register:=NR_ST;
  549. end;
  550. procedure tx86addnode.second_cmpfloat;
  551. var
  552. resflags : tresflags;
  553. begin
  554. if use_sse(left.resulttype.def) or use_sse(right.resulttype.def) then
  555. begin
  556. second_cmpfloatsse;
  557. exit;
  558. end;
  559. pass_left_right;
  560. left_and_right_must_be_fpureg;
  561. {$ifndef x86_64}
  562. if aktspecificoptprocessor<ClassPentium2 then
  563. begin
  564. emit_none(A_FCOMPP,S_NO);
  565. tcgx86(cg).dec_fpu_stack;
  566. tcgx86(cg).dec_fpu_stack;
  567. { load fpu flags }
  568. cg.getcpuregister(exprasmlist,NR_AX);
  569. emit_reg(A_FNSTSW,S_NO,NR_AX);
  570. emit_none(A_SAHF,S_NO);
  571. cg.ungetcpuregister(exprasmlist,NR_AX);
  572. if nf_swaped in flags then
  573. begin
  574. case nodetype of
  575. equaln : resflags:=F_E;
  576. unequaln : resflags:=F_NE;
  577. ltn : resflags:=F_A;
  578. lten : resflags:=F_AE;
  579. gtn : resflags:=F_B;
  580. gten : resflags:=F_BE;
  581. end;
  582. end
  583. else
  584. begin
  585. case nodetype of
  586. equaln : resflags:=F_E;
  587. unequaln : resflags:=F_NE;
  588. ltn : resflags:=F_B;
  589. lten : resflags:=F_BE;
  590. gtn : resflags:=F_A;
  591. gten : resflags:=F_AE;
  592. end;
  593. end;
  594. end
  595. else
  596. {$endif x86_64}
  597. begin
  598. exprasmlist.concat(taicpu.op_reg_reg(A_FCOMIP,S_NO,NR_ST1,NR_ST0));
  599. { fcomip pops only one fpu register }
  600. exprasmlist.concat(taicpu.op_reg(A_FSTP,S_NO,NR_ST0));
  601. tcgx86(cg).dec_fpu_stack;
  602. tcgx86(cg).dec_fpu_stack;
  603. { load fpu flags }
  604. if nf_swaped in flags then
  605. begin
  606. case nodetype of
  607. equaln : resflags:=F_E;
  608. unequaln : resflags:=F_NE;
  609. ltn : resflags:=F_A;
  610. lten : resflags:=F_AE;
  611. gtn : resflags:=F_B;
  612. gten : resflags:=F_BE;
  613. end;
  614. end
  615. else
  616. begin
  617. case nodetype of
  618. equaln : resflags:=F_E;
  619. unequaln : resflags:=F_NE;
  620. ltn : resflags:=F_B;
  621. lten : resflags:=F_BE;
  622. gtn : resflags:=F_A;
  623. gten : resflags:=F_AE;
  624. end;
  625. end;
  626. end;
  627. location_reset(location,LOC_FLAGS,OS_NO);
  628. location.resflags:=resflags;
  629. end;
  630. {*****************************************************************************
  631. Add64bit
  632. *****************************************************************************}
  633. procedure tx86addnode.second_add64bit;
  634. begin
  635. {$ifdef cpu64bit}
  636. second_addordinal;
  637. {$else cpu64bit}
  638. { must be implemented separate }
  639. internalerror(200402042);
  640. {$endif cpu64bit}
  641. end;
  642. procedure tx86addnode.second_cmp64bit;
  643. begin
  644. {$ifdef cpu64bit}
  645. second_cmpordinal;
  646. {$else cpu64bit}
  647. { must be implemented separate }
  648. internalerror(200402043);
  649. {$endif cpu64bit}
  650. end;
  651. {*****************************************************************************
  652. AddOrdinal
  653. *****************************************************************************}
  654. procedure tx86addnode.second_addordinal;
  655. var
  656. mboverflow : boolean;
  657. op : tasmop;
  658. opsize : tcgsize;
  659. { true, if unsigned types are compared }
  660. unsigned : boolean;
  661. { true, if for sets subtractions the extra not should generated }
  662. extra_not : boolean;
  663. begin
  664. { defaults }
  665. extra_not:=false;
  666. mboverflow:=false;
  667. unsigned:=not(is_signed(left.resulttype.def)) or
  668. not(is_signed(right.resulttype.def));
  669. opsize:=def_cgsize(left.resulttype.def);
  670. pass_left_right;
  671. case nodetype of
  672. addn :
  673. begin
  674. op:=A_ADD;
  675. mboverflow:=true;
  676. end;
  677. muln :
  678. begin
  679. if unsigned then
  680. op:=A_MUL
  681. else
  682. op:=A_IMUL;
  683. mboverflow:=true;
  684. end;
  685. subn :
  686. begin
  687. op:=A_SUB;
  688. mboverflow:=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. left_must_be_reg(opsize,false);
  706. emit_generic_code(op,opsize,unsigned,extra_not,mboverflow);
  707. location_freetemp(exprasmlist,right.location);
  708. set_result_location_reg;
  709. end;
  710. procedure tx86addnode.second_cmpordinal;
  711. var
  712. opsize : tcgsize;
  713. unsigned : boolean;
  714. begin
  715. unsigned:=not(is_signed(left.resulttype.def)) or
  716. not(is_signed(right.resulttype.def));
  717. opsize:=def_cgsize(left.resulttype.def);
  718. pass_left_right;
  719. left_must_be_reg(opsize,false);
  720. emit_generic_code(A_CMP,opsize,unsigned,false,false);
  721. location_freetemp(exprasmlist,right.location);
  722. location_freetemp(exprasmlist,left.location);
  723. location_reset(location,LOC_FLAGS,OS_NO);
  724. location.resflags:=getresflags(unsigned);
  725. end;
  726. begin
  727. caddnode:=tx86addnode;
  728. end.