n386add.pas 108 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337
  1. {
  2. $Id$
  3. Copyright (c) 2000 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 defines.inc}
  20. interface
  21. uses
  22. nadd,cpubase;
  23. type
  24. ti386addnode = class(taddnode)
  25. procedure pass_2;override;
  26. function getresflags(unsigned : boolean) : tresflags;
  27. procedure SetResultLocation(cmpop,unsigned : boolean);
  28. procedure addstring;
  29. procedure addset;
  30. end;
  31. implementation
  32. uses
  33. globtype,systems,
  34. cutils,verbose,globals,
  35. symconst,symdef,aasm,types,
  36. hcodegen,temp_gen,pass_2,
  37. cpuasm,
  38. node,ncon,nset,
  39. cgai386,n386util,tgcpu;
  40. function ti386addnode.getresflags(unsigned : boolean) : tresflags;
  41. begin
  42. if not(unsigned) then
  43. begin
  44. if nf_swaped in flags then
  45. case nodetype of
  46. equaln : getresflags:=F_E;
  47. unequaln : getresflags:=F_NE;
  48. ltn : getresflags:=F_G;
  49. lten : getresflags:=F_GE;
  50. gtn : getresflags:=F_L;
  51. gten : getresflags:=F_LE;
  52. end
  53. else
  54. case nodetype of
  55. equaln : getresflags:=F_E;
  56. unequaln : getresflags:=F_NE;
  57. ltn : getresflags:=F_L;
  58. lten : getresflags:=F_LE;
  59. gtn : getresflags:=F_G;
  60. gten : getresflags:=F_GE;
  61. end;
  62. end
  63. else
  64. begin
  65. if nf_swaped in flags then
  66. case nodetype of
  67. equaln : getresflags:=F_E;
  68. unequaln : getresflags:=F_NE;
  69. ltn : getresflags:=F_A;
  70. lten : getresflags:=F_AE;
  71. gtn : getresflags:=F_B;
  72. gten : getresflags:=F_BE;
  73. end
  74. else
  75. case nodetype of
  76. equaln : getresflags:=F_E;
  77. unequaln : getresflags:=F_NE;
  78. ltn : getresflags:=F_B;
  79. lten : getresflags:=F_BE;
  80. gtn : getresflags:=F_A;
  81. gten : getresflags:=F_AE;
  82. end;
  83. end;
  84. end;
  85. procedure ti386addnode.SetResultLocation(cmpop,unsigned : boolean);
  86. begin
  87. { remove temporary location if not a set or string }
  88. { that's a bad hack (FK) who did this ? }
  89. if (left.resulttype.def.deftype<>stringdef) and
  90. ((left.resulttype.def.deftype<>setdef) or (tsetdef(left.resulttype.def).settype=smallset)) and
  91. (left.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  92. ungetiftemp(left.location.reference);
  93. if (right.resulttype.def.deftype<>stringdef) and
  94. ((right.resulttype.def.deftype<>setdef) or (tsetdef(right.resulttype.def).settype=smallset)) and
  95. (right.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  96. ungetiftemp(right.location.reference);
  97. { in case of comparison operation the put result in the flags }
  98. if cmpop then
  99. begin
  100. clear_location(location);
  101. location.loc:=LOC_FLAGS;
  102. location.resflags:=getresflags(unsigned);
  103. end;
  104. end;
  105. {*****************************************************************************
  106. Addstring
  107. *****************************************************************************}
  108. procedure ti386addnode.addstring;
  109. var
  110. {$ifdef newoptimizations2}
  111. l: tasmlabel;
  112. hreg: tregister;
  113. href2: preference;
  114. oldregisterdef: boolean;
  115. {$endif newoptimizations2}
  116. pushedregs : tpushed;
  117. href : treference;
  118. pushed,
  119. cmpop : boolean;
  120. regstopush : byte;
  121. begin
  122. { string operations are not commutative }
  123. if nf_swaped in flags then
  124. swapleftright;
  125. case tstringdef(left.resulttype.def).string_typ of
  126. st_ansistring:
  127. begin
  128. case nodetype of
  129. addn:
  130. begin
  131. cmpop:=false;
  132. secondpass(left);
  133. { to avoid problem with maybe_push and restore }
  134. set_location(location,left.location);
  135. pushed:=maybe_push(right.registers32,self,false);
  136. secondpass(right);
  137. if pushed then
  138. begin
  139. restore(self,false);
  140. set_location(left.location,location);
  141. end;
  142. { get the temp location, must be done before regs are
  143. released/pushed because after the release the regs are
  144. still used for the push (PFV) }
  145. clear_location(location);
  146. location.loc:=LOC_MEM;
  147. gettempansistringreference(location.reference);
  148. decrstringref(cansistringtype.def,location.reference);
  149. { release used registers }
  150. del_location(right.location);
  151. del_location(left.location);
  152. { push the still used registers }
  153. pushusedregisters(pushedregs,$ff);
  154. { push data }
  155. emitpushreferenceaddr(location.reference);
  156. emit_push_loc(right.location);
  157. emit_push_loc(left.location);
  158. saveregvars($ff);
  159. emitcall('FPC_ANSISTR_CONCAT');
  160. popusedregisters(pushedregs);
  161. maybe_loadself;
  162. ungetiftempansi(left.location.reference);
  163. ungetiftempansi(right.location.reference);
  164. end;
  165. ltn,lten,gtn,gten,
  166. equaln,unequaln:
  167. begin
  168. cmpop:=true;
  169. if (nodetype in [equaln,unequaln]) and
  170. (left.nodetype=stringconstn) and
  171. (tstringconstnode(left).len=0) then
  172. begin
  173. secondpass(right);
  174. { release used registers }
  175. del_location(right.location);
  176. del_location(left.location);
  177. case right.location.loc of
  178. LOC_REFERENCE,LOC_MEM:
  179. emit_const_ref(A_CMP,S_L,0,newreference(right.location.reference));
  180. LOC_REGISTER,LOC_CREGISTER:
  181. emit_const_reg(A_CMP,S_L,0,right.location.register);
  182. end;
  183. ungetiftempansi(left.location.reference);
  184. ungetiftempansi(right.location.reference);
  185. end
  186. else if (nodetype in [equaln,unequaln]) and
  187. (right.nodetype=stringconstn) and
  188. (tstringconstnode(right).len=0) then
  189. begin
  190. secondpass(left);
  191. { release used registers }
  192. del_location(right.location);
  193. del_location(left.location);
  194. case right.location.loc of
  195. LOC_REFERENCE,LOC_MEM:
  196. emit_const_ref(A_CMP,S_L,0,newreference(left.location.reference));
  197. LOC_REGISTER,LOC_CREGISTER:
  198. emit_const_reg(A_CMP,S_L,0,left.location.register);
  199. end;
  200. ungetiftempansi(left.location.reference);
  201. ungetiftempansi(right.location.reference);
  202. end
  203. else
  204. begin
  205. secondpass(left);
  206. pushed:=maybe_push(right.registers32,left,false);
  207. secondpass(right);
  208. if pushed then
  209. restore(left,false);
  210. { release used registers }
  211. del_location(right.location);
  212. del_location(left.location);
  213. { push the still used registers }
  214. pushusedregisters(pushedregs,$ff);
  215. { push data }
  216. case right.location.loc of
  217. LOC_REFERENCE,LOC_MEM:
  218. emit_push_mem(right.location.reference);
  219. LOC_REGISTER,LOC_CREGISTER:
  220. emit_reg(A_PUSH,S_L,right.location.register);
  221. end;
  222. case left.location.loc of
  223. LOC_REFERENCE,LOC_MEM:
  224. emit_push_mem(left.location.reference);
  225. LOC_REGISTER,LOC_CREGISTER:
  226. emit_reg(A_PUSH,S_L,left.location.register);
  227. end;
  228. saveregvars($ff);
  229. emitcall('FPC_ANSISTR_COMPARE');
  230. emit_reg_reg(A_OR,S_L,R_EAX,R_EAX);
  231. popusedregisters(pushedregs);
  232. maybe_loadself;
  233. ungetiftempansi(left.location.reference);
  234. ungetiftempansi(right.location.reference);
  235. end;
  236. end;
  237. end;
  238. { the result of ansicompare is signed }
  239. SetResultLocation(cmpop,false);
  240. end;
  241. st_shortstring:
  242. begin
  243. case nodetype of
  244. addn:
  245. begin
  246. cmpop:=false;
  247. secondpass(left);
  248. { if str_concat is set in expr
  249. s:=s+ ... no need to create a temp string (PM) }
  250. { the tempstring can also come from a typeconversion }
  251. { or a function result, so simply check for a }
  252. { temp of 256 bytes(JM) }
  253. if not(istemp(left.location.reference) and
  254. (getsizeoftemp(left.location.reference) = 256)) and
  255. not(nf_use_strconcat in flags) then
  256. begin
  257. { can only reference be }
  258. { string in register would be funny }
  259. { therefore produce a temporary string }
  260. gettempofsizereference(256,href);
  261. copyshortstring(href,left.location.reference,255,false,true);
  262. { release the registers }
  263. { done by copyshortstring now (JM) }
  264. { del_reference(left.location.reference); }
  265. ungetiftemp(left.location.reference);
  266. { does not hurt: }
  267. clear_location(left.location);
  268. left.location.loc:=LOC_MEM;
  269. left.location.reference:=href;
  270. {$ifdef newoptimizations2}
  271. { length of temp string = 255 (JM) }
  272. { *** redefining a type is not allowed!! (thanks, Pierre) }
  273. { also problem with constant string! }
  274. tstringdef(left.resulttype.def).len := 255;
  275. {$endif newoptimizations2}
  276. end;
  277. secondpass(right);
  278. {$ifdef newoptimizations2}
  279. { special case for string := string + char (JM) }
  280. { needs string length stuff from above! }
  281. hreg := R_NO;
  282. if is_shortstring(left.resulttype.def) and
  283. is_char(right.resulttype.def) then
  284. begin
  285. getlabel(l);
  286. getexplicitregister32(R_EDI);
  287. { load the current string length }
  288. emit_ref_reg(A_MOVZX,S_BL,
  289. newreference(left.location.reference),R_EDI);
  290. { is it already maximal? }
  291. emit_const_reg(A_CMP,S_L,
  292. tstringdef(left.resulttype.def).len,R_EDI);
  293. emitjmp(C_E,l);
  294. { no, so add the new character }
  295. { is it a constant char? }
  296. if (right.nodetype <> ordconstn) then
  297. { no, make sure it is in a register }
  298. if right.location.loc in [LOC_REFERENCE,LOC_MEM] then
  299. begin
  300. { free the registers of right }
  301. del_reference(right.location.reference);
  302. { get register for the char }
  303. hreg := reg32toreg8(getregister32);
  304. emit_ref_reg(A_MOV,S_B,
  305. newreference(right.location.reference),
  306. hreg);
  307. { I don't think a temp char exists, but it won't hurt (JM) }
  308. ungetiftemp(right.location.reference);
  309. end
  310. else hreg := right.location.register;
  311. href2 := newreference(left.location.reference);
  312. { we need a new reference to store the character }
  313. { at the end of the string. Check if the base or }
  314. { index register is still free }
  315. if (left.location.reference.base <> R_NO) and
  316. (left.location.reference.index <> R_NO) then
  317. begin
  318. { they're not free, so add the base reg to }
  319. { the string length (since the index can }
  320. { have a scalefactor) and use EDI as base }
  321. emit_reg_reg(A_ADD,S_L,
  322. left.location.reference.base,R_EDI);
  323. href2^.base := R_EDI;
  324. end
  325. else
  326. { at least one is still free, so put EDI there }
  327. if href2^.base = R_NO then
  328. href2^.base := R_EDI
  329. else
  330. begin
  331. href2^.index := R_EDI;
  332. href2^.scalefactor := 1;
  333. end;
  334. { we need to be one position after the last char }
  335. inc(href2^.offset);
  336. { increase the string length }
  337. emit_ref(A_INC,S_B,newreference(left.location.reference));
  338. { and store the character at the end of the string }
  339. if (right.nodetype <> ordconstn) then
  340. begin
  341. { no new_reference(href2) because it's only }
  342. { used once (JM) }
  343. emit_reg_ref(A_MOV,S_B,hreg,href2);
  344. ungetregister(hreg);
  345. end
  346. else
  347. emit_const_ref(A_MOV,S_B,right.value,href2);
  348. emitlab(l);
  349. ungetregister32(R_EDI);
  350. end
  351. else
  352. begin
  353. {$endif newoptimizations2}
  354. { on the right we do not need the register anymore too }
  355. { Instead of releasing them already, simply do not }
  356. { push them (so the release is in the right place, }
  357. { because emitpushreferenceaddr doesn't need extra }
  358. { registers) (JM) }
  359. regstopush := $ff;
  360. remove_non_regvars_from_loc(right.location,
  361. regstopush);
  362. pushusedregisters(pushedregs,regstopush);
  363. { push the maximum possible length of the result }
  364. {$ifdef newoptimizations2}
  365. { string (could be < 255 chars now) (JM) }
  366. emit_const(A_PUSH,S_L,
  367. tstringdef(left.resulttype.def).len);
  368. {$endif newoptimizations2}
  369. emitpushreferenceaddr(left.location.reference);
  370. { the optimizer can more easily put the }
  371. { deallocations in the right place if it happens }
  372. { too early than when it happens too late (if }
  373. { the pushref needs a "lea (..),edi; push edi") }
  374. del_reference(right.location.reference);
  375. emitpushreferenceaddr(right.location.reference);
  376. saveregvars(regstopush);
  377. {$ifdef newoptimizations2}
  378. emitcall('FPC_SHORTSTR_CONCAT_LEN');
  379. {$else newoptimizations2}
  380. emitcall('FPC_SHORTSTR_CONCAT');
  381. {$endif newoptimizations2}
  382. ungetiftemp(right.location.reference);
  383. maybe_loadself;
  384. popusedregisters(pushedregs);
  385. {$ifdef newoptimizations2}
  386. end;
  387. {$endif newoptimizations2}
  388. set_location(location,left.location);
  389. end;
  390. ltn,lten,gtn,gten,
  391. equaln,unequaln :
  392. begin
  393. cmpop:=true;
  394. { generate better code for s='' and s<>'' }
  395. if (nodetype in [equaln,unequaln]) and
  396. (((left.nodetype=stringconstn) and (str_length(left)=0)) or
  397. ((right.nodetype=stringconstn) and (str_length(right)=0))) then
  398. begin
  399. secondpass(left);
  400. { are too few registers free? }
  401. pushed:=maybe_push(right.registers32,left,false);
  402. secondpass(right);
  403. if pushed then
  404. restore(left,false);
  405. { only one node can be stringconstn }
  406. { else pass 1 would have evaluted }
  407. { this node }
  408. if left.nodetype=stringconstn then
  409. emit_const_ref(
  410. A_CMP,S_B,0,newreference(right.location.reference))
  411. else
  412. emit_const_ref(
  413. A_CMP,S_B,0,newreference(left.location.reference));
  414. del_reference(right.location.reference);
  415. del_reference(left.location.reference);
  416. end
  417. else
  418. begin
  419. pushusedregisters(pushedregs,$ff);
  420. secondpass(left);
  421. emitpushreferenceaddr(left.location.reference);
  422. del_reference(left.location.reference);
  423. secondpass(right);
  424. emitpushreferenceaddr(right.location.reference);
  425. del_reference(right.location.reference);
  426. saveregvars($ff);
  427. emitcall('FPC_SHORTSTR_COMPARE');
  428. maybe_loadself;
  429. popusedregisters(pushedregs);
  430. end;
  431. ungetiftemp(left.location.reference);
  432. ungetiftemp(right.location.reference);
  433. end;
  434. else CGMessage(type_e_mismatch);
  435. end;
  436. SetResultLocation(cmpop,true);
  437. end;
  438. end;
  439. end;
  440. {*****************************************************************************
  441. Addset
  442. *****************************************************************************}
  443. procedure ti386addnode.addset;
  444. var
  445. createset,
  446. cmpop,
  447. pushed : boolean;
  448. href : treference;
  449. pushedregs : tpushed;
  450. regstopush: byte;
  451. begin
  452. cmpop:=false;
  453. { not commutative }
  454. if nf_swaped in flags then
  455. swapleftright;
  456. { optimize first loading of a set }
  457. {$ifdef usecreateset}
  458. if (right.nodetype=setelementn) and
  459. not(assigned(right.right)) and
  460. is_emptyset(left) then
  461. createset:=true
  462. else
  463. {$endif}
  464. begin
  465. createset:=false;
  466. secondpass(left);
  467. end;
  468. { are too few registers free? }
  469. pushed:=maybe_push(right.registers32,left,false);
  470. secondpass(right);
  471. if codegenerror then
  472. exit;
  473. if pushed then
  474. restore(left,false);
  475. set_location(location,left.location);
  476. { handle operations }
  477. case nodetype of
  478. equaln,
  479. unequaln
  480. ,lten, gten
  481. : begin
  482. cmpop:=true;
  483. del_location(left.location);
  484. del_location(right.location);
  485. pushusedregisters(pushedregs,$ff);
  486. If (nodetype in [equaln, unequaln, lten]) Then
  487. Begin
  488. emitpushreferenceaddr(right.location.reference);
  489. emitpushreferenceaddr(left.location.reference);
  490. End
  491. Else {gten = lten, if the arguments are reversed}
  492. Begin
  493. emitpushreferenceaddr(left.location.reference);
  494. emitpushreferenceaddr(right.location.reference);
  495. End;
  496. saveregvars($ff);
  497. Case nodetype of
  498. equaln, unequaln:
  499. emitcall('FPC_SET_COMP_SETS');
  500. lten, gten:
  501. Begin
  502. emitcall('FPC_SET_CONTAINS_SETS');
  503. { we need a jne afterwards, not a jnbe/jnae }
  504. nodetype := equaln;
  505. End;
  506. End;
  507. maybe_loadself;
  508. popusedregisters(pushedregs);
  509. ungetiftemp(left.location.reference);
  510. ungetiftemp(right.location.reference);
  511. end;
  512. addn : begin
  513. { add can be an other SET or Range or Element ! }
  514. { del_location(right.location);
  515. done in pushsetelement below PM
  516. And someone added it again because those registers must
  517. not be pushed by the pushusedregisters, however this
  518. breaks the optimizer (JM)
  519. del_location(right.location);
  520. pushusedregisters(pushedregs,$ff);}
  521. regstopush := $ff;
  522. remove_non_regvars_from_loc(right.location,regstopush);
  523. remove_non_regvars_from_loc(left.location,regstopush);
  524. pushusedregisters(pushedregs,regstopush);
  525. { this is still right before the instruction that uses }
  526. { left.location, but that can be fixed by the }
  527. { optimizer. There must never be an additional }
  528. { between the release and the use, because that is not }
  529. { detected/fixed. As Pierre said above, right.loc }
  530. { will be released in pushsetelement (JM) }
  531. del_location(left.location);
  532. href.symbol:=nil;
  533. gettempofsizereference(32,href);
  534. if createset then
  535. begin
  536. pushsetelement(tunarynode(right).left);
  537. emitpushreferenceaddr(href);
  538. saveregvars(regstopush);
  539. emitcall('FPC_SET_CREATE_ELEMENT');
  540. end
  541. else
  542. begin
  543. { add a range or a single element? }
  544. if right.nodetype=setelementn then
  545. begin
  546. concatcopy(left.location.reference,href,32,false,false);
  547. if assigned(tbinarynode(right).right) then
  548. begin
  549. pushsetelement(tbinarynode(right).right);
  550. pushsetelement(tunarynode(right).left);
  551. emitpushreferenceaddr(href);
  552. saveregvars(regstopush);
  553. emitcall('FPC_SET_SET_RANGE');
  554. end
  555. else
  556. begin
  557. pushsetelement(tunarynode(right).left);
  558. emitpushreferenceaddr(href);
  559. saveregvars(regstopush);
  560. emitcall('FPC_SET_SET_BYTE');
  561. end;
  562. end
  563. else
  564. begin
  565. { must be an other set }
  566. emitpushreferenceaddr(href);
  567. emitpushreferenceaddr(right.location.reference);
  568. emitpushreferenceaddr(left.location.reference);
  569. saveregvars(regstopush);
  570. emitcall('FPC_SET_ADD_SETS');
  571. end;
  572. end;
  573. maybe_loadself;
  574. popusedregisters(pushedregs);
  575. ungetiftemp(left.location.reference);
  576. ungetiftemp(right.location.reference);
  577. location.loc:=LOC_MEM;
  578. location.reference:=href;
  579. end;
  580. subn,
  581. symdifn,
  582. muln : begin
  583. { Find out which registers have to pushed (JM) }
  584. regstopush := $ff;
  585. remove_non_regvars_from_loc(left.location,regstopush);
  586. remove_non_regvars_from_loc(right.location,regstopush);
  587. { Push them (JM) }
  588. pushusedregisters(pushedregs,regstopush);
  589. href.symbol:=nil;
  590. gettempofsizereference(32,href);
  591. emitpushreferenceaddr(href);
  592. { Release the registers right before they're used, }
  593. { see explanation in cgai386.pas:loadansistring for }
  594. { info why this is done right before the push (JM) }
  595. del_location(right.location);
  596. emitpushreferenceaddr(right.location.reference);
  597. { The same here }
  598. del_location(left.location);
  599. emitpushreferenceaddr(left.location.reference);
  600. saveregvars(regstopush);
  601. case nodetype of
  602. subn : emitcall('FPC_SET_SUB_SETS');
  603. symdifn : emitcall('FPC_SET_SYMDIF_SETS');
  604. muln : emitcall('FPC_SET_MUL_SETS');
  605. end;
  606. maybe_loadself;
  607. popusedregisters(pushedregs);
  608. ungetiftemp(left.location.reference);
  609. ungetiftemp(right.location.reference);
  610. location.loc:=LOC_MEM;
  611. location.reference:=href;
  612. end;
  613. else
  614. CGMessage(type_e_mismatch);
  615. end;
  616. SetResultLocation(cmpop,true);
  617. end;
  618. {*****************************************************************************
  619. pass_2
  620. *****************************************************************************}
  621. procedure ti386addnode.pass_2;
  622. { is also being used for xor, and "mul", "sub, or and comparative }
  623. { operators }
  624. label do_normal;
  625. var
  626. hregister,hregister2 : tregister;
  627. noswap,popeax,popedx,
  628. pushed,mboverflow,cmpop : boolean;
  629. op,op2 : tasmop;
  630. resflags : tresflags;
  631. otl,ofl : tasmlabel;
  632. power : longint;
  633. opsize : topsize;
  634. hl4: tasmlabel;
  635. hr : preference;
  636. { true, if unsigned types are compared }
  637. unsigned : boolean;
  638. { true, if a small set is handled with the longint code }
  639. is_set : boolean;
  640. { is_in_dest if the result is put directly into }
  641. { the resulting refernce or varregister }
  642. is_in_dest : boolean;
  643. { true, if for sets subtractions the extra not should generated }
  644. extra_not : boolean;
  645. {$ifdef SUPPORT_MMX}
  646. mmxbase : tmmxtype;
  647. {$endif SUPPORT_MMX}
  648. pushedreg : tpushed;
  649. hloc : tlocation;
  650. regstopush: byte;
  651. procedure firstjmp64bitcmp;
  652. var
  653. oldnodetype : tnodetype;
  654. begin
  655. { the jump the sequence is a little bit hairy }
  656. case nodetype of
  657. ltn,gtn:
  658. begin
  659. emitjmp(flag_2_cond[getresflags(unsigned)],truelabel);
  660. { cheat a little bit for the negative test }
  661. toggleflag(nf_swaped);
  662. emitjmp(flag_2_cond[getresflags(unsigned)],falselabel);
  663. toggleflag(nf_swaped);
  664. end;
  665. lten,gten:
  666. begin
  667. oldnodetype:=nodetype;
  668. if nodetype=lten then
  669. nodetype:=ltn
  670. else
  671. nodetype:=gtn;
  672. emitjmp(flag_2_cond[getresflags(unsigned)],truelabel);
  673. { cheat for the negative test }
  674. if nodetype=ltn then
  675. nodetype:=gtn
  676. else
  677. nodetype:=ltn;
  678. emitjmp(flag_2_cond[getresflags(unsigned)],falselabel);
  679. nodetype:=oldnodetype;
  680. end;
  681. equaln:
  682. emitjmp(C_NE,falselabel);
  683. unequaln:
  684. emitjmp(C_NE,truelabel);
  685. end;
  686. end;
  687. procedure secondjmp64bitcmp;
  688. begin
  689. { the jump the sequence is a little bit hairy }
  690. case nodetype of
  691. ltn,gtn,lten,gten:
  692. begin
  693. { the comparisaion of the low dword have to be }
  694. { always unsigned! }
  695. emitjmp(flag_2_cond[getresflags(true)],truelabel);
  696. emitjmp(C_None,falselabel);
  697. end;
  698. equaln:
  699. begin
  700. emitjmp(C_NE,falselabel);
  701. emitjmp(C_None,truelabel);
  702. end;
  703. unequaln:
  704. begin
  705. emitjmp(C_NE,truelabel);
  706. emitjmp(C_None,falselabel);
  707. end;
  708. end;
  709. end;
  710. begin
  711. { to make it more readable, string and set (not smallset!) have their
  712. own procedures }
  713. case left.resulttype.def.deftype of
  714. stringdef : begin
  715. addstring;
  716. exit;
  717. end;
  718. setdef : begin
  719. { normalsets are handled separate }
  720. if not(tsetdef(left.resulttype.def).settype=smallset) then
  721. begin
  722. addset;
  723. exit;
  724. end;
  725. end;
  726. end;
  727. { defaults }
  728. unsigned:=false;
  729. is_in_dest:=false;
  730. extra_not:=false;
  731. noswap:=false;
  732. opsize:=S_L;
  733. { are we a (small)set, must be set here because the side can be
  734. swapped ! (PFV) }
  735. is_set:=(left.resulttype.def.deftype=setdef);
  736. { calculate the operator which is more difficult }
  737. firstcomplex(self);
  738. { handling boolean expressions extra: }
  739. if is_boolean(left.resulttype.def) and
  740. is_boolean(right.resulttype.def) then
  741. begin
  742. if (torddef(left.resulttype.def).typ=bool8bit) or
  743. (torddef(right.resulttype.def).typ=bool8bit) then
  744. opsize:=S_B
  745. else
  746. if (torddef(left.resulttype.def).typ=bool16bit) or
  747. (torddef(right.resulttype.def).typ=bool16bit) then
  748. opsize:=S_W
  749. else
  750. opsize:=S_L;
  751. if (cs_full_boolean_eval in aktlocalswitches) or
  752. (nodetype in
  753. [unequaln,ltn,lten,gtn,gten,equaln,xorn]) then
  754. begin
  755. if left.nodetype=ordconstn then
  756. swapleftright;
  757. if left.location.loc=LOC_JUMP then
  758. begin
  759. otl:=truelabel;
  760. getlabel(truelabel);
  761. ofl:=falselabel;
  762. getlabel(falselabel);
  763. end;
  764. secondpass(left);
  765. { if in flags then copy first to register, because the
  766. flags can be destroyed }
  767. case left.location.loc of
  768. LOC_FLAGS:
  769. locflags2reg(left.location,opsize);
  770. LOC_JUMP:
  771. locjump2reg(left.location,opsize, otl, ofl);
  772. end;
  773. set_location(location,left.location);
  774. pushed:=maybe_push(right.registers32,self,false);
  775. if right.location.loc=LOC_JUMP then
  776. begin
  777. otl:=truelabel;
  778. getlabel(truelabel);
  779. ofl:=falselabel;
  780. getlabel(falselabel);
  781. end;
  782. secondpass(right);
  783. if pushed then
  784. begin
  785. restore(self,false);
  786. set_location(left.location,location);
  787. end;
  788. case right.location.loc of
  789. LOC_FLAGS:
  790. locflags2reg(right.location,opsize);
  791. LOC_JUMP:
  792. locjump2reg(right.location,opsize,otl,ofl);
  793. end;
  794. goto do_normal;
  795. end;
  796. case nodetype of
  797. andn,
  798. orn : begin
  799. clear_location(location);
  800. location.loc:=LOC_JUMP;
  801. cmpop:=false;
  802. case nodetype of
  803. andn : begin
  804. otl:=truelabel;
  805. getlabel(truelabel);
  806. secondpass(left);
  807. maketojumpbool(left);
  808. emitlab(truelabel);
  809. truelabel:=otl;
  810. end;
  811. orn : begin
  812. ofl:=falselabel;
  813. getlabel(falselabel);
  814. secondpass(left);
  815. maketojumpbool(left);
  816. emitlab(falselabel);
  817. falselabel:=ofl;
  818. end;
  819. else
  820. CGMessage(type_e_mismatch);
  821. end;
  822. secondpass(right);
  823. maketojumpbool(right);
  824. end;
  825. else
  826. CGMessage(type_e_mismatch);
  827. end
  828. end
  829. else
  830. begin
  831. { in case of constant put it to the left }
  832. if (left.nodetype=ordconstn) then
  833. swapleftright;
  834. secondpass(left);
  835. { this will be complicated as
  836. a lot of code below assumes that
  837. location and left.location are the same }
  838. {$ifdef test_dest_loc}
  839. if dest_loc_known and (dest_loc_tree=p) and
  840. ((dest_loc.loc=LOC_REGISTER) or (dest_loc.loc=LOC_CREGISTER)) then
  841. begin
  842. set_location(location,dest_loc);
  843. in_dest_loc:=true;
  844. is_in_dest:=true;
  845. end
  846. else
  847. {$endif test_dest_loc}
  848. set_location(location,left.location);
  849. { are too few registers free? }
  850. pushed:=maybe_push(right.registers32,self,is_64bitint(left.resulttype.def));
  851. secondpass(right);
  852. if pushed then
  853. begin
  854. restore(self,is_64bitint(left.resulttype.def));
  855. set_location(left.location,location);
  856. end;
  857. if (left.resulttype.def.deftype=pointerdef) or
  858. (right.resulttype.def.deftype=pointerdef) or
  859. (is_class_or_interface(right.resulttype.def) and is_class_or_interface(left.resulttype.def)) or
  860. (left.resulttype.def.deftype=classrefdef) or
  861. (left.resulttype.def.deftype=procvardef) or
  862. ((left.resulttype.def.deftype=enumdef) and
  863. (left.resulttype.def.size=4)) or
  864. ((left.resulttype.def.deftype=orddef) and
  865. (torddef(left.resulttype.def).typ=s32bit)) or
  866. ((right.resulttype.def.deftype=orddef) and
  867. (torddef(right.resulttype.def).typ=s32bit)) or
  868. ((left.resulttype.def.deftype=orddef) and
  869. (torddef(left.resulttype.def).typ=u32bit)) or
  870. ((right.resulttype.def.deftype=orddef) and
  871. (torddef(right.resulttype.def).typ=u32bit)) or
  872. { as well as small sets }
  873. is_set then
  874. begin
  875. do_normal:
  876. mboverflow:=false;
  877. cmpop:=false;
  878. unsigned := not(is_signed(left.resulttype.def)) or
  879. not(is_signed(right.resulttype.def));
  880. case nodetype of
  881. addn : begin
  882. { this is a really ugly hack!!!!!!!!!! }
  883. { this could be done later using EDI }
  884. { as it is done for subn }
  885. { instead of two registers!!!! }
  886. if is_set then
  887. begin
  888. { adding elements is not commutative }
  889. if (nf_swaped in flags) and (left.nodetype=setelementn) then
  890. swapleftright;
  891. { are we adding set elements ? }
  892. if right.nodetype=setelementn then
  893. begin
  894. { no range support for smallsets! }
  895. if assigned(tsetelementnode(right).right) then
  896. internalerror(43244);
  897. { bts requires both elements to be registers }
  898. if left.location.loc in [LOC_MEM,LOC_REFERENCE] then
  899. begin
  900. ungetiftemp(left.location.reference);
  901. del_location(left.location);
  902. {!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
  903. hregister:=getregister32;
  904. emit_ref_reg(A_MOV,opsize,
  905. newreference(left.location.reference),hregister);
  906. clear_location(left.location);
  907. left.location.loc:=LOC_REGISTER;
  908. left.location.register:=hregister;
  909. set_location(location,left.location);
  910. end;
  911. if right.location.loc in [LOC_MEM,LOC_REFERENCE] then
  912. begin
  913. ungetiftemp(right.location.reference);
  914. del_location(right.location);
  915. hregister:=getregister32;
  916. emit_ref_reg(A_MOV,opsize,
  917. newreference(right.location.reference),hregister);
  918. clear_location(right.location);
  919. right.location.loc:=LOC_REGISTER;
  920. right.location.register:=hregister;
  921. end;
  922. op:=A_BTS;
  923. noswap:=true;
  924. end
  925. else
  926. op:=A_OR;
  927. mboverflow:=false;
  928. unsigned:=false;
  929. end
  930. else
  931. begin
  932. op:=A_ADD;
  933. mboverflow:=true;
  934. end;
  935. end;
  936. symdifn : begin
  937. { the symetric diff is only for sets }
  938. if is_set then
  939. begin
  940. op:=A_XOR;
  941. mboverflow:=false;
  942. unsigned:=false;
  943. end
  944. else
  945. CGMessage(type_e_mismatch);
  946. end;
  947. muln : begin
  948. if is_set then
  949. begin
  950. op:=A_AND;
  951. mboverflow:=false;
  952. unsigned:=false;
  953. end
  954. else
  955. begin
  956. if unsigned then
  957. op:=A_MUL
  958. else
  959. op:=A_IMUL;
  960. mboverflow:=true;
  961. end;
  962. end;
  963. subn : begin
  964. if is_set then
  965. begin
  966. op:=A_AND;
  967. mboverflow:=false;
  968. unsigned:=false;
  969. {$IfNDef NoSetConstNot}
  970. If (right.nodetype = setconstn) then
  971. right.location.reference.offset := not(right.location.reference.offset)
  972. Else
  973. {$EndIf NoNosetConstNot}
  974. extra_not:=true;
  975. end
  976. else
  977. begin
  978. op:=A_SUB;
  979. mboverflow:=true;
  980. end;
  981. end;
  982. ltn,lten,
  983. gtn,gten,
  984. equaln,unequaln : begin
  985. If is_set Then
  986. Case nodetype of
  987. lten,gten:
  988. Begin
  989. If nodetype = lten then
  990. swapleftright;
  991. if left.location.loc in [LOC_MEM,LOC_REFERENCE] then
  992. begin
  993. ungetiftemp(left.location.reference);
  994. del_reference(left.location.reference);
  995. hregister:=getregister32;
  996. emit_ref_reg(A_MOV,opsize,
  997. newreference(left.location.reference),hregister);
  998. clear_location(left.location);
  999. left.location.loc:=LOC_REGISTER;
  1000. left.location.register:=hregister;
  1001. set_location(location,left.location);
  1002. end
  1003. else
  1004. if left.location.loc = LOC_CREGISTER Then
  1005. {save the register var in a temp register, because
  1006. its value is going to be modified}
  1007. begin
  1008. hregister := getregister32;
  1009. emit_reg_reg(A_MOV,opsize,
  1010. left.location.register,hregister);
  1011. clear_location(left.location);
  1012. left.location.loc:=LOC_REGISTER;
  1013. left.location.register:=hregister;
  1014. set_location(location,left.location);
  1015. end;
  1016. {here, left.location should be LOC_REGISTER}
  1017. If right.location.loc in [LOC_MEM,LOC_REFERENCE] Then
  1018. emit_ref_reg(A_AND,opsize,
  1019. newreference(right.location.reference),left.location.register)
  1020. Else
  1021. emit_reg_reg(A_AND,opsize,
  1022. right.location.register,left.location.register);
  1023. {warning: ugly hack ahead: we need a "jne" after the cmp, so
  1024. change the nodetype from lten/gten to equaln}
  1025. nodetype := equaln
  1026. End;
  1027. {no < or > support for sets}
  1028. ltn,gtn: CGMessage(type_e_mismatch);
  1029. End;
  1030. op:=A_CMP;
  1031. cmpop:=true;
  1032. end;
  1033. xorn : op:=A_XOR;
  1034. orn : op:=A_OR;
  1035. andn : op:=A_AND;
  1036. else
  1037. CGMessage(type_e_mismatch);
  1038. end;
  1039. { filter MUL, which requires special handling }
  1040. if op=A_MUL then
  1041. begin
  1042. popeax:=false;
  1043. popedx:=false;
  1044. { here you need to free the symbol first }
  1045. { left.location and right.location must }
  1046. { only be freed when they are really released, }
  1047. { because the optimizer NEEDS correct regalloc }
  1048. { info!!! (JM) }
  1049. clear_location(location);
  1050. { the location.register will be filled in later (JM) }
  1051. location.loc:=LOC_REGISTER;
  1052. {$IfNDef NoShlMul}
  1053. if right.nodetype=ordconstn then
  1054. swapleftright;
  1055. If (left.nodetype = ordconstn) and
  1056. ispowerof2(tordconstnode(left).value, power) and
  1057. not(cs_check_overflow in aktlocalswitches) then
  1058. Begin
  1059. { This release will be moved after the next }
  1060. { instruction by the optimizer. No need to }
  1061. { release left.location, since it's a }
  1062. { constant (JM) }
  1063. release_loc(right.location);
  1064. location.register := getregister32;
  1065. emitloadord2reg(right.location,torddef(u32bittype.def),location.register,false);
  1066. emit_const_reg(A_SHL,S_L,power,location.register)
  1067. End
  1068. Else
  1069. Begin
  1070. {$EndIf NoShlMul}
  1071. regstopush := $ff;
  1072. remove_non_regvars_from_loc(right.location,regstopush);
  1073. remove_non_regvars_from_loc(left.location,regstopush);
  1074. { now, regstopush does NOT contain EAX and/or EDX if they are }
  1075. { used in either the left or the right location, excepts if }
  1076. {they are regvars. It DOES contain them if they are used in }
  1077. { another location (JM) }
  1078. if not(R_EAX in unused) and ((regstopush and ($80 shr byte(R_EAX))) <> 0) then
  1079. begin
  1080. emit_reg(A_PUSH,S_L,R_EAX);
  1081. popeax:=true;
  1082. end;
  1083. if not(R_EDX in unused) and ((regstopush and ($80 shr byte(R_EDX))) <> 0) then
  1084. begin
  1085. emit_reg(A_PUSH,S_L,R_EDX);
  1086. popedx:=true;
  1087. end;
  1088. { left.location can be R_EAX !!! }
  1089. getexplicitregister32(R_EDI);
  1090. { load the left value }
  1091. emitloadord2reg(left.location,torddef(u32bittype.def),R_EDI,true);
  1092. release_loc(left.location);
  1093. { allocate EAX }
  1094. if R_EAX in unused then
  1095. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  1096. { load he right value }
  1097. emitloadord2reg(right.location,torddef(u32bittype.def),R_EAX,true);
  1098. release_loc(right.location);
  1099. { allocate EAX if it isn't yet allocated (JM) }
  1100. if (R_EAX in unused) then
  1101. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  1102. { also allocate EDX, since it is also modified by }
  1103. { a mul (JM) }
  1104. if R_EDX in unused then
  1105. exprasmList.concat(Tairegalloc.Alloc(R_EDX));
  1106. emit_reg(A_MUL,S_L,R_EDI);
  1107. ungetregister32(R_EDI);
  1108. if R_EDX in unused then
  1109. exprasmList.concat(Tairegalloc.DeAlloc(R_EDX));
  1110. if R_EAX in unused then
  1111. exprasmList.concat(Tairegalloc.DeAlloc(R_EAX));
  1112. location.register := getregister32;
  1113. emit_reg_reg(A_MOV,S_L,R_EAX,location.register);
  1114. if popedx then
  1115. emit_reg(A_POP,S_L,R_EDX);
  1116. if popeax then
  1117. emit_reg(A_POP,S_L,R_EAX);
  1118. {$IfNDef NoShlMul}
  1119. End;
  1120. {$endif NoShlMul}
  1121. SetResultLocation(false,true);
  1122. exit;
  1123. end;
  1124. { Convert flags to register first }
  1125. if (left.location.loc=LOC_FLAGS) then
  1126. locflags2reg(left.location,opsize);
  1127. if (right.location.loc=LOC_FLAGS) then
  1128. locflags2reg(right.location,opsize);
  1129. { left and right no register? }
  1130. { then one must be demanded }
  1131. if (left.location.loc<>LOC_REGISTER) and
  1132. (right.location.loc<>LOC_REGISTER) then
  1133. begin
  1134. { register variable ? }
  1135. if (left.location.loc=LOC_CREGISTER) then
  1136. begin
  1137. { it is OK if this is the destination }
  1138. if is_in_dest then
  1139. begin
  1140. hregister:=location.register;
  1141. emit_reg_reg(A_MOV,opsize,left.location.register,
  1142. hregister);
  1143. end
  1144. else
  1145. if cmpop then
  1146. begin
  1147. { do not disturb the register }
  1148. hregister:=location.register;
  1149. end
  1150. else
  1151. begin
  1152. case opsize of
  1153. S_L : hregister:=getregister32;
  1154. S_B : hregister:=reg32toreg8(getregister32);
  1155. end;
  1156. emit_reg_reg(A_MOV,opsize,left.location.register,
  1157. hregister);
  1158. end
  1159. end
  1160. else
  1161. begin
  1162. ungetiftemp(left.location.reference);
  1163. del_reference(left.location.reference);
  1164. if is_in_dest then
  1165. begin
  1166. hregister:=location.register;
  1167. emit_ref_reg(A_MOV,opsize,
  1168. newreference(left.location.reference),hregister);
  1169. end
  1170. else
  1171. begin
  1172. { first give free, then demand new register }
  1173. case opsize of
  1174. S_L : hregister:=getregister32;
  1175. S_W : hregister:=reg32toreg16(getregister32);
  1176. S_B : hregister:=reg32toreg8(getregister32);
  1177. end;
  1178. emit_ref_reg(A_MOV,opsize,
  1179. newreference(left.location.reference),hregister);
  1180. end;
  1181. end;
  1182. clear_location(location);
  1183. location.loc:=LOC_REGISTER;
  1184. location.register:=hregister;
  1185. end
  1186. else
  1187. { if on the right the register then swap }
  1188. if not(noswap) and (right.location.loc=LOC_REGISTER) then
  1189. begin
  1190. swap_location(location,right.location);
  1191. { newly swapped also set swapped flag }
  1192. toggleflag(nf_swaped);
  1193. end;
  1194. { at this point, location.loc should be LOC_REGISTER }
  1195. { and location.register should be a valid register }
  1196. { containing the left result }
  1197. if right.location.loc<>LOC_REGISTER then
  1198. begin
  1199. if (nodetype=subn) and (nf_swaped in flags) then
  1200. begin
  1201. if right.location.loc=LOC_CREGISTER then
  1202. begin
  1203. if extra_not then
  1204. emit_reg(A_NOT,opsize,location.register);
  1205. getexplicitregister32(R_EDI);
  1206. emit_reg_reg(A_MOV,opsize,right.location.register,R_EDI);
  1207. emit_reg_reg(op,opsize,location.register,R_EDI);
  1208. emit_reg_reg(A_MOV,opsize,R_EDI,location.register);
  1209. ungetregister32(R_EDI);
  1210. end
  1211. else
  1212. begin
  1213. if extra_not then
  1214. emit_reg(A_NOT,opsize,location.register);
  1215. getexplicitregister32(R_EDI);
  1216. emit_ref_reg(A_MOV,opsize,
  1217. newreference(right.location.reference),R_EDI);
  1218. emit_reg_reg(op,opsize,location.register,R_EDI);
  1219. emit_reg_reg(A_MOV,opsize,R_EDI,location.register);
  1220. ungetregister32(R_EDI);
  1221. ungetiftemp(right.location.reference);
  1222. del_reference(right.location.reference);
  1223. end;
  1224. end
  1225. else
  1226. begin
  1227. if (right.nodetype=ordconstn) and
  1228. (op=A_CMP) and
  1229. (tordconstnode(right).value=0) then
  1230. begin
  1231. emit_reg_reg(A_TEST,opsize,location.register,
  1232. location.register);
  1233. end
  1234. else if (right.nodetype=ordconstn) and
  1235. (op=A_ADD) and
  1236. (tordconstnode(right).value=1) and
  1237. not(cs_check_overflow in aktlocalswitches) then
  1238. begin
  1239. emit_reg(A_INC,opsize,
  1240. location.register);
  1241. end
  1242. else if (right.nodetype=ordconstn) and
  1243. (op=A_SUB) and
  1244. (tordconstnode(right).value=1) and
  1245. not(cs_check_overflow in aktlocalswitches) then
  1246. begin
  1247. emit_reg(A_DEC,opsize,
  1248. location.register);
  1249. end
  1250. else if (right.nodetype=ordconstn) and
  1251. (op=A_IMUL) and
  1252. (ispowerof2(tordconstnode(right).value,power)) and
  1253. not(cs_check_overflow in aktlocalswitches) then
  1254. begin
  1255. emit_const_reg(A_SHL,opsize,power,
  1256. location.register);
  1257. end
  1258. else
  1259. begin
  1260. if (right.location.loc=LOC_CREGISTER) then
  1261. begin
  1262. if extra_not then
  1263. begin
  1264. getexplicitregister32(R_EDI);
  1265. emit_reg_reg(A_MOV,S_L,right.location.register,R_EDI);
  1266. emit_reg(A_NOT,S_L,R_EDI);
  1267. emit_reg_reg(A_AND,S_L,R_EDI,
  1268. location.register);
  1269. ungetregister32(R_EDI);
  1270. end
  1271. else
  1272. begin
  1273. emit_reg_reg(op,opsize,right.location.register,
  1274. location.register);
  1275. end;
  1276. end
  1277. else
  1278. begin
  1279. if extra_not then
  1280. begin
  1281. getexplicitregister32(R_EDI);
  1282. emit_ref_reg(A_MOV,S_L,newreference(
  1283. right.location.reference),R_EDI);
  1284. emit_reg(A_NOT,S_L,R_EDI);
  1285. emit_reg_reg(A_AND,S_L,R_EDI,
  1286. location.register);
  1287. ungetregister32(R_EDI);
  1288. end
  1289. else
  1290. begin
  1291. emit_ref_reg(op,opsize,newreference(
  1292. right.location.reference),location.register);
  1293. end;
  1294. ungetiftemp(right.location.reference);
  1295. del_reference(right.location.reference);
  1296. end;
  1297. end;
  1298. end;
  1299. end
  1300. else
  1301. begin
  1302. { when swapped another result register }
  1303. if (nodetype=subn) and (nf_swaped in flags) then
  1304. begin
  1305. if extra_not then
  1306. emit_reg(A_NOT,S_L,location.register);
  1307. emit_reg_reg(op,opsize,
  1308. location.register,right.location.register);
  1309. swap_location(location,right.location);
  1310. { newly swapped also set swapped flag }
  1311. { just to maintain ordering }
  1312. toggleflag(nf_swaped);
  1313. end
  1314. else
  1315. begin
  1316. if extra_not then
  1317. emit_reg(A_NOT,S_L,right.location.register);
  1318. emit_reg_reg(op,opsize,
  1319. right.location.register,
  1320. location.register);
  1321. end;
  1322. case opsize of
  1323. S_L : ungetregister32(right.location.register);
  1324. S_B : ungetregister32(reg8toreg32(right.location.register));
  1325. end;
  1326. end;
  1327. if cmpop then
  1328. case opsize of
  1329. S_L : ungetregister32(location.register);
  1330. S_B : ungetregister32(reg8toreg32(location.register));
  1331. end;
  1332. { only in case of overflow operations }
  1333. { produce overflow code }
  1334. { we must put it here directly, because sign of operation }
  1335. { is in unsigned VAR!! }
  1336. if mboverflow then
  1337. begin
  1338. if cs_check_overflow in aktlocalswitches then
  1339. begin
  1340. getlabel(hl4);
  1341. if unsigned then
  1342. emitjmp(C_NB,hl4)
  1343. else
  1344. emitjmp(C_NO,hl4);
  1345. emitcall('FPC_OVERFLOW');
  1346. emitlab(hl4);
  1347. end;
  1348. end;
  1349. end
  1350. else
  1351. { Char type }
  1352. if ((left.resulttype.def.deftype=orddef) and
  1353. (torddef(left.resulttype.def).typ=uchar)) or
  1354. { enumeration type 16 bit }
  1355. ((left.resulttype.def.deftype=enumdef) and
  1356. (left.resulttype.def.size=1)) then
  1357. begin
  1358. case nodetype of
  1359. ltn,lten,gtn,gten,
  1360. equaln,unequaln :
  1361. cmpop:=true;
  1362. else CGMessage(type_e_mismatch);
  1363. end;
  1364. unsigned:=true;
  1365. { left and right no register? }
  1366. { the one must be demanded }
  1367. if (location.loc<>LOC_REGISTER) and
  1368. (right.location.loc<>LOC_REGISTER) then
  1369. begin
  1370. if location.loc=LOC_CREGISTER then
  1371. begin
  1372. if cmpop then
  1373. { do not disturb register }
  1374. hregister:=location.register
  1375. else
  1376. begin
  1377. hregister:=reg32toreg8(getregister32);
  1378. emit_reg_reg(A_MOV,S_B,location.register,
  1379. hregister);
  1380. end;
  1381. end
  1382. else
  1383. begin
  1384. del_reference(location.reference);
  1385. { first give free then demand new register }
  1386. hregister:=reg32toreg8(getregister32);
  1387. emit_ref_reg(A_MOV,S_B,newreference(location.reference),
  1388. hregister);
  1389. end;
  1390. clear_location(location);
  1391. location.loc:=LOC_REGISTER;
  1392. location.register:=hregister;
  1393. end;
  1394. { now p always a register }
  1395. if (right.location.loc=LOC_REGISTER) and
  1396. (location.loc<>LOC_REGISTER) then
  1397. begin
  1398. swap_location(location,right.location);
  1399. { newly swapped also set swapped flag }
  1400. toggleflag(nf_swaped);
  1401. end;
  1402. if right.location.loc<>LOC_REGISTER then
  1403. begin
  1404. if right.location.loc=LOC_CREGISTER then
  1405. begin
  1406. emit_reg_reg(A_CMP,S_B,
  1407. right.location.register,location.register);
  1408. end
  1409. else
  1410. begin
  1411. emit_ref_reg(A_CMP,S_B,newreference(
  1412. right.location.reference),location.register);
  1413. del_reference(right.location.reference);
  1414. end;
  1415. end
  1416. else
  1417. begin
  1418. emit_reg_reg(A_CMP,S_B,right.location.register,
  1419. location.register);
  1420. ungetregister32(reg8toreg32(right.location.register));
  1421. end;
  1422. ungetregister32(reg8toreg32(location.register));
  1423. end
  1424. else
  1425. { 16 bit enumeration type }
  1426. if ((left.resulttype.def.deftype=enumdef) and
  1427. (left.resulttype.def.size=2)) then
  1428. begin
  1429. case nodetype of
  1430. ltn,lten,gtn,gten,
  1431. equaln,unequaln :
  1432. cmpop:=true;
  1433. else CGMessage(type_e_mismatch);
  1434. end;
  1435. unsigned:=true;
  1436. { left and right no register? }
  1437. { the one must be demanded }
  1438. if (location.loc<>LOC_REGISTER) and
  1439. (right.location.loc<>LOC_REGISTER) then
  1440. begin
  1441. if location.loc=LOC_CREGISTER then
  1442. begin
  1443. if cmpop then
  1444. { do not disturb register }
  1445. hregister:=location.register
  1446. else
  1447. begin
  1448. hregister:=reg32toreg16(getregister32);
  1449. emit_reg_reg(A_MOV,S_W,location.register,
  1450. hregister);
  1451. end;
  1452. end
  1453. else
  1454. begin
  1455. del_reference(location.reference);
  1456. { first give free then demand new register }
  1457. hregister:=reg32toreg16(getregister32);
  1458. emit_ref_reg(A_MOV,S_W,newreference(location.reference),
  1459. hregister);
  1460. end;
  1461. clear_location(location);
  1462. location.loc:=LOC_REGISTER;
  1463. location.register:=hregister;
  1464. end;
  1465. { now p always a register }
  1466. if (right.location.loc=LOC_REGISTER) and
  1467. (location.loc<>LOC_REGISTER) then
  1468. begin
  1469. swap_location(location,right.location);
  1470. { newly swapped also set swapped flag }
  1471. toggleflag(nf_swaped);
  1472. end;
  1473. if right.location.loc<>LOC_REGISTER then
  1474. begin
  1475. if right.location.loc=LOC_CREGISTER then
  1476. begin
  1477. emit_reg_reg(A_CMP,S_W,
  1478. right.location.register,location.register);
  1479. end
  1480. else
  1481. begin
  1482. emit_ref_reg(A_CMP,S_W,newreference(
  1483. right.location.reference),location.register);
  1484. del_reference(right.location.reference);
  1485. end;
  1486. end
  1487. else
  1488. begin
  1489. emit_reg_reg(A_CMP,S_W,right.location.register,
  1490. location.register);
  1491. ungetregister32(reg16toreg32(right.location.register));
  1492. end;
  1493. ungetregister32(reg16toreg32(location.register));
  1494. end
  1495. else
  1496. { 64 bit types }
  1497. if is_64bitint(left.resulttype.def) then
  1498. begin
  1499. mboverflow:=false;
  1500. cmpop:=false;
  1501. unsigned:=((left.resulttype.def.deftype=orddef) and
  1502. (torddef(left.resulttype.def).typ=u64bit)) or
  1503. ((right.resulttype.def.deftype=orddef) and
  1504. (torddef(right.resulttype.def).typ=u64bit));
  1505. case nodetype of
  1506. addn : begin
  1507. begin
  1508. op:=A_ADD;
  1509. op2:=A_ADC;
  1510. mboverflow:=true;
  1511. end;
  1512. end;
  1513. subn : begin
  1514. op:=A_SUB;
  1515. op2:=A_SBB;
  1516. mboverflow:=true;
  1517. end;
  1518. ltn,lten,
  1519. gtn,gten,
  1520. equaln,unequaln:
  1521. begin
  1522. op:=A_CMP;
  1523. op2:=A_CMP;
  1524. cmpop:=true;
  1525. end;
  1526. xorn:
  1527. begin
  1528. op:=A_XOR;
  1529. op2:=A_XOR;
  1530. end;
  1531. orn:
  1532. begin
  1533. op:=A_OR;
  1534. op2:=A_OR;
  1535. end;
  1536. andn:
  1537. begin
  1538. op:=A_AND;
  1539. op2:=A_AND;
  1540. end;
  1541. muln:
  1542. ;
  1543. else
  1544. CGMessage(type_e_mismatch);
  1545. end;
  1546. if nodetype=muln then
  1547. begin
  1548. { save lcoation, because we change it now }
  1549. set_location(hloc,location);
  1550. release_qword_loc(location);
  1551. release_qword_loc(right.location);
  1552. location.registerlow:=getexplicitregister32(R_EAX);
  1553. location.registerhigh:=getexplicitregister32(R_EDX);
  1554. pushusedregisters(pushedreg,$ff
  1555. and not($80 shr byte(location.registerlow))
  1556. and not($80 shr byte(location.registerhigh)));
  1557. if cs_check_overflow in aktlocalswitches then
  1558. push_int(1)
  1559. else
  1560. push_int(0);
  1561. { the left operand is in hloc, because the
  1562. location of left is location but location
  1563. is already destroyed
  1564. }
  1565. emit_pushq_loc(hloc);
  1566. clear_location(hloc);
  1567. emit_pushq_loc(right.location);
  1568. saveregvars($ff);
  1569. if torddef(resulttype.def).typ=u64bit then
  1570. emitcall('FPC_MUL_QWORD')
  1571. else
  1572. emitcall('FPC_MUL_INT64');
  1573. emit_reg_reg(A_MOV,S_L,R_EAX,location.registerlow);
  1574. emit_reg_reg(A_MOV,S_L,R_EDX,location.registerhigh);
  1575. popusedregisters(pushedreg);
  1576. location.loc:=LOC_REGISTER;
  1577. end
  1578. else
  1579. begin
  1580. { left and right no register? }
  1581. { then one must be demanded }
  1582. if (left.location.loc<>LOC_REGISTER) and
  1583. (right.location.loc<>LOC_REGISTER) then
  1584. begin
  1585. { register variable ? }
  1586. if (left.location.loc=LOC_CREGISTER) then
  1587. begin
  1588. { it is OK if this is the destination }
  1589. if is_in_dest then
  1590. begin
  1591. hregister:=location.registerlow;
  1592. hregister2:=location.registerhigh;
  1593. emit_reg_reg(A_MOV,S_L,left.location.registerlow,
  1594. hregister);
  1595. emit_reg_reg(A_MOV,S_L,left.location.registerlow,
  1596. hregister2);
  1597. end
  1598. else
  1599. if cmpop then
  1600. begin
  1601. { do not disturb the register }
  1602. hregister:=location.registerlow;
  1603. hregister2:=location.registerhigh;
  1604. end
  1605. else
  1606. begin
  1607. hregister:=getregister32;
  1608. hregister2:=getregister32;
  1609. emit_reg_reg(A_MOV,S_L,left.location.registerlow,
  1610. hregister);
  1611. emit_reg_reg(A_MOV,S_L,left.location.registerhigh,
  1612. hregister2);
  1613. end
  1614. end
  1615. else
  1616. begin
  1617. ungetiftemp(left.location.reference);
  1618. del_reference(left.location.reference);
  1619. if is_in_dest then
  1620. begin
  1621. hregister:=location.registerlow;
  1622. hregister2:=location.registerhigh;
  1623. emit_mov_ref_reg64(left.location.reference,hregister,hregister2);
  1624. end
  1625. else
  1626. begin
  1627. hregister:=getregister32;
  1628. hregister2:=getregister32;
  1629. emit_mov_ref_reg64(left.location.reference,hregister,hregister2);
  1630. end;
  1631. end;
  1632. clear_location(location);
  1633. location.loc:=LOC_REGISTER;
  1634. location.registerlow:=hregister;
  1635. location.registerhigh:=hregister2;
  1636. end
  1637. else
  1638. { if on the right the register then swap }
  1639. if not(noswap) and (right.location.loc=LOC_REGISTER) then
  1640. begin
  1641. swap_location(location,right.location);
  1642. { newly swapped also set swapped flag }
  1643. toggleflag(nf_swaped);
  1644. end;
  1645. { at this point, location.loc should be LOC_REGISTER }
  1646. { and location.register should be a valid register }
  1647. { containing the left result }
  1648. if right.location.loc<>LOC_REGISTER then
  1649. begin
  1650. if (nodetype=subn) and (nf_swaped in flags) then
  1651. begin
  1652. if right.location.loc=LOC_CREGISTER then
  1653. begin
  1654. getexplicitregister32(R_EDI);
  1655. emit_reg_reg(A_MOV,opsize,right.location.register,R_EDI);
  1656. emit_reg_reg(op,opsize,location.register,R_EDI);
  1657. emit_reg_reg(A_MOV,opsize,R_EDI,location.register);
  1658. ungetregister32(R_EDI);
  1659. getexplicitregister32(R_EDI);
  1660. emit_reg_reg(A_MOV,opsize,right.location.registerhigh,R_EDI);
  1661. { the carry flag is still ok }
  1662. emit_reg_reg(op2,opsize,location.registerhigh,R_EDI);
  1663. emit_reg_reg(A_MOV,opsize,R_EDI,location.registerhigh);
  1664. ungetregister32(R_EDI);
  1665. end
  1666. else
  1667. begin
  1668. getexplicitregister32(R_EDI);
  1669. emit_ref_reg(A_MOV,opsize,
  1670. newreference(right.location.reference),R_EDI);
  1671. emit_reg_reg(op,opsize,location.registerlow,R_EDI);
  1672. emit_reg_reg(A_MOV,opsize,R_EDI,location.registerlow);
  1673. ungetregister32(R_EDI);
  1674. getexplicitregister32(R_EDI);
  1675. hr:=newreference(right.location.reference);
  1676. inc(hr^.offset,4);
  1677. emit_ref_reg(A_MOV,opsize,
  1678. hr,R_EDI);
  1679. { here the carry flag is still preserved }
  1680. emit_reg_reg(op2,opsize,location.registerhigh,R_EDI);
  1681. emit_reg_reg(A_MOV,opsize,R_EDI,
  1682. location.registerhigh);
  1683. ungetregister32(R_EDI);
  1684. ungetiftemp(right.location.reference);
  1685. del_reference(right.location.reference);
  1686. end;
  1687. end
  1688. else if cmpop then
  1689. begin
  1690. if (right.location.loc=LOC_CREGISTER) then
  1691. begin
  1692. emit_reg_reg(A_CMP,S_L,right.location.registerhigh,
  1693. location.registerhigh);
  1694. firstjmp64bitcmp;
  1695. emit_reg_reg(A_CMP,S_L,right.location.registerlow,
  1696. location.registerlow);
  1697. secondjmp64bitcmp;
  1698. end
  1699. else
  1700. begin
  1701. hr:=newreference(right.location.reference);
  1702. inc(hr^.offset,4);
  1703. emit_ref_reg(A_CMP,S_L,
  1704. hr,location.registerhigh);
  1705. firstjmp64bitcmp;
  1706. emit_ref_reg(A_CMP,S_L,newreference(
  1707. right.location.reference),location.registerlow);
  1708. secondjmp64bitcmp;
  1709. emitjmp(C_None,falselabel);
  1710. ungetiftemp(right.location.reference);
  1711. del_reference(right.location.reference);
  1712. end;
  1713. end
  1714. else
  1715. begin
  1716. {
  1717. if (right.nodetype=ordconstn) and
  1718. (op=A_CMP) and
  1719. (right.value=0) then
  1720. begin
  1721. emit_reg_reg(A_TEST,opsize,location.register,
  1722. location.register);
  1723. end
  1724. else if (right.nodetype=ordconstn) and
  1725. (op=A_IMUL) and
  1726. (ispowerof2(right.value,power)) then
  1727. begin
  1728. emit_const_reg(A_SHL,opsize,power,
  1729. location.register);
  1730. end
  1731. else
  1732. }
  1733. begin
  1734. if (right.location.loc=LOC_CREGISTER) then
  1735. begin
  1736. emit_reg_reg(op,S_L,right.location.registerlow,
  1737. location.registerlow);
  1738. emit_reg_reg(op2,S_L,right.location.registerhigh,
  1739. location.registerhigh);
  1740. end
  1741. else
  1742. begin
  1743. emit_ref_reg(op,S_L,newreference(
  1744. right.location.reference),location.registerlow);
  1745. hr:=newreference(right.location.reference);
  1746. inc(hr^.offset,4);
  1747. emit_ref_reg(op2,S_L,
  1748. hr,location.registerhigh);
  1749. ungetiftemp(right.location.reference);
  1750. del_reference(right.location.reference);
  1751. end;
  1752. end;
  1753. end;
  1754. end
  1755. else
  1756. begin
  1757. { when swapped another result register }
  1758. if (nodetype=subn) and (nf_swaped in flags) then
  1759. begin
  1760. emit_reg_reg(op,S_L,
  1761. location.registerlow,
  1762. right.location.registerlow);
  1763. emit_reg_reg(op2,S_L,
  1764. location.registerhigh,
  1765. right.location.registerhigh);
  1766. swap_location(location,right.location);
  1767. { newly swapped also set swapped flag }
  1768. { just to maintain ordering }
  1769. toggleflag(nf_swaped);
  1770. end
  1771. else if cmpop then
  1772. begin
  1773. emit_reg_reg(A_CMP,S_L,
  1774. right.location.registerhigh,
  1775. location.registerhigh);
  1776. firstjmp64bitcmp;
  1777. emit_reg_reg(A_CMP,S_L,
  1778. right.location.registerlow,
  1779. location.registerlow);
  1780. secondjmp64bitcmp;
  1781. end
  1782. else
  1783. begin
  1784. emit_reg_reg(op,S_L,
  1785. right.location.registerlow,
  1786. location.registerlow);
  1787. emit_reg_reg(op2,S_L,
  1788. right.location.registerhigh,
  1789. location.registerhigh);
  1790. end;
  1791. ungetregister32(right.location.registerlow);
  1792. ungetregister32(right.location.registerhigh);
  1793. end;
  1794. if cmpop then
  1795. begin
  1796. ungetregister32(location.registerlow);
  1797. ungetregister32(location.registerhigh);
  1798. end;
  1799. { only in case of overflow operations }
  1800. { produce overflow code }
  1801. { we must put it here directly, because sign of operation }
  1802. { is in unsigned VAR!! }
  1803. if mboverflow then
  1804. begin
  1805. if cs_check_overflow in aktlocalswitches then
  1806. begin
  1807. getlabel(hl4);
  1808. if unsigned then
  1809. emitjmp(C_NB,hl4)
  1810. else
  1811. emitjmp(C_NO,hl4);
  1812. emitcall('FPC_OVERFLOW');
  1813. emitlab(hl4);
  1814. end;
  1815. end;
  1816. { we have LOC_JUMP as result }
  1817. if cmpop then
  1818. begin
  1819. clear_location(location);
  1820. location.loc:=LOC_JUMP;
  1821. cmpop:=false;
  1822. end;
  1823. end;
  1824. end
  1825. else
  1826. { Floating point }
  1827. if (left.resulttype.def.deftype=floatdef) then
  1828. begin
  1829. { real constants to the right, but only if it
  1830. isn't on the FPU stack, i.e. 1.0 or 0.0! }
  1831. if (left.nodetype=realconstn) and
  1832. (left.location.loc<>LOC_FPU) then
  1833. swapleftright;
  1834. cmpop:=false;
  1835. case nodetype of
  1836. addn : op:=A_FADDP;
  1837. muln : op:=A_FMULP;
  1838. subn : op:=A_FSUBP;
  1839. slashn : op:=A_FDIVP;
  1840. ltn,lten,gtn,gten,
  1841. equaln,unequaln : begin
  1842. op:=A_FCOMPP;
  1843. cmpop:=true;
  1844. end;
  1845. else CGMessage(type_e_mismatch);
  1846. end;
  1847. if (right.location.loc<>LOC_FPU) then
  1848. begin
  1849. if right.location.loc=LOC_CFPUREGISTER then
  1850. begin
  1851. emit_reg( A_FLD,S_NO,
  1852. correct_fpuregister(right.location.register,fpuvaroffset));
  1853. inc(fpuvaroffset);
  1854. end
  1855. else
  1856. floatload(tfloatdef(right.resulttype.def).typ,right.location.reference);
  1857. if (left.location.loc<>LOC_FPU) then
  1858. begin
  1859. if left.location.loc=LOC_CFPUREGISTER then
  1860. begin
  1861. emit_reg( A_FLD,S_NO,
  1862. correct_fpuregister(left.location.register,fpuvaroffset));
  1863. inc(fpuvaroffset);
  1864. end
  1865. else
  1866. floatload(tfloatdef(left.resulttype.def).typ,left.location.reference)
  1867. end
  1868. { left was on the stack => swap }
  1869. else
  1870. toggleflag(nf_swaped);
  1871. { releases the right reference }
  1872. del_reference(right.location.reference);
  1873. end
  1874. { the nominator in st0 }
  1875. else if (left.location.loc<>LOC_FPU) then
  1876. begin
  1877. if left.location.loc=LOC_CFPUREGISTER then
  1878. begin
  1879. emit_reg( A_FLD,S_NO,
  1880. correct_fpuregister(left.location.register,fpuvaroffset));
  1881. inc(fpuvaroffset);
  1882. end
  1883. else
  1884. floatload(tfloatdef(left.resulttype.def).typ,left.location.reference)
  1885. end
  1886. { fpu operands are always in the wrong order on the stack }
  1887. else
  1888. toggleflag(nf_swaped);
  1889. { releases the left reference }
  1890. if (left.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  1891. del_reference(left.location.reference);
  1892. { if we swaped the tree nodes, then use the reverse operator }
  1893. if nf_swaped in flags then
  1894. begin
  1895. if (nodetype=slashn) then
  1896. op:=A_FDIVRP
  1897. else if (nodetype=subn) then
  1898. op:=A_FSUBRP;
  1899. end;
  1900. { to avoid the pentium bug
  1901. if (op=FDIVP) and (opt_processors=pentium) then
  1902. emitcall('EMUL_FDIVP')
  1903. else
  1904. }
  1905. { the Intel assemblers want operands }
  1906. if op<>A_FCOMPP then
  1907. begin
  1908. emit_reg_reg(op,S_NO,R_ST,R_ST1);
  1909. dec(fpuvaroffset);
  1910. end
  1911. else
  1912. begin
  1913. emit_none(op,S_NO);
  1914. dec(fpuvaroffset,2);
  1915. end;
  1916. { on comparison load flags }
  1917. if cmpop then
  1918. begin
  1919. if not(R_EAX in unused) then
  1920. begin
  1921. getexplicitregister32(R_EDI);
  1922. emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
  1923. end;
  1924. emit_reg(A_FNSTSW,S_NO,R_AX);
  1925. emit_none(A_SAHF,S_NO);
  1926. if not(R_EAX in unused) then
  1927. begin
  1928. emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
  1929. ungetregister32(R_EDI);
  1930. end;
  1931. if nf_swaped in flags then
  1932. begin
  1933. case nodetype of
  1934. equaln : resflags:=F_E;
  1935. unequaln : resflags:=F_NE;
  1936. ltn : resflags:=F_A;
  1937. lten : resflags:=F_AE;
  1938. gtn : resflags:=F_B;
  1939. gten : resflags:=F_BE;
  1940. end;
  1941. end
  1942. else
  1943. begin
  1944. case nodetype of
  1945. equaln : resflags:=F_E;
  1946. unequaln : resflags:=F_NE;
  1947. ltn : resflags:=F_B;
  1948. lten : resflags:=F_BE;
  1949. gtn : resflags:=F_A;
  1950. gten : resflags:=F_AE;
  1951. end;
  1952. end;
  1953. clear_location(location);
  1954. location.loc:=LOC_FLAGS;
  1955. location.resflags:=resflags;
  1956. cmpop:=false;
  1957. end
  1958. else
  1959. begin
  1960. clear_location(location);
  1961. location.loc:=LOC_FPU;
  1962. end;
  1963. end
  1964. {$ifdef SUPPORT_MMX}
  1965. else
  1966. { MMX Arrays }
  1967. if is_mmx_able_array(left.resulttype.def) then
  1968. begin
  1969. cmpop:=false;
  1970. mmxbase:=mmx_type(left.resulttype.def);
  1971. case nodetype of
  1972. addn : begin
  1973. if (cs_mmx_saturation in aktlocalswitches) then
  1974. begin
  1975. case mmxbase of
  1976. mmxs8bit:
  1977. op:=A_PADDSB;
  1978. mmxu8bit:
  1979. op:=A_PADDUSB;
  1980. mmxs16bit,mmxfixed16:
  1981. op:=A_PADDSB;
  1982. mmxu16bit:
  1983. op:=A_PADDUSW;
  1984. end;
  1985. end
  1986. else
  1987. begin
  1988. case mmxbase of
  1989. mmxs8bit,mmxu8bit:
  1990. op:=A_PADDB;
  1991. mmxs16bit,mmxu16bit,mmxfixed16:
  1992. op:=A_PADDW;
  1993. mmxs32bit,mmxu32bit:
  1994. op:=A_PADDD;
  1995. end;
  1996. end;
  1997. end;
  1998. muln : begin
  1999. case mmxbase of
  2000. mmxs16bit,mmxu16bit:
  2001. op:=A_PMULLW;
  2002. mmxfixed16:
  2003. op:=A_PMULHW;
  2004. end;
  2005. end;
  2006. subn : begin
  2007. if (cs_mmx_saturation in aktlocalswitches) then
  2008. begin
  2009. case mmxbase of
  2010. mmxs8bit:
  2011. op:=A_PSUBSB;
  2012. mmxu8bit:
  2013. op:=A_PSUBUSB;
  2014. mmxs16bit,mmxfixed16:
  2015. op:=A_PSUBSB;
  2016. mmxu16bit:
  2017. op:=A_PSUBUSW;
  2018. end;
  2019. end
  2020. else
  2021. begin
  2022. case mmxbase of
  2023. mmxs8bit,mmxu8bit:
  2024. op:=A_PSUBB;
  2025. mmxs16bit,mmxu16bit,mmxfixed16:
  2026. op:=A_PSUBW;
  2027. mmxs32bit,mmxu32bit:
  2028. op:=A_PSUBD;
  2029. end;
  2030. end;
  2031. end;
  2032. {
  2033. ltn,lten,gtn,gten,
  2034. equaln,unequaln :
  2035. begin
  2036. op:=A_CMP;
  2037. cmpop:=true;
  2038. end;
  2039. }
  2040. xorn:
  2041. op:=A_PXOR;
  2042. orn:
  2043. op:=A_POR;
  2044. andn:
  2045. op:=A_PAND;
  2046. else CGMessage(type_e_mismatch);
  2047. end;
  2048. { left and right no register? }
  2049. { then one must be demanded }
  2050. if (left.location.loc<>LOC_MMXREGISTER) and
  2051. (right.location.loc<>LOC_MMXREGISTER) then
  2052. begin
  2053. { register variable ? }
  2054. if (left.location.loc=LOC_CMMXREGISTER) then
  2055. begin
  2056. { it is OK if this is the destination }
  2057. if is_in_dest then
  2058. begin
  2059. hregister:=location.register;
  2060. emit_reg_reg(A_MOVQ,S_NO,left.location.register,
  2061. hregister);
  2062. end
  2063. else
  2064. begin
  2065. hregister:=getregistermmx;
  2066. emit_reg_reg(A_MOVQ,S_NO,left.location.register,
  2067. hregister);
  2068. end
  2069. end
  2070. else
  2071. begin
  2072. del_reference(left.location.reference);
  2073. if is_in_dest then
  2074. begin
  2075. hregister:=location.register;
  2076. emit_ref_reg(A_MOVQ,S_NO,
  2077. newreference(left.location.reference),hregister);
  2078. end
  2079. else
  2080. begin
  2081. hregister:=getregistermmx;
  2082. emit_ref_reg(A_MOVQ,S_NO,
  2083. newreference(left.location.reference),hregister);
  2084. end;
  2085. end;
  2086. clear_location(location);
  2087. location.loc:=LOC_MMXREGISTER;
  2088. location.register:=hregister;
  2089. end
  2090. else
  2091. { if on the right the register then swap }
  2092. if (right.location.loc=LOC_MMXREGISTER) then
  2093. begin
  2094. swap_location(location,right.location);
  2095. { newly swapped also set swapped flag }
  2096. toggleflag(nf_swaped);
  2097. end;
  2098. { at this point, location.loc should be LOC_MMXREGISTER }
  2099. { and location.register should be a valid register }
  2100. { containing the left result }
  2101. if right.location.loc<>LOC_MMXREGISTER then
  2102. begin
  2103. if (nodetype=subn) and (nf_swaped in flags) then
  2104. begin
  2105. if right.location.loc=LOC_CMMXREGISTER then
  2106. begin
  2107. emit_reg_reg(A_MOVQ,S_NO,right.location.register,R_MM7);
  2108. emit_reg_reg(op,S_NO,location.register,R_MM0);
  2109. emit_reg_reg(A_MOVQ,S_NO,R_MM7,location.register);
  2110. end
  2111. else
  2112. begin
  2113. emit_ref_reg(A_MOVQ,S_NO,
  2114. newreference(right.location.reference),R_MM7);
  2115. emit_reg_reg(op,S_NO,location.register,
  2116. R_MM7);
  2117. emit_reg_reg(A_MOVQ,S_NO,
  2118. R_MM7,location.register);
  2119. del_reference(right.location.reference);
  2120. end;
  2121. end
  2122. else
  2123. begin
  2124. if (right.location.loc=LOC_CREGISTER) then
  2125. begin
  2126. emit_reg_reg(op,S_NO,right.location.register,
  2127. location.register);
  2128. end
  2129. else
  2130. begin
  2131. emit_ref_reg(op,S_NO,newreference(
  2132. right.location.reference),location.register);
  2133. del_reference(right.location.reference);
  2134. end;
  2135. end;
  2136. end
  2137. else
  2138. begin
  2139. { when swapped another result register }
  2140. if (nodetype=subn) and (nf_swaped in flags) then
  2141. begin
  2142. emit_reg_reg(op,S_NO,
  2143. location.register,right.location.register);
  2144. swap_location(location,right.location);
  2145. { newly swapped also set swapped flag }
  2146. { just to maintain ordering }
  2147. toggleflag(nf_swaped);
  2148. end
  2149. else
  2150. begin
  2151. emit_reg_reg(op,S_NO,
  2152. right.location.register,
  2153. location.register);
  2154. end;
  2155. ungetregistermmx(right.location.register);
  2156. end;
  2157. end
  2158. {$endif SUPPORT_MMX}
  2159. else CGMessage(type_e_mismatch);
  2160. end;
  2161. SetResultLocation(cmpop,unsigned);
  2162. end;
  2163. begin
  2164. caddnode:=ti386addnode;
  2165. end.
  2166. {
  2167. $Log$
  2168. Revision 1.11 2001-04-13 01:22:18 peter
  2169. * symtable change to classes
  2170. * range check generation and errors fixed, make cycle DEBUG=1 works
  2171. * memory leaks fixed
  2172. Revision 1.10 2001/04/02 21:20:36 peter
  2173. * resulttype rewrite
  2174. Revision 1.9 2000/12/31 11:14:11 jonas
  2175. + implemented/fixed docompare() mathods for all nodes (not tested)
  2176. + nopt.pas, nadd.pas, i386/n386opt.pas: optimized nodes for adding strings
  2177. and constant strings/chars together
  2178. * n386add.pas: don't copy temp strings (of size 256) to another temp string
  2179. when adding
  2180. Revision 1.8 2000/12/25 00:07:32 peter
  2181. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  2182. tlinkedlist objects)
  2183. Revision 1.7 2000/12/16 15:56:18 jonas
  2184. - removed all ifdef cardinalmulfix code
  2185. Revision 1.6 2000/12/05 11:44:32 jonas
  2186. + new integer regvar handling, should be much more efficient
  2187. Revision 1.5 2000/11/29 00:30:45 florian
  2188. * unused units removed from uses clause
  2189. * some changes for widestrings
  2190. Revision 1.4 2000/11/13 11:30:56 florian
  2191. * some bugs with interfaces and NIL fixed
  2192. Revision 1.3 2000/11/04 14:25:23 florian
  2193. + merged Attila's changes for interfaces, not tested yet
  2194. Revision 1.2 2000/10/31 22:02:56 peter
  2195. * symtable splitted, no real code changes
  2196. Revision 1.1 2000/10/15 09:33:31 peter
  2197. * moved n386*.pas to i386/ cpu_target dir
  2198. Revision 1.6 2000/10/14 10:14:47 peter
  2199. * moehrendorf oct 2000 rewrite
  2200. Revision 1.5 2000/09/30 16:08:45 peter
  2201. * more cg11 updates
  2202. Revision 1.4 2000/09/24 15:06:18 peter
  2203. * use defines.inc
  2204. Revision 1.3 2000/09/22 22:42:52 florian
  2205. * more fixes
  2206. Revision 1.2 2000/09/21 12:24:22 jonas
  2207. * small fix to my changes for full boolean evaluation support (moved
  2208. opsize determination for boolean operations back in boolean
  2209. processing block)
  2210. + full boolean evaluation support (from cg386add)
  2211. Revision 1.1 2000/09/20 21:23:32 florian
  2212. * initial revision
  2213. }