n386add.pas 63 KB

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