n386add.pas 106 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343
  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. {$ifndef noAllocEdi}
  1100. getexplicitregister32(R_EDI);
  1101. {$endif noAllocEdi}
  1102. { load the left value }
  1103. emitloadord2reg(left.location,u32bitdef,R_EDI,true);
  1104. release_loc(left.location);
  1105. { allocate EAX }
  1106. if R_EAX in unused then
  1107. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1108. { load he right value }
  1109. emitloadord2reg(right.location,u32bitdef,R_EAX,true);
  1110. release_loc(right.location);
  1111. { allocate EAX if it isn't yet allocated (JM) }
  1112. if (R_EAX in unused) then
  1113. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1114. {$ifndef noAllocEdi}
  1115. { also allocate EDX, since it is also modified by }
  1116. { a mul (JM) }
  1117. if R_EDX in unused then
  1118. exprasmlist^.concat(new(pairegalloc,alloc(R_EDX)));
  1119. {$endif noAllocEdi}
  1120. emit_reg(A_MUL,S_L,R_EDI);
  1121. {$ifndef noAllocEdi}
  1122. ungetregister32(R_EDI);
  1123. if R_EDX in unused then
  1124. exprasmlist^.concat(new(pairegalloc,dealloc(R_EDX)));
  1125. {$endif noAllocEdi}
  1126. if R_EAX in unused then
  1127. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  1128. location.register := getregister32;
  1129. emit_reg_reg(A_MOV,S_L,R_EAX,location.register);
  1130. if popedx then
  1131. emit_reg(A_POP,S_L,R_EDX);
  1132. if popeax then
  1133. emit_reg(A_POP,S_L,R_EAX);
  1134. {$IfNDef NoShlMul}
  1135. End;
  1136. {$endif NoShlMul}
  1137. SetResultLocation(false,true,p);
  1138. exit;
  1139. end;
  1140. { Convert flags to register first }
  1141. if (left.location.loc=LOC_FLAGS) then
  1142. locflags2reg(left.location,opsize);
  1143. if (right.location.loc=LOC_FLAGS) then
  1144. locflags2reg(right.location,opsize);
  1145. { left and right no register? }
  1146. { then one must be demanded }
  1147. if (left.location.loc<>LOC_REGISTER) and
  1148. (right.location.loc<>LOC_REGISTER) then
  1149. begin
  1150. { register variable ? }
  1151. if (left.location.loc=LOC_CREGISTER) then
  1152. begin
  1153. { it is OK if this is the destination }
  1154. if is_in_dest then
  1155. begin
  1156. hregister:=location.register;
  1157. emit_reg_reg(A_MOV,opsize,left.location.register,
  1158. hregister);
  1159. end
  1160. else
  1161. if cmpop then
  1162. begin
  1163. { do not disturb the register }
  1164. hregister:=location.register;
  1165. end
  1166. else
  1167. begin
  1168. case opsize of
  1169. S_L : hregister:=getregister32;
  1170. S_B : hregister:=reg32toreg8(getregister32);
  1171. end;
  1172. emit_reg_reg(A_MOV,opsize,left.location.register,
  1173. hregister);
  1174. end
  1175. end
  1176. else
  1177. begin
  1178. ungetiftemp(left.location.reference);
  1179. del_reference(left.location.reference);
  1180. if is_in_dest then
  1181. begin
  1182. hregister:=location.register;
  1183. emit_ref_reg(A_MOV,opsize,
  1184. newreference(left.location.reference),hregister);
  1185. end
  1186. else
  1187. begin
  1188. { first give free, then demand new register }
  1189. case opsize of
  1190. S_L : hregister:=getregister32;
  1191. S_W : hregister:=reg32toreg16(getregister32);
  1192. S_B : hregister:=reg32toreg8(getregister32);
  1193. end;
  1194. emit_ref_reg(A_MOV,opsize,
  1195. newreference(left.location.reference),hregister);
  1196. end;
  1197. end;
  1198. clear_location(location);
  1199. location.loc:=LOC_REGISTER;
  1200. location.register:=hregister;
  1201. end
  1202. else
  1203. { if on the right the register then swap }
  1204. if not(noswap) and (right.location.loc=LOC_REGISTER) then
  1205. begin
  1206. swap_location(location,right.location);
  1207. { newly swapped also set swapped flag }
  1208. swaped:=not(swaped);
  1209. end;
  1210. { at this point, location.loc should be LOC_REGISTER }
  1211. { and location.register should be a valid register }
  1212. { containing the left result }
  1213. if right.location.loc<>LOC_REGISTER then
  1214. begin
  1215. if (treetype=subn) and swaped then
  1216. begin
  1217. if right.location.loc=LOC_CREGISTER then
  1218. begin
  1219. if extra_not then
  1220. emit_reg(A_NOT,opsize,location.register);
  1221. {$ifndef noAllocEdi}
  1222. getexplicitregister32(R_EDI);
  1223. {$endif noAllocEdi}
  1224. emit_reg_reg(A_MOV,opsize,right.location.register,R_EDI);
  1225. emit_reg_reg(op,opsize,location.register,R_EDI);
  1226. emit_reg_reg(A_MOV,opsize,R_EDI,location.register);
  1227. {$ifndef noAllocEdi}
  1228. ungetregister32(R_EDI);
  1229. {$endif noAllocEdi}
  1230. end
  1231. else
  1232. begin
  1233. if extra_not then
  1234. emit_reg(A_NOT,opsize,location.register);
  1235. {$ifndef noAllocEdi}
  1236. getexplicitregister32(R_EDI);
  1237. {$endif noAllocEdi}
  1238. emit_ref_reg(A_MOV,opsize,
  1239. newreference(right.location.reference),R_EDI);
  1240. emit_reg_reg(op,opsize,location.register,R_EDI);
  1241. emit_reg_reg(A_MOV,opsize,R_EDI,location.register);
  1242. {$ifndef noAllocEdi}
  1243. ungetregister32(R_EDI);
  1244. {$endif noAllocEdi}
  1245. ungetiftemp(right.location.reference);
  1246. del_reference(right.location.reference);
  1247. end;
  1248. end
  1249. else
  1250. begin
  1251. if (right.treetype=ordconstn) and
  1252. (op=A_CMP) and
  1253. (right.value=0) then
  1254. begin
  1255. emit_reg_reg(A_TEST,opsize,location.register,
  1256. location.register);
  1257. end
  1258. else if (right.treetype=ordconstn) and
  1259. (op=A_ADD) and
  1260. (right.value=1) and
  1261. not(cs_check_overflow in aktlocalswitches) then
  1262. begin
  1263. emit_reg(A_INC,opsize,
  1264. location.register);
  1265. end
  1266. else if (right.treetype=ordconstn) and
  1267. (op=A_SUB) and
  1268. (right.value=1) and
  1269. not(cs_check_overflow in aktlocalswitches) then
  1270. begin
  1271. emit_reg(A_DEC,opsize,
  1272. location.register);
  1273. end
  1274. else if (right.treetype=ordconstn) and
  1275. (op=A_IMUL) and
  1276. (ispowerof2(right.value,power)) and
  1277. not(cs_check_overflow in aktlocalswitches) then
  1278. begin
  1279. emit_const_reg(A_SHL,opsize,power,
  1280. location.register);
  1281. end
  1282. else
  1283. begin
  1284. if (right.location.loc=LOC_CREGISTER) then
  1285. begin
  1286. if extra_not then
  1287. begin
  1288. {$ifndef noAllocEdi}
  1289. getexplicitregister32(R_EDI);
  1290. {$endif noAllocEdi}
  1291. emit_reg_reg(A_MOV,S_L,right.location.register,R_EDI);
  1292. emit_reg(A_NOT,S_L,R_EDI);
  1293. emit_reg_reg(A_AND,S_L,R_EDI,
  1294. location.register);
  1295. {$ifndef noAllocEdi}
  1296. ungetregister32(R_EDI);
  1297. {$endif noAllocEdi}
  1298. end
  1299. else
  1300. begin
  1301. emit_reg_reg(op,opsize,right.location.register,
  1302. location.register);
  1303. end;
  1304. end
  1305. else
  1306. begin
  1307. if extra_not then
  1308. begin
  1309. {$ifndef noAllocEdi}
  1310. getexplicitregister32(R_EDI);
  1311. {$endif noAllocEdi}
  1312. emit_ref_reg(A_MOV,S_L,newreference(
  1313. right.location.reference),R_EDI);
  1314. emit_reg(A_NOT,S_L,R_EDI);
  1315. emit_reg_reg(A_AND,S_L,R_EDI,
  1316. location.register);
  1317. {$ifndef noAllocEdi}
  1318. ungetregister32(R_EDI);
  1319. {$endif noAllocEdi}
  1320. end
  1321. else
  1322. begin
  1323. emit_ref_reg(op,opsize,newreference(
  1324. right.location.reference),location.register);
  1325. end;
  1326. ungetiftemp(right.location.reference);
  1327. del_reference(right.location.reference);
  1328. end;
  1329. end;
  1330. end;
  1331. end
  1332. else
  1333. begin
  1334. { when swapped another result register }
  1335. if (treetype=subn) and swaped then
  1336. begin
  1337. if extra_not then
  1338. emit_reg(A_NOT,S_L,location.register);
  1339. emit_reg_reg(op,opsize,
  1340. location.register,right.location.register);
  1341. swap_location(location,right.location);
  1342. { newly swapped also set swapped flag }
  1343. { just to maintain ordering }
  1344. swaped:=not(swaped);
  1345. end
  1346. else
  1347. begin
  1348. if extra_not then
  1349. emit_reg(A_NOT,S_L,right.location.register);
  1350. emit_reg_reg(op,opsize,
  1351. right.location.register,
  1352. location.register);
  1353. end;
  1354. case opsize of
  1355. S_L : ungetregister32(right.location.register);
  1356. S_B : ungetregister32(reg8toreg32(right.location.register));
  1357. end;
  1358. end;
  1359. if cmpop then
  1360. case opsize of
  1361. S_L : ungetregister32(location.register);
  1362. S_B : ungetregister32(reg8toreg32(location.register));
  1363. end;
  1364. { only in case of overflow operations }
  1365. { produce overflow code }
  1366. { we must put it here directly, because sign of operation }
  1367. { is in unsigned VAR!! }
  1368. if mboverflow then
  1369. begin
  1370. if cs_check_overflow in aktlocalswitches then
  1371. begin
  1372. getlabel(hl4);
  1373. if unsigned then
  1374. emitjmp(C_NB,hl4)
  1375. else
  1376. emitjmp(C_NO,hl4);
  1377. emitcall('FPC_OVERFLOW');
  1378. emitlab(hl4);
  1379. end;
  1380. end;
  1381. end
  1382. else
  1383. { Char type }
  1384. if ((left.resulttype^.deftype=orddef) and
  1385. (porddef(left.resulttype)^.typ=uchar)) or
  1386. { enumeration type 16 bit }
  1387. ((left.resulttype^.deftype=enumdef) and
  1388. (left.resulttype^.size=1)) then
  1389. begin
  1390. case treetype of
  1391. ltn,lten,gtn,gten,
  1392. equaln,unequaln :
  1393. cmpop:=true;
  1394. else CGMessage(type_e_mismatch);
  1395. end;
  1396. unsigned:=true;
  1397. { left and right no register? }
  1398. { the one must be demanded }
  1399. if (location.loc<>LOC_REGISTER) and
  1400. (right.location.loc<>LOC_REGISTER) then
  1401. begin
  1402. if location.loc=LOC_CREGISTER then
  1403. begin
  1404. if cmpop then
  1405. { do not disturb register }
  1406. hregister:=location.register
  1407. else
  1408. begin
  1409. hregister:=reg32toreg8(getregister32);
  1410. emit_reg_reg(A_MOV,S_B,location.register,
  1411. hregister);
  1412. end;
  1413. end
  1414. else
  1415. begin
  1416. del_reference(location.reference);
  1417. { first give free then demand new register }
  1418. hregister:=reg32toreg8(getregister32);
  1419. emit_ref_reg(A_MOV,S_B,newreference(location.reference),
  1420. hregister);
  1421. end;
  1422. clear_location(location);
  1423. location.loc:=LOC_REGISTER;
  1424. location.register:=hregister;
  1425. end;
  1426. { now p always a register }
  1427. if (right.location.loc=LOC_REGISTER) and
  1428. (location.loc<>LOC_REGISTER) then
  1429. begin
  1430. swap_location(location,right.location);
  1431. { newly swapped also set swapped flag }
  1432. swaped:=not(swaped);
  1433. end;
  1434. if right.location.loc<>LOC_REGISTER then
  1435. begin
  1436. if right.location.loc=LOC_CREGISTER then
  1437. begin
  1438. emit_reg_reg(A_CMP,S_B,
  1439. right.location.register,location.register);
  1440. end
  1441. else
  1442. begin
  1443. emit_ref_reg(A_CMP,S_B,newreference(
  1444. right.location.reference),location.register);
  1445. del_reference(right.location.reference);
  1446. end;
  1447. end
  1448. else
  1449. begin
  1450. emit_reg_reg(A_CMP,S_B,right.location.register,
  1451. location.register);
  1452. ungetregister32(reg8toreg32(right.location.register));
  1453. end;
  1454. ungetregister32(reg8toreg32(location.register));
  1455. end
  1456. else
  1457. { 16 bit enumeration type }
  1458. if ((left.resulttype^.deftype=enumdef) and
  1459. (left.resulttype^.size=2)) then
  1460. begin
  1461. case treetype of
  1462. ltn,lten,gtn,gten,
  1463. equaln,unequaln :
  1464. cmpop:=true;
  1465. else CGMessage(type_e_mismatch);
  1466. end;
  1467. unsigned:=true;
  1468. { left and right no register? }
  1469. { the one must be demanded }
  1470. if (location.loc<>LOC_REGISTER) and
  1471. (right.location.loc<>LOC_REGISTER) then
  1472. begin
  1473. if location.loc=LOC_CREGISTER then
  1474. begin
  1475. if cmpop then
  1476. { do not disturb register }
  1477. hregister:=location.register
  1478. else
  1479. begin
  1480. hregister:=reg32toreg16(getregister32);
  1481. emit_reg_reg(A_MOV,S_W,location.register,
  1482. hregister);
  1483. end;
  1484. end
  1485. else
  1486. begin
  1487. del_reference(location.reference);
  1488. { first give free then demand new register }
  1489. hregister:=reg32toreg16(getregister32);
  1490. emit_ref_reg(A_MOV,S_W,newreference(location.reference),
  1491. hregister);
  1492. end;
  1493. clear_location(location);
  1494. location.loc:=LOC_REGISTER;
  1495. location.register:=hregister;
  1496. end;
  1497. { now p always a register }
  1498. if (right.location.loc=LOC_REGISTER) and
  1499. (location.loc<>LOC_REGISTER) then
  1500. begin
  1501. swap_location(location,right.location);
  1502. { newly swapped also set swapped flag }
  1503. swaped:=not(swaped);
  1504. end;
  1505. if right.location.loc<>LOC_REGISTER then
  1506. begin
  1507. if right.location.loc=LOC_CREGISTER then
  1508. begin
  1509. emit_reg_reg(A_CMP,S_W,
  1510. right.location.register,location.register);
  1511. end
  1512. else
  1513. begin
  1514. emit_ref_reg(A_CMP,S_W,newreference(
  1515. right.location.reference),location.register);
  1516. del_reference(right.location.reference);
  1517. end;
  1518. end
  1519. else
  1520. begin
  1521. emit_reg_reg(A_CMP,S_W,right.location.register,
  1522. location.register);
  1523. ungetregister32(reg16toreg32(right.location.register));
  1524. end;
  1525. ungetregister32(reg16toreg32(location.register));
  1526. end
  1527. else
  1528. { 64 bit types }
  1529. if is_64bitint(left.resulttype) then
  1530. begin
  1531. mboverflow:=false;
  1532. cmpop:=false;
  1533. unsigned:=((left.resulttype^.deftype=orddef) and
  1534. (porddef(left.resulttype)^.typ=u64bit)) or
  1535. ((right.resulttype^.deftype=orddef) and
  1536. (porddef(right.resulttype)^.typ=u64bit));
  1537. case treetype of
  1538. addn : begin
  1539. begin
  1540. op:=A_ADD;
  1541. op2:=A_ADC;
  1542. mboverflow:=true;
  1543. end;
  1544. end;
  1545. subn : begin
  1546. op:=A_SUB;
  1547. op2:=A_SBB;
  1548. mboverflow:=true;
  1549. end;
  1550. ltn,lten,
  1551. gtn,gten,
  1552. equaln,unequaln:
  1553. begin
  1554. op:=A_CMP;
  1555. op2:=A_CMP;
  1556. cmpop:=true;
  1557. end;
  1558. xorn:
  1559. begin
  1560. op:=A_XOR;
  1561. op2:=A_XOR;
  1562. end;
  1563. orn:
  1564. begin
  1565. op:=A_OR;
  1566. op2:=A_OR;
  1567. end;
  1568. andn:
  1569. begin
  1570. op:=A_AND;
  1571. op2:=A_AND;
  1572. end;
  1573. muln:
  1574. ;
  1575. else
  1576. CGMessage(type_e_mismatch);
  1577. end;
  1578. if treetype=muln then
  1579. begin
  1580. { save lcoation, because we change it now }
  1581. set_location(hloc,location);
  1582. release_qword_loc(location);
  1583. release_qword_loc(right.location);
  1584. location.registerlow:=getexplicitregister32(R_EAX);
  1585. location.registerhigh:=getexplicitregister32(R_EDX);
  1586. pushusedregisters(pushedreg,$ff
  1587. and not($80 shr byte(location.registerlow))
  1588. and not($80 shr byte(location.registerhigh)));
  1589. if cs_check_overflow in aktlocalswitches then
  1590. push_int(1)
  1591. else
  1592. push_int(0);
  1593. { the left operand is in hloc, because the
  1594. location of left is location but location
  1595. is already destroyed
  1596. }
  1597. emit_pushq_loc(hloc);
  1598. clear_location(hloc);
  1599. emit_pushq_loc(right.location);
  1600. if porddef(resulttype)^.typ=u64bit then
  1601. emitcall('FPC_MUL_QWORD')
  1602. else
  1603. emitcall('FPC_MUL_INT64');
  1604. emit_reg_reg(A_MOV,S_L,R_EAX,location.registerlow);
  1605. emit_reg_reg(A_MOV,S_L,R_EDX,location.registerhigh);
  1606. popusedregisters(pushedreg);
  1607. location.loc:=LOC_REGISTER;
  1608. end
  1609. else
  1610. begin
  1611. { left and right no register? }
  1612. { then one must be demanded }
  1613. if (left.location.loc<>LOC_REGISTER) and
  1614. (right.location.loc<>LOC_REGISTER) then
  1615. begin
  1616. { register variable ? }
  1617. if (left.location.loc=LOC_CREGISTER) then
  1618. begin
  1619. { it is OK if this is the destination }
  1620. if is_in_dest then
  1621. begin
  1622. hregister:=location.registerlow;
  1623. hregister2:=location.registerhigh;
  1624. emit_reg_reg(A_MOV,S_L,left.location.registerlow,
  1625. hregister);
  1626. emit_reg_reg(A_MOV,S_L,left.location.registerlow,
  1627. hregister2);
  1628. end
  1629. else
  1630. if cmpop then
  1631. begin
  1632. { do not disturb the register }
  1633. hregister:=location.registerlow;
  1634. hregister2:=location.registerhigh;
  1635. end
  1636. else
  1637. begin
  1638. hregister:=getregister32;
  1639. hregister2:=getregister32;
  1640. emit_reg_reg(A_MOV,S_L,left.location.registerlow,
  1641. hregister);
  1642. emit_reg_reg(A_MOV,S_L,left.location.registerhigh,
  1643. hregister2);
  1644. end
  1645. end
  1646. else
  1647. begin
  1648. ungetiftemp(left.location.reference);
  1649. del_reference(left.location.reference);
  1650. if is_in_dest then
  1651. begin
  1652. hregister:=location.registerlow;
  1653. hregister2:=location.registerhigh;
  1654. emit_mov_ref_reg64(left.location.reference,hregister,hregister2);
  1655. end
  1656. else
  1657. begin
  1658. hregister:=getregister32;
  1659. hregister2:=getregister32;
  1660. emit_mov_ref_reg64(left.location.reference,hregister,hregister2);
  1661. end;
  1662. end;
  1663. clear_location(location);
  1664. location.loc:=LOC_REGISTER;
  1665. location.registerlow:=hregister;
  1666. location.registerhigh:=hregister2;
  1667. end
  1668. else
  1669. { if on the right the register then swap }
  1670. if not(noswap) and (right.location.loc=LOC_REGISTER) then
  1671. begin
  1672. swap_location(location,right.location);
  1673. { newly swapped also set swapped flag }
  1674. swaped:=not(swaped);
  1675. end;
  1676. { at this point, location.loc should be LOC_REGISTER }
  1677. { and location.register should be a valid register }
  1678. { containing the left result }
  1679. if right.location.loc<>LOC_REGISTER then
  1680. begin
  1681. if (treetype=subn) and swaped then
  1682. begin
  1683. if right.location.loc=LOC_CREGISTER then
  1684. begin
  1685. {$ifndef noAllocEdi}
  1686. getexplicitregister32(R_EDI);
  1687. {$endif noAllocEdi}
  1688. emit_reg_reg(A_MOV,opsize,right.location.register,R_EDI);
  1689. emit_reg_reg(op,opsize,location.register,R_EDI);
  1690. emit_reg_reg(A_MOV,opsize,R_EDI,location.register);
  1691. {$ifndef noAllocEdi}
  1692. ungetregister32(R_EDI);
  1693. getexplicitregister32(R_EDI);
  1694. {$endif noAllocEdi}
  1695. emit_reg_reg(A_MOV,opsize,right.location.registerhigh,R_EDI);
  1696. { the carry flag is still ok }
  1697. emit_reg_reg(op2,opsize,location.registerhigh,R_EDI);
  1698. emit_reg_reg(A_MOV,opsize,R_EDI,location.registerhigh);
  1699. {$ifndef noAllocEdi}
  1700. ungetregister32(R_EDI);
  1701. {$endif noAllocEdi}
  1702. end
  1703. else
  1704. begin
  1705. {$ifndef noAllocEdi}
  1706. getexplicitregister32(R_EDI);
  1707. {$endif noAllocEdi}
  1708. emit_ref_reg(A_MOV,opsize,
  1709. newreference(right.location.reference),R_EDI);
  1710. emit_reg_reg(op,opsize,location.registerlow,R_EDI);
  1711. emit_reg_reg(A_MOV,opsize,R_EDI,location.registerlow);
  1712. {$ifndef noAllocEdi}
  1713. ungetregister32(R_EDI);
  1714. getexplicitregister32(R_EDI);
  1715. {$endif noAllocEdi}
  1716. hr:=newreference(right.location.reference);
  1717. inc(hr^.offset,4);
  1718. emit_ref_reg(A_MOV,opsize,
  1719. hr,R_EDI);
  1720. { here the carry flag is still preserved }
  1721. emit_reg_reg(op2,opsize,location.registerhigh,R_EDI);
  1722. emit_reg_reg(A_MOV,opsize,R_EDI,
  1723. location.registerhigh);
  1724. {$ifndef noAllocEdi}
  1725. ungetregister32(R_EDI);
  1726. {$endif noAllocEdi}
  1727. ungetiftemp(right.location.reference);
  1728. del_reference(right.location.reference);
  1729. end;
  1730. end
  1731. else if cmpop then
  1732. begin
  1733. if (right.location.loc=LOC_CREGISTER) then
  1734. begin
  1735. emit_reg_reg(A_CMP,S_L,right.location.registerhigh,
  1736. location.registerhigh);
  1737. firstjmp64bitcmp;
  1738. emit_reg_reg(A_CMP,S_L,right.location.registerlow,
  1739. location.registerlow);
  1740. secondjmp64bitcmp;
  1741. end
  1742. else
  1743. begin
  1744. hr:=newreference(right.location.reference);
  1745. inc(hr^.offset,4);
  1746. emit_ref_reg(A_CMP,S_L,
  1747. hr,location.registerhigh);
  1748. firstjmp64bitcmp;
  1749. emit_ref_reg(A_CMP,S_L,newreference(
  1750. right.location.reference),location.registerlow);
  1751. secondjmp64bitcmp;
  1752. emitjmp(C_None,falselabel);
  1753. ungetiftemp(right.location.reference);
  1754. del_reference(right.location.reference);
  1755. end;
  1756. end
  1757. else
  1758. begin
  1759. {
  1760. if (right.treetype=ordconstn) and
  1761. (op=A_CMP) and
  1762. (right.value=0) then
  1763. begin
  1764. emit_reg_reg(A_TEST,opsize,location.register,
  1765. location.register);
  1766. end
  1767. else if (right.treetype=ordconstn) and
  1768. (op=A_IMUL) and
  1769. (ispowerof2(right.value,power)) then
  1770. begin
  1771. emit_const_reg(A_SHL,opsize,power,
  1772. location.register);
  1773. end
  1774. else
  1775. }
  1776. begin
  1777. if (right.location.loc=LOC_CREGISTER) then
  1778. begin
  1779. emit_reg_reg(op,S_L,right.location.registerlow,
  1780. location.registerlow);
  1781. emit_reg_reg(op2,S_L,right.location.registerhigh,
  1782. location.registerhigh);
  1783. end
  1784. else
  1785. begin
  1786. emit_ref_reg(op,S_L,newreference(
  1787. right.location.reference),location.registerlow);
  1788. hr:=newreference(right.location.reference);
  1789. inc(hr^.offset,4);
  1790. emit_ref_reg(op2,S_L,
  1791. hr,location.registerhigh);
  1792. ungetiftemp(right.location.reference);
  1793. del_reference(right.location.reference);
  1794. end;
  1795. end;
  1796. end;
  1797. end
  1798. else
  1799. begin
  1800. { when swapped another result register }
  1801. if (treetype=subn) and swaped then
  1802. begin
  1803. emit_reg_reg(op,S_L,
  1804. location.registerlow,
  1805. right.location.registerlow);
  1806. emit_reg_reg(op2,S_L,
  1807. location.registerhigh,
  1808. right.location.registerhigh);
  1809. swap_location(location,right.location);
  1810. { newly swapped also set swapped flag }
  1811. { just to maintain ordering }
  1812. swaped:=not(swaped);
  1813. end
  1814. else if cmpop then
  1815. begin
  1816. emit_reg_reg(A_CMP,S_L,
  1817. right.location.registerhigh,
  1818. location.registerhigh);
  1819. firstjmp64bitcmp;
  1820. emit_reg_reg(A_CMP,S_L,
  1821. right.location.registerlow,
  1822. location.registerlow);
  1823. secondjmp64bitcmp;
  1824. end
  1825. else
  1826. begin
  1827. emit_reg_reg(op,S_L,
  1828. right.location.registerlow,
  1829. location.registerlow);
  1830. emit_reg_reg(op2,S_L,
  1831. right.location.registerhigh,
  1832. location.registerhigh);
  1833. end;
  1834. ungetregister32(right.location.registerlow);
  1835. ungetregister32(right.location.registerhigh);
  1836. end;
  1837. if cmpop then
  1838. begin
  1839. ungetregister32(location.registerlow);
  1840. ungetregister32(location.registerhigh);
  1841. end;
  1842. { only in case of overflow operations }
  1843. { produce overflow code }
  1844. { we must put it here directly, because sign of operation }
  1845. { is in unsigned VAR!! }
  1846. if mboverflow then
  1847. begin
  1848. if cs_check_overflow in aktlocalswitches then
  1849. begin
  1850. getlabel(hl4);
  1851. if unsigned then
  1852. emitjmp(C_NB,hl4)
  1853. else
  1854. emitjmp(C_NO,hl4);
  1855. emitcall('FPC_OVERFLOW');
  1856. emitlab(hl4);
  1857. end;
  1858. end;
  1859. { we have LOC_JUMP as result }
  1860. if cmpop then
  1861. begin
  1862. clear_location(location);
  1863. location.loc:=LOC_JUMP;
  1864. cmpop:=false;
  1865. end;
  1866. end;
  1867. end
  1868. else
  1869. { Floating point }
  1870. if (left.resulttype^.deftype=floatdef) and
  1871. (pfloatdef(left.resulttype)^.typ<>f32bit) then
  1872. begin
  1873. { real constants to the right, but only if it
  1874. isn't on the FPU stack, i.e. 1.0 or 0.0! }
  1875. if (left.treetype=realconstn) and
  1876. (left.location.loc<>LOC_FPU) then
  1877. swaptree(p);
  1878. cmpop:=false;
  1879. case treetype of
  1880. addn : op:=A_FADDP;
  1881. muln : op:=A_FMULP;
  1882. subn : op:=A_FSUBP;
  1883. slashn : op:=A_FDIVP;
  1884. ltn,lten,gtn,gten,
  1885. equaln,unequaln : begin
  1886. op:=A_FCOMPP;
  1887. cmpop:=true;
  1888. end;
  1889. else CGMessage(type_e_mismatch);
  1890. end;
  1891. if (right.location.loc<>LOC_FPU) then
  1892. begin
  1893. if right.location.loc=LOC_CFPUREGISTER then
  1894. begin
  1895. emit_reg( A_FLD,S_NO,
  1896. correct_fpuregister(right.location.register,fpuvaroffset));
  1897. inc(fpuvaroffset);
  1898. end
  1899. else
  1900. floatload(pfloatdef(right.resulttype)^.typ,right.location.reference);
  1901. if (left.location.loc<>LOC_FPU) then
  1902. begin
  1903. if left.location.loc=LOC_CFPUREGISTER then
  1904. begin
  1905. emit_reg( A_FLD,S_NO,
  1906. correct_fpuregister(left.location.register,fpuvaroffset));
  1907. inc(fpuvaroffset);
  1908. end
  1909. else
  1910. floatload(pfloatdef(left.resulttype)^.typ,left.location.reference)
  1911. end
  1912. { left was on the stack => swap }
  1913. else
  1914. swaped:=not(swaped);
  1915. { releases the right reference }
  1916. del_reference(right.location.reference);
  1917. end
  1918. { the nominator in st0 }
  1919. else if (left.location.loc<>LOC_FPU) then
  1920. begin
  1921. if left.location.loc=LOC_CFPUREGISTER then
  1922. begin
  1923. emit_reg( A_FLD,S_NO,
  1924. correct_fpuregister(left.location.register,fpuvaroffset));
  1925. inc(fpuvaroffset);
  1926. end
  1927. else
  1928. floatload(pfloatdef(left.resulttype)^.typ,left.location.reference)
  1929. end
  1930. { fpu operands are always in the wrong order on the stack }
  1931. else
  1932. swaped:=not(swaped);
  1933. { releases the left reference }
  1934. if (left.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  1935. del_reference(left.location.reference);
  1936. { if we swaped the tree nodes, then use the reverse operator }
  1937. if swaped then
  1938. begin
  1939. if (treetype=slashn) then
  1940. op:=A_FDIVRP
  1941. else if (treetype=subn) then
  1942. op:=A_FSUBRP;
  1943. end;
  1944. { to avoid the pentium bug
  1945. if (op=FDIVP) and (opt_processors=pentium) then
  1946. emitcall('EMUL_FDIVP')
  1947. else
  1948. }
  1949. { the Intel assemblers want operands }
  1950. if op<>A_FCOMPP then
  1951. begin
  1952. emit_reg_reg(op,S_NO,R_ST,R_ST1);
  1953. dec(fpuvaroffset);
  1954. end
  1955. else
  1956. begin
  1957. emit_none(op,S_NO);
  1958. dec(fpuvaroffset,2);
  1959. end;
  1960. { on comparison load flags }
  1961. if cmpop then
  1962. begin
  1963. if not(R_EAX in unused) then
  1964. begin
  1965. {$ifndef noAllocEdi}
  1966. getexplicitregister32(R_EDI);
  1967. {$endif noAllocEdi}
  1968. emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
  1969. end;
  1970. emit_reg(A_FNSTSW,S_NO,R_AX);
  1971. emit_none(A_SAHF,S_NO);
  1972. if not(R_EAX in unused) then
  1973. begin
  1974. emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
  1975. {$ifndef noAllocEdi}
  1976. ungetregister32(R_EDI);
  1977. {$endif noAllocEdi}
  1978. end;
  1979. if swaped then
  1980. begin
  1981. case treetype of
  1982. equaln : flags:=F_E;
  1983. unequaln : flags:=F_NE;
  1984. ltn : flags:=F_A;
  1985. lten : flags:=F_AE;
  1986. gtn : flags:=F_B;
  1987. gten : flags:=F_BE;
  1988. end;
  1989. end
  1990. else
  1991. begin
  1992. case treetype of
  1993. equaln : flags:=F_E;
  1994. unequaln : flags:=F_NE;
  1995. ltn : flags:=F_B;
  1996. lten : flags:=F_BE;
  1997. gtn : flags:=F_A;
  1998. gten : flags:=F_AE;
  1999. end;
  2000. end;
  2001. clear_location(location);
  2002. location.loc:=LOC_FLAGS;
  2003. location.resflags:=flags;
  2004. cmpop:=false;
  2005. end
  2006. else
  2007. begin
  2008. clear_location(location);
  2009. location.loc:=LOC_FPU;
  2010. end;
  2011. end
  2012. {$ifdef SUPPORT_MMX}
  2013. else
  2014. { MMX Arrays }
  2015. if is_mmx_able_array(left.resulttype) then
  2016. begin
  2017. cmpop:=false;
  2018. mmxbase:=mmx_type(left.resulttype);
  2019. case treetype of
  2020. addn : begin
  2021. if (cs_mmx_saturation in aktlocalswitches) then
  2022. begin
  2023. case mmxbase of
  2024. mmxs8bit:
  2025. op:=A_PADDSB;
  2026. mmxu8bit:
  2027. op:=A_PADDUSB;
  2028. mmxs16bit,mmxfixed16:
  2029. op:=A_PADDSB;
  2030. mmxu16bit:
  2031. op:=A_PADDUSW;
  2032. end;
  2033. end
  2034. else
  2035. begin
  2036. case mmxbase of
  2037. mmxs8bit,mmxu8bit:
  2038. op:=A_PADDB;
  2039. mmxs16bit,mmxu16bit,mmxfixed16:
  2040. op:=A_PADDW;
  2041. mmxs32bit,mmxu32bit:
  2042. op:=A_PADDD;
  2043. end;
  2044. end;
  2045. end;
  2046. muln : begin
  2047. case mmxbase of
  2048. mmxs16bit,mmxu16bit:
  2049. op:=A_PMULLW;
  2050. mmxfixed16:
  2051. op:=A_PMULHW;
  2052. end;
  2053. end;
  2054. subn : begin
  2055. if (cs_mmx_saturation in aktlocalswitches) then
  2056. begin
  2057. case mmxbase of
  2058. mmxs8bit:
  2059. op:=A_PSUBSB;
  2060. mmxu8bit:
  2061. op:=A_PSUBUSB;
  2062. mmxs16bit,mmxfixed16:
  2063. op:=A_PSUBSB;
  2064. mmxu16bit:
  2065. op:=A_PSUBUSW;
  2066. end;
  2067. end
  2068. else
  2069. begin
  2070. case mmxbase of
  2071. mmxs8bit,mmxu8bit:
  2072. op:=A_PSUBB;
  2073. mmxs16bit,mmxu16bit,mmxfixed16:
  2074. op:=A_PSUBW;
  2075. mmxs32bit,mmxu32bit:
  2076. op:=A_PSUBD;
  2077. end;
  2078. end;
  2079. end;
  2080. {
  2081. ltn,lten,gtn,gten,
  2082. equaln,unequaln :
  2083. begin
  2084. op:=A_CMP;
  2085. cmpop:=true;
  2086. end;
  2087. }
  2088. xorn:
  2089. op:=A_PXOR;
  2090. orn:
  2091. op:=A_POR;
  2092. andn:
  2093. op:=A_PAND;
  2094. else CGMessage(type_e_mismatch);
  2095. end;
  2096. { left and right no register? }
  2097. { then one must be demanded }
  2098. if (left.location.loc<>LOC_MMXREGISTER) and
  2099. (right.location.loc<>LOC_MMXREGISTER) then
  2100. begin
  2101. { register variable ? }
  2102. if (left.location.loc=LOC_CMMXREGISTER) then
  2103. begin
  2104. { it is OK if this is the destination }
  2105. if is_in_dest then
  2106. begin
  2107. hregister:=location.register;
  2108. emit_reg_reg(A_MOVQ,S_NO,left.location.register,
  2109. hregister);
  2110. end
  2111. else
  2112. begin
  2113. hregister:=getregistermmx;
  2114. emit_reg_reg(A_MOVQ,S_NO,left.location.register,
  2115. hregister);
  2116. end
  2117. end
  2118. else
  2119. begin
  2120. del_reference(left.location.reference);
  2121. if is_in_dest then
  2122. begin
  2123. hregister:=location.register;
  2124. emit_ref_reg(A_MOVQ,S_NO,
  2125. newreference(left.location.reference),hregister);
  2126. end
  2127. else
  2128. begin
  2129. hregister:=getregistermmx;
  2130. emit_ref_reg(A_MOVQ,S_NO,
  2131. newreference(left.location.reference),hregister);
  2132. end;
  2133. end;
  2134. clear_location(location);
  2135. location.loc:=LOC_MMXREGISTER;
  2136. location.register:=hregister;
  2137. end
  2138. else
  2139. { if on the right the register then swap }
  2140. if (right.location.loc=LOC_MMXREGISTER) then
  2141. begin
  2142. swap_location(location,right.location);
  2143. { newly swapped also set swapped flag }
  2144. swaped:=not(swaped);
  2145. end;
  2146. { at this point, location.loc should be LOC_MMXREGISTER }
  2147. { and location.register should be a valid register }
  2148. { containing the left result }
  2149. if right.location.loc<>LOC_MMXREGISTER then
  2150. begin
  2151. if (treetype=subn) and swaped then
  2152. begin
  2153. if right.location.loc=LOC_CMMXREGISTER then
  2154. begin
  2155. emit_reg_reg(A_MOVQ,S_NO,right.location.register,R_MM7);
  2156. emit_reg_reg(op,S_NO,location.register,R_MM0);
  2157. emit_reg_reg(A_MOVQ,S_NO,R_MM7,location.register);
  2158. end
  2159. else
  2160. begin
  2161. emit_ref_reg(A_MOVQ,S_NO,
  2162. newreference(right.location.reference),R_MM7);
  2163. emit_reg_reg(op,S_NO,location.register,
  2164. R_MM7);
  2165. emit_reg_reg(A_MOVQ,S_NO,
  2166. R_MM7,location.register);
  2167. del_reference(right.location.reference);
  2168. end;
  2169. end
  2170. else
  2171. begin
  2172. if (right.location.loc=LOC_CREGISTER) then
  2173. begin
  2174. emit_reg_reg(op,S_NO,right.location.register,
  2175. location.register);
  2176. end
  2177. else
  2178. begin
  2179. emit_ref_reg(op,S_NO,newreference(
  2180. right.location.reference),location.register);
  2181. del_reference(right.location.reference);
  2182. end;
  2183. end;
  2184. end
  2185. else
  2186. begin
  2187. { when swapped another result register }
  2188. if (treetype=subn) and swaped then
  2189. begin
  2190. emit_reg_reg(op,S_NO,
  2191. location.register,right.location.register);
  2192. swap_location(location,right.location);
  2193. { newly swapped also set swapped flag }
  2194. { just to maintain ordering }
  2195. swaped:=not(swaped);
  2196. end
  2197. else
  2198. begin
  2199. emit_reg_reg(op,S_NO,
  2200. right.location.register,
  2201. location.register);
  2202. end;
  2203. ungetregistermmx(right.location.register);
  2204. end;
  2205. end
  2206. {$endif SUPPORT_MMX}
  2207. else CGMessage(type_e_mismatch);
  2208. end;
  2209. SetResultLocation(cmpop,unsigned);
  2210. end;
  2211. procedure ti386addnode.pass_2;
  2212. begin
  2213. end;
  2214. begin
  2215. caddnode:=ti386addnode;
  2216. end.
  2217. {
  2218. $Log$
  2219. Revision 1.4 2000-09-24 15:06:18 peter
  2220. * use defines.inc
  2221. Revision 1.3 2000/09/22 22:42:52 florian
  2222. * more fixes
  2223. Revision 1.2 2000/09/21 12:24:22 jonas
  2224. * small fix to my changes for full boolean evaluation support (moved
  2225. opsize determination for boolean operations back in boolean
  2226. processing block)
  2227. + full boolean evaluation support (from cg386add)
  2228. Revision 1.1 2000/09/20 21:23:32 florian
  2229. * initial revision
  2230. }