cg386add.pas 111 KB

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