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