cg386add.pas 111 KB

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