n386add.pas 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794
  1. {
  2. $Id$
  3. Copyright (c) 2000-2002 by Florian Klaempfl
  4. Code generation for add nodes on the i386
  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 n386add;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. node,nadd,cpubase,cginfo;
  23. type
  24. ti386addnode = class(taddnode)
  25. procedure pass_2;override;
  26. protected
  27. function first_addstring : tnode; override;
  28. private
  29. procedure pass_left_and_right(var pushedfpu:boolean);
  30. function getresflags(unsigned : boolean) : tresflags;
  31. procedure left_must_be_reg(opsize:TOpSize;noswap:boolean);
  32. procedure emit_op_right_left(op:TAsmOp;opsize:TOpSize);
  33. procedure emit_generic_code(op:TAsmOp;opsize:TOpSize;unsigned,extra_not,mboverflow:boolean);
  34. procedure set_result_location(cmpop,unsigned:boolean);
  35. procedure second_addstring;
  36. procedure second_addboolean;
  37. procedure second_addfloat;
  38. procedure second_addsmallset;
  39. procedure second_mul;
  40. {$ifdef SUPPORT_MMX}
  41. procedure second_addmmx;
  42. {$endif SUPPORT_MMX}
  43. procedure second_add64bit;
  44. end;
  45. implementation
  46. uses
  47. globtype,systems,
  48. cutils,verbose,globals,
  49. symconst,symdef,paramgr,
  50. aasmbase,aasmtai,aasmcpu,defutil,htypechk,
  51. cgbase,pass_2,regvars,
  52. ncon,nset,
  53. cga,ncgutil,tgobj,rgobj,cgobj,cg64f32,rgcpu;
  54. {*****************************************************************************
  55. Helpers
  56. *****************************************************************************}
  57. const
  58. opsize_2_cgsize : array[S_B..S_L] of tcgsize = (OS_8,OS_16,OS_32);
  59. procedure ti386addnode.pass_left_and_right(var pushedfpu:boolean);
  60. var
  61. pushedregs : tmaybesave;
  62. begin
  63. { calculate the operator which is more difficult }
  64. firstcomplex(self);
  65. { in case of constant put it to the left }
  66. if (left.nodetype=ordconstn) then
  67. swapleftright;
  68. secondpass(left);
  69. { are too few registers free? }
  70. {$ifndef newra}
  71. maybe_save(exprasmlist,right.registers32,left.location,pushedregs);
  72. {$endif newra}
  73. if location.loc=LOC_FPUREGISTER then
  74. pushedfpu:=maybe_pushfpu(exprasmlist,right.registersfpu,left.location)
  75. else
  76. pushedfpu:=false;
  77. secondpass(right);
  78. {$ifndef newra}
  79. maybe_restore(exprasmlist,left.location,pushedregs);
  80. {$endif}
  81. end;
  82. function ti386addnode.getresflags(unsigned : boolean) : tresflags;
  83. begin
  84. case nodetype of
  85. equaln : getresflags:=F_E;
  86. unequaln : getresflags:=F_NE;
  87. else
  88. if not(unsigned) then
  89. begin
  90. if nf_swaped in flags then
  91. case nodetype of
  92. ltn : getresflags:=F_G;
  93. lten : getresflags:=F_GE;
  94. gtn : getresflags:=F_L;
  95. gten : getresflags:=F_LE;
  96. end
  97. else
  98. case nodetype of
  99. ltn : getresflags:=F_L;
  100. lten : getresflags:=F_LE;
  101. gtn : getresflags:=F_G;
  102. gten : getresflags:=F_GE;
  103. end;
  104. end
  105. else
  106. begin
  107. if nf_swaped in flags then
  108. case nodetype of
  109. ltn : getresflags:=F_A;
  110. lten : getresflags:=F_AE;
  111. gtn : getresflags:=F_B;
  112. gten : getresflags:=F_BE;
  113. end
  114. else
  115. case nodetype of
  116. ltn : getresflags:=F_B;
  117. lten : getresflags:=F_BE;
  118. gtn : getresflags:=F_A;
  119. gten : getresflags:=F_AE;
  120. end;
  121. end;
  122. end;
  123. end;
  124. procedure ti386addnode.left_must_be_reg(opsize:TOpSize;noswap:boolean);
  125. begin
  126. { left location is not a register? }
  127. if (left.location.loc<>LOC_REGISTER) then
  128. begin
  129. { if right is register then we can swap the locations }
  130. if (not noswap) and
  131. (right.location.loc=LOC_REGISTER) then
  132. begin
  133. location_swap(left.location,right.location);
  134. toggleflag(nf_swaped);
  135. end
  136. else
  137. begin
  138. { maybe we can reuse a constant register when the
  139. operation is a comparison that doesn't change the
  140. value of the register }
  141. location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],(nodetype in [ltn,lten,gtn,gten,equaln,unequaln]));
  142. end;
  143. end;
  144. end;
  145. procedure ti386addnode.emit_op_right_left(op:TAsmOp;opsize:TOpsize);
  146. begin
  147. { left must be a register }
  148. case right.location.loc of
  149. LOC_REGISTER,
  150. LOC_CREGISTER :
  151. exprasmlist.concat(taicpu.op_reg_reg(op,opsize,right.location.register,left.location.register));
  152. LOC_REFERENCE,
  153. LOC_CREFERENCE :
  154. exprasmlist.concat(taicpu.op_ref_reg(op,opsize,right.location.reference,left.location.register));
  155. LOC_CONSTANT :
  156. exprasmlist.concat(taicpu.op_const_reg(op,opsize,right.location.value,left.location.register));
  157. else
  158. internalerror(200203232);
  159. end;
  160. end;
  161. procedure ti386addnode.set_result_location(cmpop,unsigned:boolean);
  162. begin
  163. if cmpop then
  164. begin
  165. location_reset(location,LOC_FLAGS,OS_NO);
  166. location.resflags:=getresflags(unsigned);
  167. end
  168. else
  169. location_copy(location,left.location);
  170. end;
  171. procedure ti386addnode.emit_generic_code(op:TAsmOp;opsize:TOpSize;unsigned,extra_not,mboverflow:boolean);
  172. var
  173. power : longint;
  174. hl4 : tasmlabel;
  175. r : Tregister;
  176. begin
  177. { at this point, left.location.loc should be LOC_REGISTER }
  178. if right.location.loc=LOC_REGISTER then
  179. begin
  180. { right.location is a LOC_REGISTER }
  181. { when swapped another result register }
  182. if (nodetype=subn) and (nf_swaped in flags) then
  183. begin
  184. if extra_not then
  185. emit_reg(A_NOT,S_L,left.location.register);
  186. emit_reg_reg(op,opsize,left.location.register,right.location.register);
  187. { newly swapped also set swapped flag }
  188. location_swap(left.location,right.location);
  189. toggleflag(nf_swaped);
  190. end
  191. else
  192. begin
  193. if extra_not then
  194. emit_reg(A_NOT,S_L,right.location.register);
  195. emit_reg_reg(op,opsize,right.location.register,left.location.register);
  196. end;
  197. end
  198. else
  199. begin
  200. { right.location is not a LOC_REGISTER }
  201. if (nodetype=subn) and (nf_swaped in flags) then
  202. begin
  203. if extra_not then
  204. emit_reg(A_NOT,opsize,left.location.register);
  205. {$ifdef newra}
  206. r:=rg.getregisterint(exprasmlist,OS_INT);
  207. {$else}
  208. r.enum:=R_INTREGISTER;
  209. r.number:=NR_EDI;
  210. rg.getexplicitregisterint(exprasmlist,NR_EDI);
  211. {$endif}
  212. cg.a_load_loc_reg(exprasmlist,right.location,r);
  213. emit_reg_reg(op,opsize,left.location.register,r);
  214. emit_reg_reg(A_MOV,opsize,r,left.location.register);
  215. rg.ungetregisterint(exprasmlist,r);
  216. end
  217. else
  218. begin
  219. { Optimizations when right.location is a constant value }
  220. if (op=A_CMP) and
  221. (nodetype in [equaln,unequaln]) and
  222. (right.location.loc=LOC_CONSTANT) and
  223. (right.location.value=0) then
  224. begin
  225. emit_reg_reg(A_TEST,opsize,left.location.register,left.location.register);
  226. end
  227. else
  228. if (op=A_ADD) and
  229. (right.location.loc=LOC_CONSTANT) and
  230. (right.location.value=1) and
  231. not(cs_check_overflow in aktlocalswitches) then
  232. begin
  233. emit_reg(A_INC,opsize,left.location.register);
  234. end
  235. else
  236. if (op=A_SUB) and
  237. (right.location.loc=LOC_CONSTANT) and
  238. (right.location.value=1) and
  239. not(cs_check_overflow in aktlocalswitches) then
  240. begin
  241. emit_reg(A_DEC,opsize,left.location.register);
  242. end
  243. else
  244. if (op=A_IMUL) and
  245. (right.location.loc=LOC_CONSTANT) and
  246. (ispowerof2(right.location.value,power)) and
  247. not(cs_check_overflow in aktlocalswitches) then
  248. begin
  249. emit_const_reg(A_SHL,opsize,power,left.location.register);
  250. end
  251. else
  252. begin
  253. if extra_not then
  254. begin
  255. {$ifdef newra}
  256. r:=rg.getregisterint(exprasmlist,OS_INT);
  257. {$else}
  258. rg.getexplicitregisterint(exprasmlist,NR_EDI);
  259. r.enum:=R_INTREGISTER;
  260. r.number:=NR_EDI;
  261. {$endif}
  262. cg.a_load_loc_reg(exprasmlist,right.location,r);
  263. emit_reg(A_NOT,S_L,r);
  264. emit_reg_reg(A_AND,S_L,r,left.location.register);
  265. rg.ungetregisterint(exprasmlist,r);
  266. end
  267. else
  268. begin
  269. emit_op_right_left(op,opsize);
  270. end;
  271. end;
  272. end;
  273. end;
  274. { only in case of overflow operations }
  275. { produce overflow code }
  276. { we must put it here directly, because sign of operation }
  277. { is in unsigned VAR!! }
  278. if mboverflow then
  279. begin
  280. if cs_check_overflow in aktlocalswitches then
  281. begin
  282. objectlibrary.getlabel(hl4);
  283. if unsigned then
  284. emitjmp(C_NB,hl4)
  285. else
  286. emitjmp(C_NO,hl4);
  287. cg.a_call_name(exprasmlist,'FPC_OVERFLOW');
  288. cg.a_label(exprasmlist,hl4);
  289. end;
  290. end;
  291. end;
  292. {*****************************************************************************
  293. Addstring
  294. *****************************************************************************}
  295. { note: if you implemented an fpc_shortstr_concat similar to the }
  296. { one in i386.inc, you have to override first_addstring like in }
  297. { ti386addnode.first_string and implement the shortstring concat }
  298. { manually! The generic routine is different from the i386 one (JM) }
  299. function ti386addnode.first_addstring : tnode;
  300. begin
  301. { special cases for shortstrings, handled in pass_2 (JM) }
  302. { can't handle fpc_shortstr_compare with compilerproc either because it }
  303. { returns its results in the flags instead of in eax }
  304. if (nodetype in [ltn,lten,gtn,gten,equaln,unequaln]) and
  305. is_shortstring(left.resulttype.def) and
  306. not(((left.nodetype=stringconstn) and (str_length(left)=0)) or
  307. ((right.nodetype=stringconstn) and (str_length(right)=0))) then
  308. begin
  309. expectloc:=LOC_FLAGS;
  310. calcregisters(self,0,0,0);
  311. result := nil;
  312. exit;
  313. end;
  314. { otherwise, use the generic code }
  315. result := inherited first_addstring;
  316. end;
  317. procedure ti386addnode.second_addstring;
  318. var
  319. cmpop : boolean;
  320. pushed : Tpushedsavedint;
  321. begin
  322. { string operations are not commutative }
  323. if nf_swaped in flags then
  324. swapleftright;
  325. case tstringdef(left.resulttype.def).string_typ of
  326. st_shortstring:
  327. begin
  328. case nodetype of
  329. ltn,lten,gtn,gten,equaln,unequaln :
  330. begin
  331. cmpop := true;
  332. rg.saveusedintregisters(exprasmlist,pushed,all_intregisters);
  333. secondpass(left);
  334. location_release(exprasmlist,left.location);
  335. cg.a_paramaddr_ref(exprasmlist,left.location.reference,paramanager.getintparaloc(2));
  336. secondpass(right);
  337. location_release(exprasmlist,right.location);
  338. cg.a_paramaddr_ref(exprasmlist,right.location.reference,paramanager.getintparaloc(1));
  339. rg.saveintregvars(exprasmlist,all_intregisters);
  340. cg.a_call_name(exprasmlist,'FPC_SHORTSTR_COMPARE');
  341. rg.restoreusedintregisters(exprasmlist,pushed);
  342. location_freetemp(exprasmlist,left.location);
  343. location_freetemp(exprasmlist,right.location);
  344. end;
  345. end;
  346. set_result_location(cmpop,true);
  347. end;
  348. else
  349. { rest should be handled in first pass (JM) }
  350. internalerror(200108303);
  351. end;
  352. end;
  353. {*****************************************************************************
  354. AddBoolean
  355. *****************************************************************************}
  356. procedure ti386addnode.second_addboolean;
  357. var
  358. op : TAsmOp;
  359. opsize : TOpsize;
  360. cmpop,
  361. isjump : boolean;
  362. otl,ofl : tasmlabel;
  363. pushedregs : tmaybesave;
  364. begin
  365. { calculate the operator which is more difficult }
  366. firstcomplex(self);
  367. cmpop:=false;
  368. if (torddef(left.resulttype.def).typ=bool8bit) or
  369. (torddef(right.resulttype.def).typ=bool8bit) then
  370. opsize:=S_B
  371. else
  372. if (torddef(left.resulttype.def).typ=bool16bit) or
  373. (torddef(right.resulttype.def).typ=bool16bit) then
  374. opsize:=S_W
  375. else
  376. opsize:=S_L;
  377. if (cs_full_boolean_eval in aktlocalswitches) or
  378. (nodetype in [unequaln,ltn,lten,gtn,gten,equaln,xorn]) then
  379. begin
  380. if left.nodetype in [ordconstn,realconstn] then
  381. swapleftright;
  382. isjump:=(left.location.loc=LOC_JUMP);
  383. if isjump then
  384. begin
  385. otl:=truelabel;
  386. objectlibrary.getlabel(truelabel);
  387. ofl:=falselabel;
  388. objectlibrary.getlabel(falselabel);
  389. end;
  390. secondpass(left);
  391. if left.location.loc in [LOC_FLAGS,LOC_JUMP] then
  392. location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],false);
  393. if isjump then
  394. begin
  395. truelabel:=otl;
  396. falselabel:=ofl;
  397. end;
  398. {$ifndef newra}
  399. maybe_save(exprasmlist,right.registers32,left.location,pushedregs);
  400. {$endif}
  401. isjump:=(right.location.loc=LOC_JUMP);
  402. if isjump then
  403. begin
  404. otl:=truelabel;
  405. objectlibrary.getlabel(truelabel);
  406. ofl:=falselabel;
  407. objectlibrary.getlabel(falselabel);
  408. end;
  409. secondpass(right);
  410. {$ifndef newra}
  411. maybe_restore(exprasmlist,left.location,pushedregs);
  412. {$endif newra}
  413. if right.location.loc in [LOC_FLAGS,LOC_JUMP] then
  414. location_force_reg(exprasmlist,right.location,opsize_2_cgsize[opsize],false);
  415. if isjump then
  416. begin
  417. truelabel:=otl;
  418. falselabel:=ofl;
  419. end;
  420. { left must be a register }
  421. left_must_be_reg(opsize,false);
  422. { compare the }
  423. case nodetype of
  424. ltn,lten,gtn,gten,
  425. equaln,unequaln :
  426. begin
  427. op:=A_CMP;
  428. cmpop:=true;
  429. end;
  430. xorn :
  431. op:=A_XOR;
  432. orn :
  433. op:=A_OR;
  434. andn :
  435. op:=A_AND;
  436. else
  437. internalerror(200203247);
  438. end;
  439. emit_op_right_left(op,opsize);
  440. location_freetemp(exprasmlist,right.location);
  441. location_release(exprasmlist,right.location);
  442. if cmpop then
  443. begin
  444. location_freetemp(exprasmlist,left.location);
  445. location_release(exprasmlist,left.location);
  446. end;
  447. set_result_location(cmpop,true);
  448. end
  449. else
  450. begin
  451. case nodetype of
  452. andn,
  453. orn :
  454. begin
  455. location_reset(location,LOC_JUMP,OS_NO);
  456. case nodetype of
  457. andn :
  458. begin
  459. otl:=truelabel;
  460. objectlibrary.getlabel(truelabel);
  461. secondpass(left);
  462. maketojumpbool(exprasmlist,left,lr_load_regvars);
  463. cg.a_label(exprasmlist,truelabel);
  464. truelabel:=otl;
  465. end;
  466. orn :
  467. begin
  468. ofl:=falselabel;
  469. objectlibrary.getlabel(falselabel);
  470. secondpass(left);
  471. maketojumpbool(exprasmlist,left,lr_load_regvars);
  472. cg.a_label(exprasmlist,falselabel);
  473. falselabel:=ofl;
  474. end;
  475. else
  476. internalerror(2003042212);
  477. end;
  478. secondpass(right);
  479. maketojumpbool(exprasmlist,right,lr_load_regvars);
  480. end;
  481. else
  482. internalerror(2003042213);
  483. end;
  484. end;
  485. end;
  486. {*****************************************************************************
  487. AddFloat
  488. *****************************************************************************}
  489. procedure ti386addnode.second_addfloat;
  490. var
  491. op : TAsmOp;
  492. resflags : tresflags;
  493. pushedfpu,
  494. cmpop : boolean;
  495. r,r2:Tregister;
  496. begin
  497. pass_left_and_right(pushedfpu);
  498. cmpop:=false;
  499. case nodetype of
  500. addn :
  501. op:=A_FADDP;
  502. muln :
  503. op:=A_FMULP;
  504. subn :
  505. op:=A_FSUBP;
  506. slashn :
  507. op:=A_FDIVP;
  508. ltn,lten,gtn,gten,
  509. equaln,unequaln :
  510. begin
  511. op:=A_FCOMPP;
  512. cmpop:=true;
  513. end;
  514. else
  515. internalerror(2003042214);
  516. end;
  517. if (right.location.loc<>LOC_FPUREGISTER) then
  518. begin
  519. r.enum:=R_ST;
  520. cg.a_loadfpu_loc_reg(exprasmlist,right.location,r);
  521. if (right.location.loc <> LOC_CFPUREGISTER) and
  522. pushedfpu then
  523. location_freetemp(exprasmlist,left.location);
  524. if (left.location.loc<>LOC_FPUREGISTER) then
  525. begin
  526. cg.a_loadfpu_loc_reg(exprasmlist,left.location,r);
  527. if (left.location.loc <> LOC_CFPUREGISTER) and
  528. pushedfpu then
  529. location_freetemp(exprasmlist,left.location);
  530. end
  531. else
  532. begin
  533. { left was on the stack => swap }
  534. toggleflag(nf_swaped);
  535. end;
  536. { releases the right reference }
  537. location_release(exprasmlist,right.location);
  538. end
  539. { the nominator in st0 }
  540. else if (left.location.loc<>LOC_FPUREGISTER) then
  541. begin
  542. r.enum:=R_ST;
  543. cg.a_loadfpu_loc_reg(exprasmlist,left.location,r);
  544. if (left.location.loc <> LOC_CFPUREGISTER) and
  545. pushedfpu then
  546. location_freetemp(exprasmlist,left.location);
  547. end
  548. else
  549. begin
  550. { fpu operands are always in the wrong order on the stack }
  551. toggleflag(nf_swaped);
  552. end;
  553. { releases the left reference }
  554. if (left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  555. location_release(exprasmlist,left.location);
  556. { if we swaped the tree nodes, then use the reverse operator }
  557. if nf_swaped in flags then
  558. begin
  559. if (nodetype=slashn) then
  560. op:=A_FDIVRP
  561. else if (nodetype=subn) then
  562. op:=A_FSUBRP;
  563. end;
  564. { to avoid the pentium bug
  565. if (op=FDIVP) and (opt_processors=pentium) then
  566. cg.a_call_name(exprasmlist,'EMUL_FDIVP')
  567. else
  568. }
  569. { the Intel assemblers want operands }
  570. if op<>A_FCOMPP then
  571. begin
  572. r.enum:=R_ST;
  573. r2.enum:=R_ST1;
  574. emit_reg_reg(op,S_NO,r,r2);
  575. dec(trgcpu(rg).fpuvaroffset);
  576. end
  577. else
  578. begin
  579. emit_none(op,S_NO);
  580. dec(trgcpu(rg).fpuvaroffset,2);
  581. end;
  582. { on comparison load flags }
  583. if cmpop then
  584. begin
  585. {$ifdef newra}
  586. r:=rg.getexplicitregisterint(exprasmlist,NR_AX);
  587. {$else}
  588. if not(RS_EAX in rg.unusedregsint) then
  589. begin
  590. rg.getexplicitregisterint(exprasmlist,NR_EDI);
  591. r.enum:=R_INTREGISTER;
  592. r.number:=NR_EAX;
  593. r2.enum:=R_INTREGISTER;;
  594. r2.number:=NR_EDI;
  595. emit_reg_reg(A_MOV,S_L,r,r2);
  596. end;
  597. r.enum:=R_INTREGISTER;
  598. r.number:=NR_AX;
  599. {$endif}
  600. emit_reg(A_FNSTSW,S_NO,r);
  601. emit_none(A_SAHF,S_NO);
  602. {$ifdef newra}
  603. rg.ungetregisterint(exprasmlist,r);
  604. {$else}
  605. if not(RS_EAX in rg.unusedregsint) then
  606. begin
  607. r.enum:=R_INTREGISTER;
  608. r.number:=NR_EAX;
  609. r2.enum:=R_INTREGISTER;;
  610. r2.number:=NR_EDI;
  611. emit_reg_reg(A_MOV,S_L,r2,r);
  612. rg.ungetregisterint(exprasmlist,r2);
  613. end;
  614. {$endif}
  615. if nf_swaped in flags then
  616. begin
  617. case nodetype of
  618. equaln : resflags:=F_E;
  619. unequaln : resflags:=F_NE;
  620. ltn : resflags:=F_A;
  621. lten : resflags:=F_AE;
  622. gtn : resflags:=F_B;
  623. gten : resflags:=F_BE;
  624. end;
  625. end
  626. else
  627. begin
  628. case nodetype of
  629. equaln : resflags:=F_E;
  630. unequaln : resflags:=F_NE;
  631. ltn : resflags:=F_B;
  632. lten : resflags:=F_BE;
  633. gtn : resflags:=F_A;
  634. gten : resflags:=F_AE;
  635. end;
  636. end;
  637. location_reset(location,LOC_FLAGS,OS_NO);
  638. location.resflags:=resflags;
  639. end
  640. else
  641. begin
  642. location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
  643. location.register.enum:=R_ST;
  644. end;
  645. end;
  646. {*****************************************************************************
  647. AddSmallSet
  648. *****************************************************************************}
  649. procedure ti386addnode.second_addsmallset;
  650. var
  651. opsize : TOpSize;
  652. op : TAsmOp;
  653. cmpop,
  654. pushedfpu,
  655. extra_not,
  656. noswap : boolean;
  657. begin
  658. pass_left_and_right(pushedfpu);
  659. { when a setdef is passed, it has to be a smallset }
  660. if ((left.resulttype.def.deftype=setdef) and
  661. (tsetdef(left.resulttype.def).settype<>smallset)) or
  662. ((right.resulttype.def.deftype=setdef) and
  663. (tsetdef(right.resulttype.def).settype<>smallset)) then
  664. internalerror(200203301);
  665. cmpop:=false;
  666. noswap:=false;
  667. extra_not:=false;
  668. opsize:=S_L;
  669. case nodetype of
  670. addn :
  671. begin
  672. { this is a really ugly hack!!!!!!!!!! }
  673. { this could be done later using EDI }
  674. { as it is done for subn }
  675. { instead of two registers!!!! }
  676. { adding elements is not commutative }
  677. if (nf_swaped in flags) and (left.nodetype=setelementn) then
  678. swapleftright;
  679. { are we adding set elements ? }
  680. if right.nodetype=setelementn then
  681. begin
  682. { no range support for smallsets! }
  683. if assigned(tsetelementnode(right).right) then
  684. internalerror(43244);
  685. { bts requires both elements to be registers }
  686. location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],false);
  687. location_force_reg(exprasmlist,right.location,opsize_2_cgsize[opsize],true);
  688. op:=A_BTS;
  689. noswap:=true;
  690. end
  691. else
  692. op:=A_OR;
  693. end;
  694. symdifn :
  695. op:=A_XOR;
  696. muln :
  697. op:=A_AND;
  698. subn :
  699. begin
  700. op:=A_AND;
  701. if (not(nf_swaped in flags)) and
  702. (right.location.loc=LOC_CONSTANT) then
  703. right.location.value := not(right.location.value)
  704. else if (nf_swaped in flags) and
  705. (left.location.loc=LOC_CONSTANT) then
  706. left.location.value := not(left.location.value)
  707. else
  708. extra_not:=true;
  709. end;
  710. equaln,
  711. unequaln :
  712. begin
  713. op:=A_CMP;
  714. cmpop:=true;
  715. end;
  716. lten,gten:
  717. begin
  718. If (not(nf_swaped in flags) and
  719. (nodetype = lten)) or
  720. ((nf_swaped in flags) and
  721. (nodetype = gten)) then
  722. swapleftright;
  723. location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],true);
  724. emit_op_right_left(A_AND,opsize);
  725. op:=A_CMP;
  726. cmpop:=true;
  727. { warning: ugly hack, we need a JE so change the node to equaln }
  728. nodetype:=equaln;
  729. end;
  730. xorn :
  731. op:=A_XOR;
  732. orn :
  733. op:=A_OR;
  734. andn :
  735. op:=A_AND;
  736. else
  737. internalerror(2003042215);
  738. end;
  739. { left must be a register }
  740. left_must_be_reg(opsize,noswap);
  741. emit_generic_code(op,opsize,true,extra_not,false);
  742. location_freetemp(exprasmlist,right.location);
  743. location_release(exprasmlist,right.location);
  744. if cmpop then
  745. begin
  746. location_freetemp(exprasmlist,left.location);
  747. location_release(exprasmlist,left.location);
  748. end;
  749. set_result_location(cmpop,true);
  750. end;
  751. {*****************************************************************************
  752. Add64bit
  753. *****************************************************************************}
  754. procedure ti386addnode.second_add64bit;
  755. var
  756. op : TOpCG;
  757. op1,op2 : TAsmOp;
  758. opsize : TOpSize;
  759. hregister,
  760. hregister2 : tregister;
  761. href : treference;
  762. hl4 : tasmlabel;
  763. pushedfpu,
  764. mboverflow,
  765. cmpop,
  766. unsigned : boolean;
  767. r:Tregister;
  768. procedure firstjmp64bitcmp;
  769. var
  770. oldnodetype : tnodetype;
  771. begin
  772. load_all_regvars(exprasmlist);
  773. { the jump the sequence is a little bit hairy }
  774. case nodetype of
  775. ltn,gtn:
  776. begin
  777. emitjmp(flags_to_cond(getresflags(unsigned)),truelabel);
  778. { cheat a little bit for the negative test }
  779. toggleflag(nf_swaped);
  780. emitjmp(flags_to_cond(getresflags(unsigned)),falselabel);
  781. toggleflag(nf_swaped);
  782. end;
  783. lten,gten:
  784. begin
  785. oldnodetype:=nodetype;
  786. if nodetype=lten then
  787. nodetype:=ltn
  788. else
  789. nodetype:=gtn;
  790. emitjmp(flags_to_cond(getresflags(unsigned)),truelabel);
  791. { cheat for the negative test }
  792. if nodetype=ltn then
  793. nodetype:=gtn
  794. else
  795. nodetype:=ltn;
  796. emitjmp(flags_to_cond(getresflags(unsigned)),falselabel);
  797. nodetype:=oldnodetype;
  798. end;
  799. equaln:
  800. emitjmp(C_NE,falselabel);
  801. unequaln:
  802. emitjmp(C_NE,truelabel);
  803. end;
  804. end;
  805. procedure secondjmp64bitcmp;
  806. begin
  807. { the jump the sequence is a little bit hairy }
  808. case nodetype of
  809. ltn,gtn,lten,gten:
  810. begin
  811. { the comparisaion of the low dword have to be }
  812. { always unsigned! }
  813. emitjmp(flags_to_cond(getresflags(true)),truelabel);
  814. cg.a_jmp_always(exprasmlist,falselabel);
  815. end;
  816. equaln:
  817. begin
  818. emitjmp(C_NE,falselabel);
  819. cg.a_jmp_always(exprasmlist,truelabel);
  820. end;
  821. unequaln:
  822. begin
  823. emitjmp(C_NE,truelabel);
  824. cg.a_jmp_always(exprasmlist,falselabel);
  825. end;
  826. end;
  827. end;
  828. begin
  829. firstcomplex(self);
  830. pass_left_and_right(pushedfpu);
  831. op1:=A_NONE;
  832. op2:=A_NONE;
  833. mboverflow:=false;
  834. cmpop:=false;
  835. opsize:=S_L;
  836. unsigned:=((left.resulttype.def.deftype=orddef) and
  837. (torddef(left.resulttype.def).typ=u64bit)) or
  838. ((right.resulttype.def.deftype=orddef) and
  839. (torddef(right.resulttype.def).typ=u64bit));
  840. case nodetype of
  841. addn :
  842. begin
  843. op:=OP_ADD;
  844. mboverflow:=true;
  845. end;
  846. subn :
  847. begin
  848. op:=OP_SUB;
  849. op1:=A_SUB;
  850. op2:=A_SBB;
  851. mboverflow:=true;
  852. end;
  853. ltn,lten,
  854. gtn,gten,
  855. equaln,unequaln:
  856. begin
  857. op:=OP_NONE;
  858. cmpop:=true;
  859. end;
  860. xorn:
  861. op:=OP_XOR;
  862. orn:
  863. op:=OP_OR;
  864. andn:
  865. op:=OP_AND;
  866. else
  867. begin
  868. { everything should be handled in pass_1 (JM) }
  869. internalerror(200109051);
  870. end;
  871. end;
  872. { left and right no register? }
  873. { then one must be demanded }
  874. if (left.location.loc<>LOC_REGISTER) then
  875. begin
  876. if (right.location.loc<>LOC_REGISTER) then
  877. begin
  878. { we can reuse a CREGISTER for comparison }
  879. if not((left.location.loc=LOC_CREGISTER) and cmpop) then
  880. begin
  881. if (left.location.loc<>LOC_CREGISTER) then
  882. begin
  883. location_freetemp(exprasmlist,left.location);
  884. location_release(exprasmlist,left.location);
  885. end;
  886. hregister:=rg.getregisterint(exprasmlist,OS_INT);
  887. hregister2:=rg.getregisterint(exprasmlist,OS_INT);
  888. cg64.a_load64_loc_reg(exprasmlist,left.location,joinreg64(hregister,hregister2));
  889. location_reset(left.location,LOC_REGISTER,OS_64);
  890. left.location.registerlow:=hregister;
  891. left.location.registerhigh:=hregister2;
  892. end;
  893. end
  894. else
  895. begin
  896. location_swap(left.location,right.location);
  897. toggleflag(nf_swaped);
  898. end;
  899. end;
  900. { at this point, left.location.loc should be LOC_REGISTER }
  901. if right.location.loc=LOC_REGISTER then
  902. begin
  903. { when swapped another result register }
  904. if (nodetype=subn) and (nf_swaped in flags) then
  905. begin
  906. cg64.a_op64_reg_reg(exprasmlist,op,
  907. left.location.register64,
  908. right.location.register64);
  909. location_swap(left.location,right.location);
  910. toggleflag(nf_swaped);
  911. end
  912. else if cmpop then
  913. begin
  914. emit_reg_reg(A_CMP,S_L,right.location.registerhigh,left.location.registerhigh);
  915. firstjmp64bitcmp;
  916. emit_reg_reg(A_CMP,S_L,right.location.registerlow,left.location.registerlow);
  917. secondjmp64bitcmp;
  918. end
  919. else
  920. begin
  921. cg64.a_op64_reg_reg(exprasmlist,op,
  922. right.location.register64,
  923. left.location.register64);
  924. end;
  925. location_release(exprasmlist,right.location);
  926. end
  927. else
  928. begin
  929. { right.location<>LOC_REGISTER }
  930. if (nodetype=subn) and (nf_swaped in flags) then
  931. begin
  932. {$ifdef newra}
  933. r:=rg.getregisterint(exprasmlist,OS_INT);
  934. {$else}
  935. rg.getexplicitregisterint(exprasmlist,NR_EDI);
  936. r.enum:=R_INTREGISTER;
  937. r.number:=NR_EDI;
  938. {$endif}
  939. cg64.a_load64low_loc_reg(exprasmlist,right.location,r);
  940. emit_reg_reg(op1,opsize,left.location.registerlow,r);
  941. emit_reg_reg(A_MOV,opsize,r,left.location.registerlow);
  942. cg64.a_load64high_loc_reg(exprasmlist,right.location,r);
  943. { the carry flag is still ok }
  944. emit_reg_reg(op2,opsize,left.location.registerhigh,r);
  945. emit_reg_reg(A_MOV,opsize,r,left.location.registerhigh);
  946. rg.ungetregisterint(exprasmlist,r);
  947. if right.location.loc<>LOC_CREGISTER then
  948. begin
  949. location_freetemp(exprasmlist,right.location);
  950. location_release(exprasmlist,right.location);
  951. end;
  952. end
  953. else if cmpop then
  954. begin
  955. case right.location.loc of
  956. LOC_CREGISTER :
  957. begin
  958. emit_reg_reg(A_CMP,S_L,right.location.registerhigh,left.location.registerhigh);
  959. firstjmp64bitcmp;
  960. emit_reg_reg(A_CMP,S_L,right.location.registerlow,left.location.registerlow);
  961. secondjmp64bitcmp;
  962. end;
  963. LOC_CREFERENCE,
  964. LOC_REFERENCE :
  965. begin
  966. href:=right.location.reference;
  967. inc(href.offset,4);
  968. emit_ref_reg(A_CMP,S_L,href,left.location.registerhigh);
  969. firstjmp64bitcmp;
  970. emit_ref_reg(A_CMP,S_L,right.location.reference,left.location.registerlow);
  971. secondjmp64bitcmp;
  972. cg.a_jmp_always(exprasmlist,falselabel);
  973. location_freetemp(exprasmlist,right.location);
  974. location_release(exprasmlist,right.location);
  975. end;
  976. LOC_CONSTANT :
  977. begin
  978. exprasmlist.concat(taicpu.op_const_reg(A_CMP,S_L,hi(right.location.valueqword),left.location.registerhigh));
  979. firstjmp64bitcmp;
  980. exprasmlist.concat(taicpu.op_const_reg(A_CMP,S_L,lo(right.location.valueqword),left.location.registerlow));
  981. secondjmp64bitcmp;
  982. end;
  983. else
  984. internalerror(200203282);
  985. end;
  986. end
  987. else
  988. begin
  989. cg64.a_op64_loc_reg(exprasmlist,op,right.location,
  990. left.location.register64);
  991. if (right.location.loc<>LOC_CREGISTER) then
  992. begin
  993. location_freetemp(exprasmlist,right.location);
  994. location_release(exprasmlist,right.location);
  995. end;
  996. end;
  997. end;
  998. if (left.location.loc<>LOC_CREGISTER) and cmpop then
  999. begin
  1000. location_freetemp(exprasmlist,left.location);
  1001. location_release(exprasmlist,left.location);
  1002. end;
  1003. { only in case of overflow operations }
  1004. { produce overflow code }
  1005. { we must put it here directly, because sign of operation }
  1006. { is in unsigned VAR!! }
  1007. if mboverflow then
  1008. begin
  1009. if cs_check_overflow in aktlocalswitches then
  1010. begin
  1011. objectlibrary.getlabel(hl4);
  1012. if unsigned then
  1013. emitjmp(C_NB,hl4)
  1014. else
  1015. emitjmp(C_NO,hl4);
  1016. cg.a_call_name(exprasmlist,'FPC_OVERFLOW');
  1017. cg.a_label(exprasmlist,hl4);
  1018. end;
  1019. end;
  1020. { we have LOC_JUMP as result }
  1021. if cmpop then
  1022. location_reset(location,LOC_JUMP,OS_NO)
  1023. else
  1024. location_copy(location,left.location);
  1025. end;
  1026. {*****************************************************************************
  1027. AddMMX
  1028. *****************************************************************************}
  1029. {$ifdef SUPPORT_MMX}
  1030. procedure ti386addnode.second_addmmx;
  1031. var
  1032. op : TAsmOp;
  1033. pushedfpu,
  1034. cmpop : boolean;
  1035. mmxbase : tmmxtype;
  1036. r,hregister : tregister;
  1037. begin
  1038. pass_left_and_right(pushedfpu);
  1039. cmpop:=false;
  1040. mmxbase:=mmx_type(left.resulttype.def);
  1041. case nodetype of
  1042. addn :
  1043. begin
  1044. if (cs_mmx_saturation in aktlocalswitches) then
  1045. begin
  1046. case mmxbase of
  1047. mmxs8bit:
  1048. op:=A_PADDSB;
  1049. mmxu8bit:
  1050. op:=A_PADDUSB;
  1051. mmxs16bit,mmxfixed16:
  1052. op:=A_PADDSB;
  1053. mmxu16bit:
  1054. op:=A_PADDUSW;
  1055. end;
  1056. end
  1057. else
  1058. begin
  1059. case mmxbase of
  1060. mmxs8bit,mmxu8bit:
  1061. op:=A_PADDB;
  1062. mmxs16bit,mmxu16bit,mmxfixed16:
  1063. op:=A_PADDW;
  1064. mmxs32bit,mmxu32bit:
  1065. op:=A_PADDD;
  1066. end;
  1067. end;
  1068. end;
  1069. muln :
  1070. begin
  1071. case mmxbase of
  1072. mmxs16bit,mmxu16bit:
  1073. op:=A_PMULLW;
  1074. mmxfixed16:
  1075. op:=A_PMULHW;
  1076. end;
  1077. end;
  1078. subn :
  1079. begin
  1080. if (cs_mmx_saturation in aktlocalswitches) then
  1081. begin
  1082. case mmxbase of
  1083. mmxs8bit:
  1084. op:=A_PSUBSB;
  1085. mmxu8bit:
  1086. op:=A_PSUBUSB;
  1087. mmxs16bit,mmxfixed16:
  1088. op:=A_PSUBSB;
  1089. mmxu16bit:
  1090. op:=A_PSUBUSW;
  1091. end;
  1092. end
  1093. else
  1094. begin
  1095. case mmxbase of
  1096. mmxs8bit,mmxu8bit:
  1097. op:=A_PSUBB;
  1098. mmxs16bit,mmxu16bit,mmxfixed16:
  1099. op:=A_PSUBW;
  1100. mmxs32bit,mmxu32bit:
  1101. op:=A_PSUBD;
  1102. end;
  1103. end;
  1104. end;
  1105. xorn:
  1106. op:=A_PXOR;
  1107. orn:
  1108. op:=A_POR;
  1109. andn:
  1110. op:=A_PAND;
  1111. else
  1112. internalerror(2003042214);
  1113. end;
  1114. { left and right no register? }
  1115. { then one must be demanded }
  1116. if (left.location.loc<>LOC_MMXREGISTER) then
  1117. begin
  1118. if (right.location.loc=LOC_MMXREGISTER) then
  1119. begin
  1120. location_swap(left.location,right.location);
  1121. toggleflag(nf_swaped);
  1122. end
  1123. else
  1124. begin
  1125. { register variable ? }
  1126. if (left.location.loc=LOC_CMMXREGISTER) then
  1127. begin
  1128. hregister:=rg.getregistermm(exprasmlist);
  1129. emit_reg_reg(A_MOVQ,S_NO,left.location.register,hregister);
  1130. end
  1131. else
  1132. begin
  1133. if not(left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  1134. internalerror(200203245);
  1135. location_release(exprasmlist,left.location);
  1136. hregister:=rg.getregistermm(exprasmlist);
  1137. emit_ref_reg(A_MOVQ,S_NO,left.location.reference,hregister);
  1138. end;
  1139. location_reset(left.location,LOC_MMXREGISTER,OS_NO);
  1140. left.location.register:=hregister;
  1141. end;
  1142. end;
  1143. { at this point, left.location.loc should be LOC_MMXREGISTER }
  1144. if right.location.loc<>LOC_MMXREGISTER then
  1145. begin
  1146. if (nodetype=subn) and (nf_swaped in flags) then
  1147. begin
  1148. r.enum:=R_MM7;
  1149. if right.location.loc=LOC_CMMXREGISTER then
  1150. begin
  1151. emit_reg_reg(A_MOVQ,S_NO,right.location.register,r);
  1152. emit_reg_reg(op,S_NO,left.location.register,r);
  1153. emit_reg_reg(A_MOVQ,S_NO,r,left.location.register);
  1154. end
  1155. else
  1156. begin
  1157. if not(left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  1158. internalerror(200203247);
  1159. emit_ref_reg(A_MOVQ,S_NO,right.location.reference,r);
  1160. emit_reg_reg(op,S_NO,left.location.register,r);
  1161. emit_reg_reg(A_MOVQ,S_NO,r,left.location.register);
  1162. location_release(exprasmlist,right.location);
  1163. end;
  1164. end
  1165. else
  1166. begin
  1167. if (right.location.loc=LOC_CMMXREGISTER) then
  1168. begin
  1169. emit_reg_reg(op,S_NO,right.location.register,left.location.register);
  1170. end
  1171. else
  1172. begin
  1173. if not(right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  1174. internalerror(200203246);
  1175. emit_ref_reg(op,S_NO,right.location.reference,left.location.register);
  1176. location_release(exprasmlist,right.location);
  1177. end;
  1178. end;
  1179. end
  1180. else
  1181. begin
  1182. { right.location=LOC_MMXREGISTER }
  1183. if (nodetype=subn) and (nf_swaped in flags) then
  1184. begin
  1185. emit_reg_reg(op,S_NO,left.location.register,right.location.register);
  1186. location_swap(left.location,right.location);
  1187. toggleflag(nf_swaped);
  1188. end
  1189. else
  1190. begin
  1191. emit_reg_reg(op,S_NO,right.location.register,left.location.register);
  1192. end;
  1193. end;
  1194. location_freetemp(exprasmlist,right.location);
  1195. location_release(exprasmlist,right.location);
  1196. if cmpop then
  1197. begin
  1198. location_freetemp(exprasmlist,left.location);
  1199. location_release(exprasmlist,left.location);
  1200. end;
  1201. set_result_location(cmpop,true);
  1202. end;
  1203. {$endif SUPPORT_MMX}
  1204. {*****************************************************************************
  1205. MUL
  1206. *****************************************************************************}
  1207. {$ifdef newra}
  1208. procedure ti386addnode.second_mul;
  1209. var r,r_eax:Tregister;
  1210. begin
  1211. {The location.register will be filled in later (JM)}
  1212. location_reset(location,LOC_REGISTER,OS_INT);
  1213. {Get a temp register and load the left value into it
  1214. and free the location.}
  1215. r:=rg.getregisterint(exprasmlist,OS_INT);
  1216. cg.a_load_loc_reg(exprasmlist,left.location,r);
  1217. location_release(exprasmlist,left.location);
  1218. {Allocate EAX.}
  1219. rg.getexplicitregisterint(exprasmlist,NR_EAX);
  1220. r_eax.enum:=R_INTREGISTER;
  1221. r_eax.number:=NR_EAX;
  1222. {Load the right value.}
  1223. cg.a_load_loc_reg(exprasmlist,right.location,r_eax);
  1224. location_release(exprasmlist,right.location);
  1225. {The mul instruction frees register r.}
  1226. rg.ungetregisterint(exprasmlist,r);
  1227. {Also allocate EDX, since it is also modified by a mul (JM).}
  1228. rg.getexplicitregisterint(exprasmlist,NR_EDX);
  1229. emit_reg(A_MUL,S_L,r);
  1230. {Free EDX}
  1231. r.enum:=R_INTREGISTER;
  1232. r.number:=NR_EDX;
  1233. rg.ungetregisterint(exprasmlist,r);
  1234. {Free EAX}
  1235. rg.ungetregisterint(exprasmlist,r_eax);
  1236. {Allocate a new register and store the result in EAX in it.}
  1237. location.register:=rg.getregisterint(exprasmlist,OS_INT);
  1238. emit_reg_reg(A_MOV,S_L,r_eax,location.register);
  1239. location_freetemp(exprasmlist,left.location);
  1240. location_freetemp(exprasmlist,right.location);
  1241. end;
  1242. {$else}
  1243. procedure ti386addnode.second_mul;
  1244. var popeax,popedx:boolean;
  1245. regstopush:Tsupregset;
  1246. r:Tregister;
  1247. begin
  1248. popeax:=false;
  1249. popedx:=false;
  1250. { here you need to free the symbol first }
  1251. { left.location and right.location must }
  1252. { only be freed when they are really released, }
  1253. { because the optimizer NEEDS correct regalloc }
  1254. { info!!! (JM) }
  1255. { the location.register will be filled in later (JM) }
  1256. location_reset(location,LOC_REGISTER,OS_INT);
  1257. regstopush := all_intregisters;
  1258. remove_non_regvars_from_loc(right.location,regstopush);
  1259. remove_non_regvars_from_loc(left.location,regstopush);
  1260. { now, regstopush does NOT contain EAX and/or EDX if they are }
  1261. { used in either the left or the right location, excepts if }
  1262. {they are regvars. It DOES contain them if they are used in }
  1263. { another location (JM) }
  1264. r.enum:=R_INTREGISTER;
  1265. if not(RS_EAX in rg.unusedregsint) and
  1266. (RS_EAX in regstopush) then
  1267. begin
  1268. r.number:=NR_EAX;
  1269. emit_reg(A_PUSH,S_L,r);
  1270. popeax:=true;
  1271. end;
  1272. if not(RS_EDX in rg.unusedregsint) and
  1273. (RS_EDX in regstopush) then
  1274. begin
  1275. r.number:=NR_EDX;
  1276. emit_reg(A_PUSH,S_L,r);
  1277. popedx:=true;
  1278. end;
  1279. { left.location can be R_EAX !!! }
  1280. rg.getexplicitregisterint(exprasmlist,NR_EDI);
  1281. { load the left value }
  1282. r.number:=NR_EDI;
  1283. cg.a_load_loc_reg(exprasmlist,left.location,r);
  1284. location_release(exprasmlist,left.location);
  1285. { allocate EAX }
  1286. r.number:=NR_EAX;
  1287. if RS_EAX in rg.unusedregsint then
  1288. exprasmList.concat(tai_regalloc.Alloc(r));
  1289. { load he right value }
  1290. cg.a_load_loc_reg(exprasmlist,right.location,r);
  1291. location_release(exprasmlist,right.location);
  1292. { allocate EAX if it isn't yet allocated (JM) }
  1293. if (RS_EAX in rg.unusedregsint) then
  1294. exprasmlist.concat(tai_regalloc.Alloc(r));
  1295. { also allocate EDX, since it is also modified by }
  1296. { a mul (JM) }
  1297. r.number:=NR_EDX;
  1298. if RS_EDX in rg.unusedregsint then
  1299. exprasmlist.concat(tai_regalloc.Alloc(r));
  1300. r.number:=NR_EDI;
  1301. emit_reg(A_MUL,S_L,r);
  1302. rg.ungetregisterint(exprasmlist,r);
  1303. r.enum:=R_INTREGISTER;
  1304. r.number:=NR_EDX;
  1305. if RS_EDX in rg.unusedregsint then
  1306. exprasmlist.concat(tai_regalloc.DeAlloc(r));
  1307. r.number:=NR_EAX;
  1308. if RS_EAX in rg.unusedregsint then
  1309. exprasmlist.concat(tai_regalloc.DeAlloc(r));
  1310. location.register:=rg.getregisterint(exprasmlist,OS_INT);
  1311. r.number:=NR_EAX;
  1312. emit_reg_reg(A_MOV,S_L,r,location.register);
  1313. r.number:=NR_EDX;
  1314. if popedx then
  1315. emit_reg(A_POP,S_L,r);
  1316. r.number:=NR_EAX;
  1317. if popeax then
  1318. emit_reg(A_POP,S_L,r);
  1319. location_freetemp(exprasmlist,left.location);
  1320. location_freetemp(exprasmlist,right.location);
  1321. end;
  1322. {$endif}
  1323. {*****************************************************************************
  1324. pass_2
  1325. *****************************************************************************}
  1326. procedure ti386addnode.pass_2;
  1327. { is also being used for xor, and "mul", "sub, or and comparative }
  1328. { operators }
  1329. var
  1330. pushedfpu,
  1331. mboverflow,cmpop : boolean;
  1332. op : tasmop;
  1333. opsize : topsize;
  1334. { true, if unsigned types are compared }
  1335. unsigned : boolean;
  1336. { is_in_dest if the result is put directly into }
  1337. { the resulting refernce or varregister }
  1338. {is_in_dest : boolean;}
  1339. { true, if for sets subtractions the extra not should generated }
  1340. extra_not : boolean;
  1341. begin
  1342. { to make it more readable, string and set (not smallset!) have their
  1343. own procedures }
  1344. case left.resulttype.def.deftype of
  1345. orddef :
  1346. begin
  1347. { handling boolean expressions }
  1348. if is_boolean(left.resulttype.def) and
  1349. is_boolean(right.resulttype.def) then
  1350. begin
  1351. second_addboolean;
  1352. exit;
  1353. end
  1354. { 64bit operations }
  1355. else if is_64bit(left.resulttype.def) then
  1356. begin
  1357. second_add64bit;
  1358. exit;
  1359. end;
  1360. end;
  1361. stringdef :
  1362. begin
  1363. second_addstring;
  1364. exit;
  1365. end;
  1366. setdef :
  1367. begin
  1368. { normalsets are already handled in pass1 }
  1369. if (tsetdef(left.resulttype.def).settype<>smallset) then
  1370. internalerror(200109041);
  1371. second_addsmallset;
  1372. exit;
  1373. end;
  1374. arraydef :
  1375. begin
  1376. {$ifdef SUPPORT_MMX}
  1377. if is_mmx_able_array(left.resulttype.def) then
  1378. begin
  1379. second_addmmx;
  1380. exit;
  1381. end;
  1382. {$endif SUPPORT_MMX}
  1383. end;
  1384. floatdef :
  1385. begin
  1386. second_addfloat;
  1387. exit;
  1388. end;
  1389. end;
  1390. { defaults }
  1391. {is_in_dest:=false;}
  1392. extra_not:=false;
  1393. mboverflow:=false;
  1394. cmpop:=false;
  1395. unsigned:=not(is_signed(left.resulttype.def)) or
  1396. not(is_signed(right.resulttype.def));
  1397. opsize:=def_opsize(left.resulttype.def);
  1398. pass_left_and_right(pushedfpu);
  1399. if (left.resulttype.def.deftype=pointerdef) or
  1400. (right.resulttype.def.deftype=pointerdef) or
  1401. (is_class_or_interface(right.resulttype.def) and is_class_or_interface(left.resulttype.def)) or
  1402. (left.resulttype.def.deftype=classrefdef) or
  1403. (left.resulttype.def.deftype=procvardef) or
  1404. ((left.resulttype.def.deftype=enumdef) and
  1405. (left.resulttype.def.size=4)) or
  1406. ((left.resulttype.def.deftype=orddef) and
  1407. (torddef(left.resulttype.def).typ in [s32bit,u32bit])) or
  1408. ((right.resulttype.def.deftype=orddef) and
  1409. (torddef(right.resulttype.def).typ in [s32bit,u32bit])) then
  1410. begin
  1411. case nodetype of
  1412. addn :
  1413. begin
  1414. op:=A_ADD;
  1415. mboverflow:=true;
  1416. end;
  1417. muln :
  1418. begin
  1419. if unsigned then
  1420. op:=A_MUL
  1421. else
  1422. op:=A_IMUL;
  1423. mboverflow:=true;
  1424. end;
  1425. subn :
  1426. begin
  1427. op:=A_SUB;
  1428. mboverflow:=true;
  1429. end;
  1430. ltn,lten,
  1431. gtn,gten,
  1432. equaln,unequaln :
  1433. begin
  1434. op:=A_CMP;
  1435. cmpop:=true;
  1436. end;
  1437. xorn :
  1438. op:=A_XOR;
  1439. orn :
  1440. op:=A_OR;
  1441. andn :
  1442. op:=A_AND;
  1443. else
  1444. internalerror(200304229);
  1445. end;
  1446. { filter MUL, which requires special handling }
  1447. if op=A_MUL then
  1448. begin
  1449. second_mul;
  1450. exit;
  1451. end;
  1452. { Convert flags to register first }
  1453. if (left.location.loc=LOC_FLAGS) then
  1454. location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],false);
  1455. if (right.location.loc=LOC_FLAGS) then
  1456. location_force_reg(exprasmlist,right.location,opsize_2_cgsize[opsize],false);
  1457. left_must_be_reg(opsize,false);
  1458. emit_generic_code(op,opsize,unsigned,extra_not,mboverflow);
  1459. location_freetemp(exprasmlist,right.location);
  1460. location_release(exprasmlist,right.location);
  1461. if cmpop and
  1462. (left.location.loc<>LOC_CREGISTER) then
  1463. begin
  1464. location_freetemp(exprasmlist,left.location);
  1465. location_release(exprasmlist,left.location);
  1466. end;
  1467. set_result_location(cmpop,unsigned);
  1468. end
  1469. { 8/16 bit enum,char,wchar types }
  1470. else
  1471. if ((left.resulttype.def.deftype=orddef) and
  1472. (torddef(left.resulttype.def).typ in [uchar,uwidechar])) or
  1473. ((left.resulttype.def.deftype=enumdef) and
  1474. ((left.resulttype.def.size=1) or
  1475. (left.resulttype.def.size=2))) then
  1476. begin
  1477. case nodetype of
  1478. ltn,lten,gtn,gten,
  1479. equaln,unequaln :
  1480. cmpop:=true;
  1481. else
  1482. internalerror(2003042210);
  1483. end;
  1484. left_must_be_reg(opsize,false);
  1485. emit_op_right_left(A_CMP,opsize);
  1486. location_freetemp(exprasmlist,right.location);
  1487. location_release(exprasmlist,right.location);
  1488. if left.location.loc<>LOC_CREGISTER then
  1489. begin
  1490. location_freetemp(exprasmlist,left.location);
  1491. location_release(exprasmlist,left.location);
  1492. end;
  1493. set_result_location(true,true);
  1494. end
  1495. else
  1496. internalerror(2003042211);
  1497. end;
  1498. begin
  1499. caddnode:=ti386addnode;
  1500. end.
  1501. {
  1502. $Log$
  1503. Revision 1.68 2003-05-26 19:38:28 peter
  1504. * generic fpc_shorstr_concat
  1505. + fpc_shortstr_append_shortstr optimization
  1506. Revision 1.67 2003/05/22 21:32:29 peter
  1507. * removed some unit dependencies
  1508. Revision 1.66 2003/04/26 09:12:55 peter
  1509. * add string returns in LOC_REFERENCE
  1510. Revision 1.65 2003/04/23 20:16:04 peter
  1511. + added currency support based on int64
  1512. + is_64bit for use in cg units instead of is_64bitint
  1513. * removed cgmessage from n386add, replace with internalerrors
  1514. Revision 1.64 2003/04/23 09:51:16 daniel
  1515. * Removed usage of edi in a lot of places when new register allocator used
  1516. + Added newra versions of g_concatcopy and secondadd_float
  1517. Revision 1.63 2003/04/22 23:50:23 peter
  1518. * firstpass uses expectloc
  1519. * checks if there are differences between the expectloc and
  1520. location.loc from secondpass in EXTDEBUG
  1521. Revision 1.62 2003/04/22 10:09:35 daniel
  1522. + Implemented the actual register allocator
  1523. + Scratch registers unavailable when new register allocator used
  1524. + maybe_save/maybe_restore unavailable when new register allocator used
  1525. Revision 1.61 2003/04/17 10:02:48 daniel
  1526. * Tweaked register allocate/deallocate positition to less interferences
  1527. are generated.
  1528. Revision 1.60 2003/03/28 19:16:57 peter
  1529. * generic constructor working for i386
  1530. * remove fixed self register
  1531. * esi added as address register for i386
  1532. Revision 1.59 2003/03/13 19:52:23 jonas
  1533. * and more new register allocator fixes (in the i386 code generator this
  1534. time). At least now the ppc cross compiler can compile the linux
  1535. system unit again, but I haven't tested it.
  1536. Revision 1.58 2003/03/08 20:36:41 daniel
  1537. + Added newra version of Ti386shlshrnode
  1538. + Added interference graph construction code
  1539. Revision 1.57 2003/03/08 13:59:17 daniel
  1540. * Work to handle new register notation in ag386nsm
  1541. + Added newra version of Ti386moddivnode
  1542. Revision 1.56 2003/03/08 10:53:48 daniel
  1543. * Created newra version of secondmul in n386add.pas
  1544. Revision 1.55 2003/02/19 22:00:15 daniel
  1545. * Code generator converted to new register notation
  1546. - Horribily outdated todo.txt removed
  1547. Revision 1.54 2003/01/13 18:37:44 daniel
  1548. * Work on register conversion
  1549. Revision 1.53 2003/01/08 18:43:57 daniel
  1550. * Tregister changed into a record
  1551. Revision 1.52 2002/11/25 17:43:26 peter
  1552. * splitted defbase in defutil,symutil,defcmp
  1553. * merged isconvertable and is_equal into compare_defs(_ext)
  1554. * made operator search faster by walking the list only once
  1555. Revision 1.51 2002/11/15 01:58:56 peter
  1556. * merged changes from 1.0.7 up to 04-11
  1557. - -V option for generating bug report tracing
  1558. - more tracing for option parsing
  1559. - errors for cdecl and high()
  1560. - win32 import stabs
  1561. - win32 records<=8 are returned in eax:edx (turned off by default)
  1562. - heaptrc update
  1563. - more info for temp management in .s file with EXTDEBUG
  1564. Revision 1.50 2002/10/20 13:11:27 jonas
  1565. * re-enabled optimized version of comparisons with the empty string that
  1566. I accidentally disabled in revision 1.26
  1567. Revision 1.49 2002/08/23 16:14:49 peter
  1568. * tempgen cleanup
  1569. * tt_noreuse temp type added that will be used in genentrycode
  1570. Revision 1.48 2002/08/14 18:41:48 jonas
  1571. - remove valuelow/valuehigh fields from tlocation, because they depend
  1572. on the endianess of the host operating system -> difficult to get
  1573. right. Use lo/hi(location.valueqword) instead (remember to use
  1574. valueqword and not value!!)
  1575. Revision 1.47 2002/08/11 14:32:29 peter
  1576. * renamed current_library to objectlibrary
  1577. Revision 1.46 2002/08/11 13:24:16 peter
  1578. * saving of asmsymbols in ppu supported
  1579. * asmsymbollist global is removed and moved into a new class
  1580. tasmlibrarydata that will hold the info of a .a file which
  1581. corresponds with a single module. Added librarydata to tmodule
  1582. to keep the library info stored for the module. In the future the
  1583. objectfiles will also be stored to the tasmlibrarydata class
  1584. * all getlabel/newasmsymbol and friends are moved to the new class
  1585. Revision 1.45 2002/07/26 11:17:52 jonas
  1586. * the optimization of converting a multiplication with a power of two to
  1587. a shl is moved from n386add/secondpass to nadd/resulttypepass
  1588. Revision 1.44 2002/07/20 11:58:00 florian
  1589. * types.pas renamed to defbase.pas because D6 contains a types
  1590. unit so this would conflicts if D6 programms are compiled
  1591. + Willamette/SSE2 instructions to assembler added
  1592. Revision 1.43 2002/07/11 14:41:32 florian
  1593. * start of the new generic parameter handling
  1594. Revision 1.42 2002/07/07 09:52:33 florian
  1595. * powerpc target fixed, very simple units can be compiled
  1596. * some basic stuff for better callparanode handling, far from being finished
  1597. Revision 1.41 2002/07/01 18:46:31 peter
  1598. * internal linker
  1599. * reorganized aasm layer
  1600. Revision 1.40 2002/07/01 16:23:55 peter
  1601. * cg64 patch
  1602. * basics for currency
  1603. * asnode updates for class and interface (not finished)
  1604. Revision 1.39 2002/05/18 13:34:22 peter
  1605. * readded missing revisions
  1606. Revision 1.38 2002/05/16 19:46:51 carl
  1607. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  1608. + try to fix temp allocation (still in ifdef)
  1609. + generic constructor calls
  1610. + start of tassembler / tmodulebase class cleanup
  1611. Revision 1.36 2002/05/13 19:54:37 peter
  1612. * removed n386ld and n386util units
  1613. * maybe_save/maybe_restore added instead of the old maybe_push
  1614. Revision 1.35 2002/05/12 16:53:17 peter
  1615. * moved entry and exitcode to ncgutil and cgobj
  1616. * foreach gets extra argument for passing local data to the
  1617. iterator function
  1618. * -CR checks also class typecasts at runtime by changing them
  1619. into as
  1620. * fixed compiler to cycle with the -CR option
  1621. * fixed stabs with elf writer, finally the global variables can
  1622. be watched
  1623. * removed a lot of routines from cga unit and replaced them by
  1624. calls to cgobj
  1625. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  1626. u32bit then the other is typecasted also to u32bit without giving
  1627. a rangecheck warning/error.
  1628. * fixed pascal calling method with reversing also the high tree in
  1629. the parast, detected by tcalcst3 test
  1630. Revision 1.34 2002/04/25 20:16:40 peter
  1631. * moved more routines from cga/n386util
  1632. Revision 1.33 2002/04/05 15:09:13 jonas
  1633. * fixed web bug 1915
  1634. Revision 1.32 2002/04/04 19:06:10 peter
  1635. * removed unused units
  1636. * use tlocation.size in cg.a_*loc*() routines
  1637. Revision 1.31 2002/04/02 17:11:35 peter
  1638. * tlocation,treference update
  1639. * LOC_CONSTANT added for better constant handling
  1640. * secondadd splitted in multiple routines
  1641. * location_force_reg added for loading a location to a register
  1642. of a specified size
  1643. * secondassignment parses now first the right and then the left node
  1644. (this is compatible with Kylix). This saves a lot of push/pop especially
  1645. with string operations
  1646. * adapted some routines to use the new cg methods
  1647. Revision 1.29 2002/03/04 19:10:13 peter
  1648. * removed compiler warnings
  1649. }