n386add.pas 60 KB

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