nx86add.pas 30 KB

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