nx86add.pas 33 KB

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