n386add.pas 106 KB

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