cg386add.pas 115 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486
  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. {$IfNDef regallocfix}
  602. del_location(p^.left^.location);
  603. del_location(p^.right^.location);
  604. pushusedregisters(pushedregs,$ff);
  605. {$EndIf regallocfix}
  606. href.symbol:=nil;
  607. gettempofsizereference(32,href);
  608. emitpushreferenceaddr(href);
  609. emitpushreferenceaddr(p^.right^.location.reference);
  610. {$IfDef regallocfix}
  611. del_location(p^.right^.location);
  612. {$EndIf regallocfix}
  613. emitpushreferenceaddr(p^.left^.location.reference);
  614. {$IfDef regallocfix}
  615. del_location(p^.left^.location);
  616. {$EndIf regallocfix}
  617. case p^.treetype of
  618. subn : emitcall('FPC_SET_SUB_SETS');
  619. symdifn : emitcall('FPC_SET_SYMDIF_SETS');
  620. muln : emitcall('FPC_SET_MUL_SETS');
  621. end;
  622. maybe_loadesi;
  623. popusedregisters(pushedregs);
  624. ungetiftemp(p^.left^.location.reference);
  625. ungetiftemp(p^.right^.location.reference);
  626. p^.location.loc:=LOC_MEM;
  627. p^.location.reference:=href;
  628. end;
  629. else
  630. CGMessage(type_e_mismatch);
  631. end;
  632. SetResultLocation(cmpop,true,p);
  633. end;
  634. {*****************************************************************************
  635. SecondAdd
  636. *****************************************************************************}
  637. procedure secondadd(var p : ptree);
  638. { is also being used for xor, and "mul", "sub, or and comparative }
  639. { operators }
  640. label do_normal;
  641. var
  642. hregister,hregister2 : tregister;
  643. noswap,popeax,popedx,
  644. pushed,mboverflow,cmpop : boolean;
  645. op,op2 : tasmop;
  646. flags : tresflags;
  647. otl,ofl,hl : pasmlabel;
  648. power : longint;
  649. opsize : topsize;
  650. hl4: pasmlabel;
  651. hr : preference;
  652. { true, if unsigned types are compared }
  653. unsigned : boolean;
  654. { true, if a small set is handled with the longint code }
  655. is_set : boolean;
  656. { is_in_dest if the result is put directly into }
  657. { the resulting refernce or varregister }
  658. is_in_dest : boolean;
  659. { true, if for sets subtractions the extra not should generated }
  660. extra_not : boolean;
  661. {$ifdef SUPPORT_MMX}
  662. mmxbase : tmmxtype;
  663. {$endif SUPPORT_MMX}
  664. pushedreg : tpushed;
  665. hloc : tlocation;
  666. regstopush: byte;
  667. procedure firstjmp64bitcmp;
  668. var
  669. oldtreetype : ttreetyp;
  670. begin
  671. { the jump the sequence is a little bit hairy }
  672. case p^.treetype of
  673. ltn,gtn:
  674. begin
  675. emitjmp(flag_2_cond[getresflags(p,unsigned)],truelabel);
  676. { cheat a little bit for the negative test }
  677. p^.swaped:=not(p^.swaped);
  678. emitjmp(flag_2_cond[getresflags(p,unsigned)],falselabel);
  679. p^.swaped:=not(p^.swaped);
  680. end;
  681. lten,gten:
  682. begin
  683. oldtreetype:=p^.treetype;
  684. if p^.treetype=lten then
  685. p^.treetype:=ltn
  686. else
  687. p^.treetype:=gtn;
  688. emitjmp(flag_2_cond[getresflags(p,unsigned)],truelabel);
  689. { cheat for the negative test }
  690. if p^.treetype=ltn then
  691. p^.treetype:=gtn
  692. else
  693. p^.treetype:=ltn;
  694. emitjmp(flag_2_cond[getresflags(p,unsigned)],falselabel);
  695. p^.treetype:=oldtreetype;
  696. end;
  697. equaln:
  698. emitjmp(C_NE,falselabel);
  699. unequaln:
  700. emitjmp(C_NE,truelabel);
  701. end;
  702. end;
  703. procedure secondjmp64bitcmp;
  704. begin
  705. { the jump the sequence is a little bit hairy }
  706. case p^.treetype of
  707. ltn,gtn,lten,gten:
  708. begin
  709. { the comparisaion of the low dword have to be }
  710. { always unsigned! }
  711. emitjmp(flag_2_cond[getresflags(p,true)],truelabel);
  712. emitjmp(C_None,falselabel);
  713. end;
  714. equaln:
  715. begin
  716. emitjmp(C_NE,falselabel);
  717. emitjmp(C_None,truelabel);
  718. end;
  719. unequaln:
  720. begin
  721. emitjmp(C_NE,truelabel);
  722. emitjmp(C_None,falselabel);
  723. end;
  724. end;
  725. end;
  726. begin
  727. { to make it more readable, string and set (not smallset!) have their
  728. own procedures }
  729. case p^.left^.resulttype^.deftype of
  730. stringdef : begin
  731. addstring(p);
  732. exit;
  733. end;
  734. setdef : begin
  735. { normalsets are handled separate }
  736. if not(psetdef(p^.left^.resulttype)^.settype=smallset) then
  737. begin
  738. addset(p);
  739. exit;
  740. end;
  741. end;
  742. end;
  743. { defaults }
  744. unsigned:=false;
  745. is_in_dest:=false;
  746. extra_not:=false;
  747. noswap:=false;
  748. opsize:=S_L;
  749. { are we a (small)set, must be set here because the side can be
  750. swapped ! (PFV) }
  751. is_set:=(p^.left^.resulttype^.deftype=setdef);
  752. { calculate the operator which is more difficult }
  753. firstcomplex(p);
  754. { handling boolean expressions extra: }
  755. if is_boolean(p^.left^.resulttype) and
  756. is_boolean(p^.right^.resulttype) then
  757. begin
  758. if (porddef(p^.left^.resulttype)^.typ=bool8bit) or
  759. (porddef(p^.right^.resulttype)^.typ=bool8bit) then
  760. opsize:=S_B
  761. else
  762. if (porddef(p^.left^.resulttype)^.typ=bool16bit) or
  763. (porddef(p^.right^.resulttype)^.typ=bool16bit) then
  764. opsize:=S_W
  765. else
  766. opsize:=S_L;
  767. case p^.treetype of
  768. andn,
  769. orn : begin
  770. clear_location(p^.location);
  771. p^.location.loc:=LOC_JUMP;
  772. cmpop:=false;
  773. case p^.treetype of
  774. andn : begin
  775. otl:=truelabel;
  776. getlabel(truelabel);
  777. secondpass(p^.left);
  778. maketojumpbool(p^.left);
  779. emitlab(truelabel);
  780. truelabel:=otl;
  781. end;
  782. orn : begin
  783. ofl:=falselabel;
  784. getlabel(falselabel);
  785. secondpass(p^.left);
  786. maketojumpbool(p^.left);
  787. emitlab(falselabel);
  788. falselabel:=ofl;
  789. end;
  790. else
  791. CGMessage(type_e_mismatch);
  792. end;
  793. secondpass(p^.right);
  794. maketojumpbool(p^.right);
  795. end;
  796. unequaln,ltn,lten,gtn,gten,
  797. equaln,xorn : begin
  798. if p^.left^.treetype=ordconstn then
  799. swaptree(p);
  800. if p^.left^.location.loc=LOC_JUMP then
  801. begin
  802. otl:=truelabel;
  803. getlabel(truelabel);
  804. ofl:=falselabel;
  805. getlabel(falselabel);
  806. end;
  807. secondpass(p^.left);
  808. { if in flags then copy first to register, because the
  809. flags can be destroyed }
  810. case p^.left^.location.loc of
  811. LOC_FLAGS:
  812. locflags2reg(p^.left^.location,opsize);
  813. LOC_JUMP:
  814. begin
  815. case opsize of
  816. S_L : hregister:=getregister32;
  817. S_W : hregister:=reg32toreg16(getregister32);
  818. S_B : hregister:=reg32toreg8(getregister32);
  819. end;
  820. p^.left^.location.loc:=LOC_REGISTER;
  821. p^.left^.location.register:=hregister;
  822. emitlab(truelabel);
  823. truelabel:=otl;
  824. emit_const_reg(A_MOV,opsize,1,hregister);
  825. getlabel(hl);
  826. emitjmp(C_None,hl);
  827. emitlab(falselabel);
  828. falselabel:=ofl;
  829. emit_reg_reg(A_XOR,S_L,makereg32(hregister),
  830. makereg32(hregister));
  831. emitlab(hl);
  832. end;
  833. end;
  834. set_location(p^.location,p^.left^.location);
  835. pushed:=maybe_push(p^.right^.registers32,p,false);
  836. if p^.right^.location.loc=LOC_JUMP then
  837. begin
  838. otl:=truelabel;
  839. getlabel(truelabel);
  840. ofl:=falselabel;
  841. getlabel(falselabel);
  842. end;
  843. secondpass(p^.right);
  844. if pushed then
  845. begin
  846. restore(p,false);
  847. set_location(p^.left^.location,p^.location);
  848. end;
  849. case p^.right^.location.loc of
  850. LOC_FLAGS:
  851. locflags2reg(p^.right^.location,opsize);
  852. LOC_JUMP:
  853. begin
  854. case opsize of
  855. S_L : hregister:=getregister32;
  856. S_W : hregister:=reg32toreg16(getregister32);
  857. S_B : hregister:=reg32toreg8(getregister32);
  858. end;
  859. p^.right^.location.loc:=LOC_REGISTER;
  860. p^.right^.location.register:=hregister;
  861. emitlab(truelabel);
  862. truelabel:=otl;
  863. emit_const_reg(A_MOV,opsize,1,hregister);
  864. getlabel(hl);
  865. emitjmp(C_None,hl);
  866. emitlab(falselabel);
  867. falselabel:=ofl;
  868. emit_reg_reg(A_XOR,S_L,makereg32(hregister),
  869. makereg32(hregister));
  870. emitlab(hl);
  871. end;
  872. end;
  873. goto do_normal;
  874. end
  875. else
  876. CGMessage(type_e_mismatch);
  877. end
  878. end
  879. else
  880. begin
  881. { in case of constant put it to the left }
  882. if (p^.left^.treetype=ordconstn) then
  883. swaptree(p);
  884. secondpass(p^.left);
  885. { this will be complicated as
  886. a lot of code below assumes that
  887. p^.location and p^.left^.location are the same }
  888. {$ifdef test_dest_loc}
  889. if dest_loc_known and (dest_loc_tree=p) and
  890. ((dest_loc.loc=LOC_REGISTER) or (dest_loc.loc=LOC_CREGISTER)) then
  891. begin
  892. set_location(p^.location,dest_loc);
  893. in_dest_loc:=true;
  894. is_in_dest:=true;
  895. end
  896. else
  897. {$endif test_dest_loc}
  898. set_location(p^.location,p^.left^.location);
  899. { are too few registers free? }
  900. pushed:=maybe_push(p^.right^.registers32,p,is_64bitint(p^.left^.resulttype));
  901. secondpass(p^.right);
  902. if pushed then
  903. begin
  904. restore(p,is_64bitint(p^.left^.resulttype));
  905. set_location(p^.left^.location,p^.location);
  906. end;
  907. if (p^.left^.resulttype^.deftype=pointerdef) or
  908. (p^.right^.resulttype^.deftype=pointerdef) or
  909. ((p^.right^.resulttype^.deftype=objectdef) and
  910. pobjectdef(p^.right^.resulttype)^.is_class and
  911. (p^.left^.resulttype^.deftype=objectdef) and
  912. pobjectdef(p^.left^.resulttype)^.is_class
  913. ) or
  914. (p^.left^.resulttype^.deftype=classrefdef) or
  915. (p^.left^.resulttype^.deftype=procvardef) or
  916. ((p^.left^.resulttype^.deftype=enumdef) and
  917. (p^.left^.resulttype^.size=4)) or
  918. ((p^.left^.resulttype^.deftype=orddef) and
  919. (porddef(p^.left^.resulttype)^.typ=s32bit)) or
  920. ((p^.right^.resulttype^.deftype=orddef) and
  921. (porddef(p^.right^.resulttype)^.typ=s32bit)) or
  922. ((p^.left^.resulttype^.deftype=orddef) and
  923. (porddef(p^.left^.resulttype)^.typ=u32bit)) or
  924. ((p^.right^.resulttype^.deftype=orddef) and
  925. (porddef(p^.right^.resulttype)^.typ=u32bit)) or
  926. { as well as small sets }
  927. is_set then
  928. begin
  929. do_normal:
  930. mboverflow:=false;
  931. cmpop:=false;
  932. {$ifndef cardinalmulfix}
  933. unsigned :=
  934. (p^.left^.resulttype^.deftype=pointerdef) or
  935. (p^.right^.resulttype^.deftype=pointerdef) or
  936. ((p^.left^.resulttype^.deftype=orddef) and
  937. (porddef(p^.left^.resulttype)^.typ=u32bit)) or
  938. ((p^.right^.resulttype^.deftype=orddef) and
  939. (porddef(p^.right^.resulttype)^.typ=u32bit));
  940. {$else cardinalmulfix}
  941. unsigned := not(is_signed(p^.left^.resulttype)) or
  942. not(is_signed(p^.right^.resulttype));
  943. {$endif cardinalmulfix}
  944. case p^.treetype of
  945. addn : begin
  946. { this is a really ugly hack!!!!!!!!!! }
  947. { this could be done later using EDI }
  948. { as it is done for subn }
  949. { instead of two registers!!!! }
  950. if is_set then
  951. begin
  952. { adding elements is not commutative }
  953. if p^.swaped and (p^.left^.treetype=setelementn) then
  954. swaptree(p);
  955. { are we adding set elements ? }
  956. if p^.right^.treetype=setelementn then
  957. begin
  958. { no range support for smallsets! }
  959. if assigned(p^.right^.right) then
  960. internalerror(43244);
  961. { bts requires both elements to be registers }
  962. if p^.left^.location.loc in [LOC_MEM,LOC_REFERENCE] then
  963. begin
  964. ungetiftemp(p^.left^.location.reference);
  965. del_location(p^.left^.location);
  966. {!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
  967. hregister:=getregister32;
  968. emit_ref_reg(A_MOV,opsize,
  969. newreference(p^.left^.location.reference),hregister);
  970. clear_location(p^.left^.location);
  971. p^.left^.location.loc:=LOC_REGISTER;
  972. p^.left^.location.register:=hregister;
  973. set_location(p^.location,p^.left^.location);
  974. end;
  975. if p^.right^.location.loc in [LOC_MEM,LOC_REFERENCE] then
  976. begin
  977. ungetiftemp(p^.right^.location.reference);
  978. del_location(p^.right^.location);
  979. hregister:=getregister32;
  980. emit_ref_reg(A_MOV,opsize,
  981. newreference(p^.right^.location.reference),hregister);
  982. clear_location(p^.right^.location);
  983. p^.right^.location.loc:=LOC_REGISTER;
  984. p^.right^.location.register:=hregister;
  985. end;
  986. op:=A_BTS;
  987. noswap:=true;
  988. end
  989. else
  990. op:=A_OR;
  991. mboverflow:=false;
  992. unsigned:=false;
  993. end
  994. else
  995. begin
  996. op:=A_ADD;
  997. mboverflow:=true;
  998. end;
  999. end;
  1000. symdifn : begin
  1001. { the symetric diff is only for sets }
  1002. if is_set then
  1003. begin
  1004. op:=A_XOR;
  1005. mboverflow:=false;
  1006. unsigned:=false;
  1007. end
  1008. else
  1009. CGMessage(type_e_mismatch);
  1010. end;
  1011. muln : begin
  1012. if is_set then
  1013. begin
  1014. op:=A_AND;
  1015. mboverflow:=false;
  1016. unsigned:=false;
  1017. end
  1018. else
  1019. begin
  1020. if unsigned then
  1021. op:=A_MUL
  1022. else
  1023. op:=A_IMUL;
  1024. mboverflow:=true;
  1025. end;
  1026. end;
  1027. subn : begin
  1028. if is_set then
  1029. begin
  1030. op:=A_AND;
  1031. mboverflow:=false;
  1032. unsigned:=false;
  1033. {$IfNDef NoSetConstNot}
  1034. If (p^.right^.treetype = setconstn) then
  1035. p^.right^.location.reference.offset := not(p^.right^.location.reference.offset)
  1036. Else
  1037. {$EndIf NoNosetConstNot}
  1038. extra_not:=true;
  1039. end
  1040. else
  1041. begin
  1042. op:=A_SUB;
  1043. mboverflow:=true;
  1044. end;
  1045. end;
  1046. ltn,lten,
  1047. gtn,gten,
  1048. equaln,unequaln : begin
  1049. {$IfNDef NoSetInclusion}
  1050. If is_set Then
  1051. Case p^.treetype of
  1052. lten,gten:
  1053. Begin
  1054. If p^.treetype = lten then
  1055. swaptree(p);
  1056. if p^.left^.location.loc in [LOC_MEM,LOC_REFERENCE] then
  1057. begin
  1058. ungetiftemp(p^.left^.location.reference);
  1059. del_reference(p^.left^.location.reference);
  1060. hregister:=getregister32;
  1061. emit_ref_reg(A_MOV,opsize,
  1062. newreference(p^.left^.location.reference),hregister);
  1063. clear_location(p^.left^.location);
  1064. p^.left^.location.loc:=LOC_REGISTER;
  1065. p^.left^.location.register:=hregister;
  1066. set_location(p^.location,p^.left^.location);
  1067. end
  1068. else
  1069. if p^.left^.location.loc = LOC_CREGISTER Then
  1070. {save the register var in a temp register, because
  1071. its value is going to be modified}
  1072. begin
  1073. hregister := getregister32;
  1074. emit_reg_reg(A_MOV,opsize,
  1075. p^.left^.location.register,hregister);
  1076. clear_location(p^.left^.location);
  1077. p^.left^.location.loc:=LOC_REGISTER;
  1078. p^.left^.location.register:=hregister;
  1079. set_location(p^.location,p^.left^.location);
  1080. end;
  1081. {here, p^.left^.location should be LOC_REGISTER}
  1082. If p^.right^.location.loc in [LOC_MEM,LOC_REFERENCE] Then
  1083. emit_ref_reg(A_AND,opsize,
  1084. newreference(p^.right^.location.reference),p^.left^.location.register)
  1085. Else
  1086. emit_reg_reg(A_AND,opsize,
  1087. p^.right^.location.register,p^.left^.location.register);
  1088. {warning: ugly hack ahead: we need a "jne" after the cmp, so
  1089. change the treetype from lten/gten to equaln}
  1090. p^.treetype := equaln
  1091. End;
  1092. {no < or > support for sets}
  1093. ltn,gtn: CGMessage(type_e_mismatch);
  1094. End;
  1095. {$EndIf NoSetInclusion}
  1096. op:=A_CMP;
  1097. cmpop:=true;
  1098. end;
  1099. xorn : op:=A_XOR;
  1100. orn : op:=A_OR;
  1101. andn : op:=A_AND;
  1102. else
  1103. CGMessage(type_e_mismatch);
  1104. end;
  1105. { filter MUL, which requires special handling }
  1106. if op=A_MUL then
  1107. begin
  1108. popeax:=false;
  1109. popedx:=false;
  1110. { here you need to free the symbol first }
  1111. { p^.left^.location and p^.right^.location must }
  1112. { only be freed when they are really released, }
  1113. { because the optimizer NEEDS correct regalloc }
  1114. { info!!! (JM) }
  1115. clear_location(p^.location);
  1116. { the p^.location.register will be filled in later (JM) }
  1117. p^.location.loc:=LOC_REGISTER;
  1118. {$IfNDef NoShlMul}
  1119. if p^.right^.treetype=ordconstn then
  1120. swaptree(p);
  1121. If (p^.left^.treetype = ordconstn) and
  1122. ispowerof2(p^.left^.value, power) and
  1123. not(cs_check_overflow in aktlocalswitches) then
  1124. Begin
  1125. { This release will be moved after the next }
  1126. { instruction by the optimizer. No need to }
  1127. { release p^.left^.location, since it's a }
  1128. { constant (JM) }
  1129. release_loc(p^.right^.location);
  1130. p^.location.register := getregister32;
  1131. emitloadord2reg(p^.right^.location,u32bitdef,p^.location.register,true);
  1132. emit_const_reg(A_SHL,S_L,power,p^.location.register)
  1133. End
  1134. Else
  1135. Begin
  1136. {$EndIf NoShlMul}
  1137. regstopush := $ff;
  1138. remove_non_regvars_from_loc(p^.right^.location,regstopush);
  1139. remove_non_regvars_from_loc(p^.left^.location,regstopush);
  1140. { now, regstopush does NOT contain EAX and/or EDX if they are }
  1141. { used in either the left or the right location, excepts if }
  1142. {they are regvars. It DOES contain them if they are used in }
  1143. { another location (JM) }
  1144. if not(R_EAX in unused) and ((regstopush and ($80 shr byte(R_EAX))) <> 0) then
  1145. begin
  1146. emit_reg(A_PUSH,S_L,R_EAX);
  1147. popeax:=true;
  1148. end;
  1149. if not(R_EDX in unused) and ((regstopush and ($80 shr byte(R_EDX))) <> 0) then
  1150. begin
  1151. emit_reg(A_PUSH,S_L,R_EDX);
  1152. popedx:=true;
  1153. end;
  1154. { p^.left^.location can be R_EAX !!! }
  1155. {$ifndef noAllocEdi}
  1156. getexplicitregister32(R_EDI);
  1157. {$endif noAllocEdi}
  1158. { load the left value }
  1159. emitloadord2reg(p^.left^.location,u32bitdef,R_EDI,true);
  1160. release_loc(p^.left^.location);
  1161. { allocate EAX }
  1162. if R_EAX in unused then
  1163. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1164. { load he right value }
  1165. emitloadord2reg(p^.right^.location,u32bitdef,R_EAX,true);
  1166. release_loc(p^.right^.location);
  1167. { allocate EAX if it isn't yet allocated (JM) }
  1168. if (R_EAX in unused) then
  1169. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1170. {$ifndef noAllocEdi}
  1171. { also allocate EDX, since it is also modified by }
  1172. { a mul (JM) }
  1173. if R_EDX in unused then
  1174. exprasmlist^.concat(new(pairegalloc,alloc(R_EDX)));
  1175. {$endif noAllocEdi}
  1176. emit_reg(A_MUL,S_L,R_EDI);
  1177. {$ifndef noAllocEdi}
  1178. ungetregister32(R_EDI);
  1179. if R_EDX in unused then
  1180. exprasmlist^.concat(new(pairegalloc,dealloc(R_EDX)));
  1181. {$endif noAllocEdi}
  1182. if R_EAX in unused then
  1183. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  1184. p^.location.register := getregister32;
  1185. emit_reg_reg(A_MOV,S_L,R_EAX,p^.location.register);
  1186. if popedx then
  1187. emit_reg(A_POP,S_L,R_EDX);
  1188. if popeax then
  1189. emit_reg(A_POP,S_L,R_EAX);
  1190. {$IfNDef NoShlMul}
  1191. End;
  1192. {$endif NoShlMul}
  1193. SetResultLocation(false,true,p);
  1194. exit;
  1195. end;
  1196. { Convert flags to register first }
  1197. if (p^.left^.location.loc=LOC_FLAGS) then
  1198. locflags2reg(p^.left^.location,opsize);
  1199. if (p^.right^.location.loc=LOC_FLAGS) then
  1200. locflags2reg(p^.right^.location,opsize);
  1201. { left and right no register? }
  1202. { then one must be demanded }
  1203. if (p^.left^.location.loc<>LOC_REGISTER) and
  1204. (p^.right^.location.loc<>LOC_REGISTER) then
  1205. begin
  1206. { register variable ? }
  1207. if (p^.left^.location.loc=LOC_CREGISTER) then
  1208. begin
  1209. { it is OK if this is the destination }
  1210. if is_in_dest then
  1211. begin
  1212. hregister:=p^.location.register;
  1213. emit_reg_reg(A_MOV,opsize,p^.left^.location.register,
  1214. hregister);
  1215. end
  1216. else
  1217. if cmpop then
  1218. begin
  1219. { do not disturb the register }
  1220. hregister:=p^.location.register;
  1221. end
  1222. else
  1223. begin
  1224. case opsize of
  1225. S_L : hregister:=getregister32;
  1226. S_B : hregister:=reg32toreg8(getregister32);
  1227. end;
  1228. emit_reg_reg(A_MOV,opsize,p^.left^.location.register,
  1229. hregister);
  1230. end
  1231. end
  1232. else
  1233. begin
  1234. ungetiftemp(p^.left^.location.reference);
  1235. del_reference(p^.left^.location.reference);
  1236. if is_in_dest then
  1237. begin
  1238. hregister:=p^.location.register;
  1239. emit_ref_reg(A_MOV,opsize,
  1240. newreference(p^.left^.location.reference),hregister);
  1241. end
  1242. else
  1243. begin
  1244. { first give free, then demand new register }
  1245. case opsize of
  1246. S_L : hregister:=getregister32;
  1247. S_W : hregister:=reg32toreg16(getregister32);
  1248. S_B : hregister:=reg32toreg8(getregister32);
  1249. end;
  1250. emit_ref_reg(A_MOV,opsize,
  1251. newreference(p^.left^.location.reference),hregister);
  1252. end;
  1253. end;
  1254. clear_location(p^.location);
  1255. p^.location.loc:=LOC_REGISTER;
  1256. p^.location.register:=hregister;
  1257. end
  1258. else
  1259. { if on the right the register then swap }
  1260. if not(noswap) and (p^.right^.location.loc=LOC_REGISTER) then
  1261. begin
  1262. swap_location(p^.location,p^.right^.location);
  1263. { newly swapped also set swapped flag }
  1264. p^.swaped:=not(p^.swaped);
  1265. end;
  1266. { at this point, p^.location.loc should be LOC_REGISTER }
  1267. { and p^.location.register should be a valid register }
  1268. { containing the left result }
  1269. if p^.right^.location.loc<>LOC_REGISTER then
  1270. begin
  1271. if (p^.treetype=subn) and p^.swaped then
  1272. begin
  1273. if p^.right^.location.loc=LOC_CREGISTER then
  1274. begin
  1275. if extra_not then
  1276. emit_reg(A_NOT,opsize,p^.location.register);
  1277. {$ifndef noAllocEdi}
  1278. getexplicitregister32(R_EDI);
  1279. {$endif noAllocEdi}
  1280. emit_reg_reg(A_MOV,opsize,p^.right^.location.register,R_EDI);
  1281. emit_reg_reg(op,opsize,p^.location.register,R_EDI);
  1282. emit_reg_reg(A_MOV,opsize,R_EDI,p^.location.register);
  1283. {$ifndef noAllocEdi}
  1284. ungetregister32(R_EDI);
  1285. {$endif noAllocEdi}
  1286. end
  1287. else
  1288. begin
  1289. if extra_not then
  1290. emit_reg(A_NOT,opsize,p^.location.register);
  1291. {$ifndef noAllocEdi}
  1292. getexplicitregister32(R_EDI);
  1293. {$endif noAllocEdi}
  1294. emit_ref_reg(A_MOV,opsize,
  1295. newreference(p^.right^.location.reference),R_EDI);
  1296. emit_reg_reg(op,opsize,p^.location.register,R_EDI);
  1297. emit_reg_reg(A_MOV,opsize,R_EDI,p^.location.register);
  1298. {$ifndef noAllocEdi}
  1299. ungetregister32(R_EDI);
  1300. {$endif noAllocEdi}
  1301. ungetiftemp(p^.right^.location.reference);
  1302. del_reference(p^.right^.location.reference);
  1303. end;
  1304. end
  1305. else
  1306. begin
  1307. if (p^.right^.treetype=ordconstn) and
  1308. (op=A_CMP) and
  1309. (p^.right^.value=0) then
  1310. begin
  1311. emit_reg_reg(A_TEST,opsize,p^.location.register,
  1312. p^.location.register);
  1313. end
  1314. else if (p^.right^.treetype=ordconstn) and
  1315. (op=A_ADD) and
  1316. (p^.right^.value=1) and
  1317. not(cs_check_overflow in aktlocalswitches) then
  1318. begin
  1319. emit_reg(A_INC,opsize,
  1320. p^.location.register);
  1321. end
  1322. else if (p^.right^.treetype=ordconstn) and
  1323. (op=A_SUB) and
  1324. (p^.right^.value=1) and
  1325. not(cs_check_overflow in aktlocalswitches) then
  1326. begin
  1327. emit_reg(A_DEC,opsize,
  1328. p^.location.register);
  1329. end
  1330. else if (p^.right^.treetype=ordconstn) and
  1331. (op=A_IMUL) and
  1332. (ispowerof2(p^.right^.value,power)) and
  1333. not(cs_check_overflow in aktlocalswitches) then
  1334. begin
  1335. emit_const_reg(A_SHL,opsize,power,
  1336. p^.location.register);
  1337. end
  1338. else
  1339. begin
  1340. if (p^.right^.location.loc=LOC_CREGISTER) then
  1341. begin
  1342. if extra_not then
  1343. begin
  1344. {$ifndef noAllocEdi}
  1345. getexplicitregister32(R_EDI);
  1346. {$endif noAllocEdi}
  1347. emit_reg_reg(A_MOV,S_L,p^.right^.location.register,R_EDI);
  1348. emit_reg(A_NOT,S_L,R_EDI);
  1349. emit_reg_reg(A_AND,S_L,R_EDI,
  1350. p^.location.register);
  1351. {$ifndef noAllocEdi}
  1352. ungetregister32(R_EDI);
  1353. {$endif noAllocEdi}
  1354. end
  1355. else
  1356. begin
  1357. emit_reg_reg(op,opsize,p^.right^.location.register,
  1358. p^.location.register);
  1359. end;
  1360. end
  1361. else
  1362. begin
  1363. if extra_not then
  1364. begin
  1365. {$ifndef noAllocEdi}
  1366. getexplicitregister32(R_EDI);
  1367. {$endif noAllocEdi}
  1368. emit_ref_reg(A_MOV,S_L,newreference(
  1369. p^.right^.location.reference),R_EDI);
  1370. emit_reg(A_NOT,S_L,R_EDI);
  1371. emit_reg_reg(A_AND,S_L,R_EDI,
  1372. p^.location.register);
  1373. {$ifndef noAllocEdi}
  1374. ungetregister32(R_EDI);
  1375. {$endif noAllocEdi}
  1376. end
  1377. else
  1378. begin
  1379. emit_ref_reg(op,opsize,newreference(
  1380. p^.right^.location.reference),p^.location.register);
  1381. end;
  1382. ungetiftemp(p^.right^.location.reference);
  1383. del_reference(p^.right^.location.reference);
  1384. end;
  1385. end;
  1386. end;
  1387. end
  1388. else
  1389. begin
  1390. { when swapped another result register }
  1391. if (p^.treetype=subn) and p^.swaped then
  1392. begin
  1393. if extra_not then
  1394. emit_reg(A_NOT,S_L,p^.location.register);
  1395. emit_reg_reg(op,opsize,
  1396. p^.location.register,p^.right^.location.register);
  1397. swap_location(p^.location,p^.right^.location);
  1398. { newly swapped also set swapped flag }
  1399. { just to maintain ordering }
  1400. p^.swaped:=not(p^.swaped);
  1401. end
  1402. else
  1403. begin
  1404. if extra_not then
  1405. emit_reg(A_NOT,S_L,p^.right^.location.register);
  1406. emit_reg_reg(op,opsize,
  1407. p^.right^.location.register,
  1408. p^.location.register);
  1409. end;
  1410. case opsize of
  1411. S_L : ungetregister32(p^.right^.location.register);
  1412. S_B : ungetregister32(reg8toreg32(p^.right^.location.register));
  1413. end;
  1414. end;
  1415. if cmpop then
  1416. case opsize of
  1417. S_L : ungetregister32(p^.location.register);
  1418. S_B : ungetregister32(reg8toreg32(p^.location.register));
  1419. end;
  1420. { only in case of overflow operations }
  1421. { produce overflow code }
  1422. { we must put it here directly, because sign of operation }
  1423. { is in unsigned VAR!! }
  1424. if mboverflow then
  1425. begin
  1426. if cs_check_overflow in aktlocalswitches then
  1427. begin
  1428. getlabel(hl4);
  1429. if unsigned then
  1430. emitjmp(C_NB,hl4)
  1431. else
  1432. emitjmp(C_NO,hl4);
  1433. emitcall('FPC_OVERFLOW');
  1434. emitlab(hl4);
  1435. end;
  1436. end;
  1437. end
  1438. else
  1439. { Char type }
  1440. if ((p^.left^.resulttype^.deftype=orddef) and
  1441. (porddef(p^.left^.resulttype)^.typ=uchar)) or
  1442. { enumeration type 16 bit }
  1443. ((p^.left^.resulttype^.deftype=enumdef) and
  1444. (p^.left^.resulttype^.size=1)) then
  1445. begin
  1446. case p^.treetype of
  1447. ltn,lten,gtn,gten,
  1448. equaln,unequaln :
  1449. cmpop:=true;
  1450. else CGMessage(type_e_mismatch);
  1451. end;
  1452. unsigned:=true;
  1453. { left and right no register? }
  1454. { the one must be demanded }
  1455. if (p^.location.loc<>LOC_REGISTER) and
  1456. (p^.right^.location.loc<>LOC_REGISTER) then
  1457. begin
  1458. if p^.location.loc=LOC_CREGISTER then
  1459. begin
  1460. if cmpop then
  1461. { do not disturb register }
  1462. hregister:=p^.location.register
  1463. else
  1464. begin
  1465. hregister:=reg32toreg8(getregister32);
  1466. emit_reg_reg(A_MOV,S_B,p^.location.register,
  1467. hregister);
  1468. end;
  1469. end
  1470. else
  1471. begin
  1472. del_reference(p^.location.reference);
  1473. { first give free then demand new register }
  1474. hregister:=reg32toreg8(getregister32);
  1475. emit_ref_reg(A_MOV,S_B,newreference(p^.location.reference),
  1476. hregister);
  1477. end;
  1478. clear_location(p^.location);
  1479. p^.location.loc:=LOC_REGISTER;
  1480. p^.location.register:=hregister;
  1481. end;
  1482. { now p always a register }
  1483. if (p^.right^.location.loc=LOC_REGISTER) and
  1484. (p^.location.loc<>LOC_REGISTER) then
  1485. begin
  1486. swap_location(p^.location,p^.right^.location);
  1487. { newly swapped also set swapped flag }
  1488. p^.swaped:=not(p^.swaped);
  1489. end;
  1490. if p^.right^.location.loc<>LOC_REGISTER then
  1491. begin
  1492. if p^.right^.location.loc=LOC_CREGISTER then
  1493. begin
  1494. emit_reg_reg(A_CMP,S_B,
  1495. p^.right^.location.register,p^.location.register);
  1496. end
  1497. else
  1498. begin
  1499. emit_ref_reg(A_CMP,S_B,newreference(
  1500. p^.right^.location.reference),p^.location.register);
  1501. del_reference(p^.right^.location.reference);
  1502. end;
  1503. end
  1504. else
  1505. begin
  1506. emit_reg_reg(A_CMP,S_B,p^.right^.location.register,
  1507. p^.location.register);
  1508. ungetregister32(reg8toreg32(p^.right^.location.register));
  1509. end;
  1510. ungetregister32(reg8toreg32(p^.location.register));
  1511. end
  1512. else
  1513. { 16 bit enumeration type }
  1514. if ((p^.left^.resulttype^.deftype=enumdef) and
  1515. (p^.left^.resulttype^.size=2)) then
  1516. begin
  1517. case p^.treetype of
  1518. ltn,lten,gtn,gten,
  1519. equaln,unequaln :
  1520. cmpop:=true;
  1521. else CGMessage(type_e_mismatch);
  1522. end;
  1523. unsigned:=true;
  1524. { left and right no register? }
  1525. { the one must be demanded }
  1526. if (p^.location.loc<>LOC_REGISTER) and
  1527. (p^.right^.location.loc<>LOC_REGISTER) then
  1528. begin
  1529. if p^.location.loc=LOC_CREGISTER then
  1530. begin
  1531. if cmpop then
  1532. { do not disturb register }
  1533. hregister:=p^.location.register
  1534. else
  1535. begin
  1536. hregister:=reg32toreg16(getregister32);
  1537. emit_reg_reg(A_MOV,S_W,p^.location.register,
  1538. hregister);
  1539. end;
  1540. end
  1541. else
  1542. begin
  1543. del_reference(p^.location.reference);
  1544. { first give free then demand new register }
  1545. hregister:=reg32toreg16(getregister32);
  1546. emit_ref_reg(A_MOV,S_W,newreference(p^.location.reference),
  1547. hregister);
  1548. end;
  1549. clear_location(p^.location);
  1550. p^.location.loc:=LOC_REGISTER;
  1551. p^.location.register:=hregister;
  1552. end;
  1553. { now p always a register }
  1554. if (p^.right^.location.loc=LOC_REGISTER) and
  1555. (p^.location.loc<>LOC_REGISTER) then
  1556. begin
  1557. swap_location(p^.location,p^.right^.location);
  1558. { newly swapped also set swapped flag }
  1559. p^.swaped:=not(p^.swaped);
  1560. end;
  1561. if p^.right^.location.loc<>LOC_REGISTER then
  1562. begin
  1563. if p^.right^.location.loc=LOC_CREGISTER then
  1564. begin
  1565. emit_reg_reg(A_CMP,S_W,
  1566. p^.right^.location.register,p^.location.register);
  1567. end
  1568. else
  1569. begin
  1570. emit_ref_reg(A_CMP,S_W,newreference(
  1571. p^.right^.location.reference),p^.location.register);
  1572. del_reference(p^.right^.location.reference);
  1573. end;
  1574. end
  1575. else
  1576. begin
  1577. emit_reg_reg(A_CMP,S_W,p^.right^.location.register,
  1578. p^.location.register);
  1579. ungetregister32(reg16toreg32(p^.right^.location.register));
  1580. end;
  1581. ungetregister32(reg16toreg32(p^.location.register));
  1582. end
  1583. else
  1584. { 64 bit types }
  1585. if is_64bitint(p^.left^.resulttype) then
  1586. begin
  1587. mboverflow:=false;
  1588. cmpop:=false;
  1589. unsigned:=((p^.left^.resulttype^.deftype=orddef) and
  1590. (porddef(p^.left^.resulttype)^.typ=u64bit)) or
  1591. ((p^.right^.resulttype^.deftype=orddef) and
  1592. (porddef(p^.right^.resulttype)^.typ=u64bit));
  1593. case p^.treetype of
  1594. addn : begin
  1595. begin
  1596. op:=A_ADD;
  1597. op2:=A_ADC;
  1598. mboverflow:=true;
  1599. end;
  1600. end;
  1601. subn : begin
  1602. op:=A_SUB;
  1603. op2:=A_SBB;
  1604. mboverflow:=true;
  1605. end;
  1606. ltn,lten,
  1607. gtn,gten,
  1608. equaln,unequaln:
  1609. begin
  1610. op:=A_CMP;
  1611. op2:=A_CMP;
  1612. cmpop:=true;
  1613. end;
  1614. xorn:
  1615. begin
  1616. op:=A_XOR;
  1617. op2:=A_XOR;
  1618. end;
  1619. orn:
  1620. begin
  1621. op:=A_OR;
  1622. op2:=A_OR;
  1623. end;
  1624. andn:
  1625. begin
  1626. op:=A_AND;
  1627. op2:=A_AND;
  1628. end;
  1629. muln:
  1630. ;
  1631. else
  1632. CGMessage(type_e_mismatch);
  1633. end;
  1634. if p^.treetype=muln then
  1635. begin
  1636. { save p^.lcoation, because we change it now }
  1637. set_location(hloc,p^.location);
  1638. release_qword_loc(p^.location);
  1639. release_qword_loc(p^.right^.location);
  1640. p^.location.registerlow:=getexplicitregister32(R_EAX);
  1641. p^.location.registerhigh:=getexplicitregister32(R_EDX);
  1642. pushusedregisters(pushedreg,$ff
  1643. and not($80 shr byte(p^.location.registerlow))
  1644. and not($80 shr byte(p^.location.registerhigh)));
  1645. if cs_check_overflow in aktlocalswitches then
  1646. push_int(1)
  1647. else
  1648. push_int(0);
  1649. { the left operand is in hloc, because the
  1650. location of left is p^.location but p^.location
  1651. is already destroyed
  1652. }
  1653. emit_pushq_loc(hloc);
  1654. clear_location(hloc);
  1655. emit_pushq_loc(p^.right^.location);
  1656. if porddef(p^.resulttype)^.typ=u64bit then
  1657. emitcall('FPC_MUL_QWORD')
  1658. else
  1659. emitcall('FPC_MUL_INT64');
  1660. emit_reg_reg(A_MOV,S_L,R_EAX,p^.location.registerlow);
  1661. emit_reg_reg(A_MOV,S_L,R_EDX,p^.location.registerhigh);
  1662. popusedregisters(pushedreg);
  1663. p^.location.loc:=LOC_REGISTER;
  1664. end
  1665. else
  1666. begin
  1667. { left and right no register? }
  1668. { then one must be demanded }
  1669. if (p^.left^.location.loc<>LOC_REGISTER) and
  1670. (p^.right^.location.loc<>LOC_REGISTER) then
  1671. begin
  1672. { register variable ? }
  1673. if (p^.left^.location.loc=LOC_CREGISTER) then
  1674. begin
  1675. { it is OK if this is the destination }
  1676. if is_in_dest then
  1677. begin
  1678. hregister:=p^.location.registerlow;
  1679. hregister2:=p^.location.registerhigh;
  1680. emit_reg_reg(A_MOV,S_L,p^.left^.location.registerlow,
  1681. hregister);
  1682. emit_reg_reg(A_MOV,S_L,p^.left^.location.registerlow,
  1683. hregister2);
  1684. end
  1685. else
  1686. if cmpop then
  1687. begin
  1688. { do not disturb the register }
  1689. hregister:=p^.location.registerlow;
  1690. hregister2:=p^.location.registerhigh;
  1691. end
  1692. else
  1693. begin
  1694. hregister:=getregister32;
  1695. hregister2:=getregister32;
  1696. emit_reg_reg(A_MOV,S_L,p^.left^.location.registerlow,
  1697. hregister);
  1698. emit_reg_reg(A_MOV,S_L,p^.left^.location.registerhigh,
  1699. hregister2);
  1700. end
  1701. end
  1702. else
  1703. begin
  1704. ungetiftemp(p^.left^.location.reference);
  1705. del_reference(p^.left^.location.reference);
  1706. if is_in_dest then
  1707. begin
  1708. hregister:=p^.location.registerlow;
  1709. hregister2:=p^.location.registerhigh;
  1710. emit_mov_ref_reg64(p^.left^.location.reference,hregister,hregister2);
  1711. end
  1712. else
  1713. begin
  1714. hregister:=getregister32;
  1715. hregister2:=getregister32;
  1716. emit_mov_ref_reg64(p^.left^.location.reference,hregister,hregister2);
  1717. end;
  1718. end;
  1719. clear_location(p^.location);
  1720. p^.location.loc:=LOC_REGISTER;
  1721. p^.location.registerlow:=hregister;
  1722. p^.location.registerhigh:=hregister2;
  1723. end
  1724. else
  1725. { if on the right the register then swap }
  1726. if not(noswap) and (p^.right^.location.loc=LOC_REGISTER) then
  1727. begin
  1728. swap_location(p^.location,p^.right^.location);
  1729. { newly swapped also set swapped flag }
  1730. p^.swaped:=not(p^.swaped);
  1731. end;
  1732. { at this point, p^.location.loc should be LOC_REGISTER }
  1733. { and p^.location.register should be a valid register }
  1734. { containing the left result }
  1735. if p^.right^.location.loc<>LOC_REGISTER then
  1736. begin
  1737. if (p^.treetype=subn) and p^.swaped then
  1738. begin
  1739. if p^.right^.location.loc=LOC_CREGISTER then
  1740. begin
  1741. {$ifndef noAllocEdi}
  1742. getexplicitregister32(R_EDI);
  1743. {$endif noAllocEdi}
  1744. emit_reg_reg(A_MOV,opsize,p^.right^.location.register,R_EDI);
  1745. emit_reg_reg(op,opsize,p^.location.register,R_EDI);
  1746. emit_reg_reg(A_MOV,opsize,R_EDI,p^.location.register);
  1747. {$ifndef noAllocEdi}
  1748. ungetregister32(R_EDI);
  1749. getexplicitregister32(R_EDI);
  1750. {$endif noAllocEdi}
  1751. emit_reg_reg(A_MOV,opsize,p^.right^.location.registerhigh,R_EDI);
  1752. { the carry flag is still ok }
  1753. emit_reg_reg(op2,opsize,p^.location.registerhigh,R_EDI);
  1754. emit_reg_reg(A_MOV,opsize,R_EDI,p^.location.registerhigh);
  1755. {$ifndef noAllocEdi}
  1756. ungetregister32(R_EDI);
  1757. {$endif noAllocEdi}
  1758. end
  1759. else
  1760. begin
  1761. {$ifndef noAllocEdi}
  1762. getexplicitregister32(R_EDI);
  1763. {$endif noAllocEdi}
  1764. emit_ref_reg(A_MOV,opsize,
  1765. newreference(p^.right^.location.reference),R_EDI);
  1766. emit_reg_reg(op,opsize,p^.location.registerlow,R_EDI);
  1767. emit_reg_reg(A_MOV,opsize,R_EDI,p^.location.registerlow);
  1768. {$ifndef noAllocEdi}
  1769. ungetregister32(R_EDI);
  1770. getexplicitregister32(R_EDI);
  1771. {$endif noAllocEdi}
  1772. hr:=newreference(p^.right^.location.reference);
  1773. inc(hr^.offset,4);
  1774. emit_ref_reg(A_MOV,opsize,
  1775. hr,R_EDI);
  1776. { here the carry flag is still preserved }
  1777. emit_reg_reg(op2,opsize,p^.location.registerhigh,R_EDI);
  1778. emit_reg_reg(A_MOV,opsize,R_EDI,
  1779. p^.location.registerhigh);
  1780. {$ifndef noAllocEdi}
  1781. ungetregister32(R_EDI);
  1782. {$endif noAllocEdi}
  1783. ungetiftemp(p^.right^.location.reference);
  1784. del_reference(p^.right^.location.reference);
  1785. end;
  1786. end
  1787. else if cmpop then
  1788. begin
  1789. if (p^.right^.location.loc=LOC_CREGISTER) then
  1790. begin
  1791. emit_reg_reg(A_CMP,S_L,p^.right^.location.registerhigh,
  1792. p^.location.registerhigh);
  1793. firstjmp64bitcmp;
  1794. emit_reg_reg(A_CMP,S_L,p^.right^.location.registerlow,
  1795. p^.location.registerlow);
  1796. secondjmp64bitcmp;
  1797. end
  1798. else
  1799. begin
  1800. hr:=newreference(p^.right^.location.reference);
  1801. inc(hr^.offset,4);
  1802. emit_ref_reg(A_CMP,S_L,
  1803. hr,p^.location.registerhigh);
  1804. firstjmp64bitcmp;
  1805. emit_ref_reg(A_CMP,S_L,newreference(
  1806. p^.right^.location.reference),p^.location.registerlow);
  1807. secondjmp64bitcmp;
  1808. emitjmp(C_None,falselabel);
  1809. ungetiftemp(p^.right^.location.reference);
  1810. del_reference(p^.right^.location.reference);
  1811. end;
  1812. end
  1813. else
  1814. begin
  1815. {
  1816. if (p^.right^.treetype=ordconstn) and
  1817. (op=A_CMP) and
  1818. (p^.right^.value=0) then
  1819. begin
  1820. emit_reg_reg(A_TEST,opsize,p^.location.register,
  1821. p^.location.register);
  1822. end
  1823. else if (p^.right^.treetype=ordconstn) and
  1824. (op=A_IMUL) and
  1825. (ispowerof2(p^.right^.value,power)) then
  1826. begin
  1827. emit_const_reg(A_SHL,opsize,power,
  1828. p^.location.register);
  1829. end
  1830. else
  1831. }
  1832. begin
  1833. if (p^.right^.location.loc=LOC_CREGISTER) then
  1834. begin
  1835. emit_reg_reg(op,S_L,p^.right^.location.registerlow,
  1836. p^.location.registerlow);
  1837. emit_reg_reg(op2,S_L,p^.right^.location.registerhigh,
  1838. p^.location.registerhigh);
  1839. end
  1840. else
  1841. begin
  1842. emit_ref_reg(op,S_L,newreference(
  1843. p^.right^.location.reference),p^.location.registerlow);
  1844. hr:=newreference(p^.right^.location.reference);
  1845. inc(hr^.offset,4);
  1846. emit_ref_reg(op2,S_L,
  1847. hr,p^.location.registerhigh);
  1848. ungetiftemp(p^.right^.location.reference);
  1849. del_reference(p^.right^.location.reference);
  1850. end;
  1851. end;
  1852. end;
  1853. end
  1854. else
  1855. begin
  1856. { when swapped another result register }
  1857. if (p^.treetype=subn) and p^.swaped then
  1858. begin
  1859. emit_reg_reg(op,S_L,
  1860. p^.location.registerlow,
  1861. p^.right^.location.registerlow);
  1862. emit_reg_reg(op2,S_L,
  1863. p^.location.registerhigh,
  1864. p^.right^.location.registerhigh);
  1865. swap_location(p^.location,p^.right^.location);
  1866. { newly swapped also set swapped flag }
  1867. { just to maintain ordering }
  1868. p^.swaped:=not(p^.swaped);
  1869. end
  1870. else if cmpop then
  1871. begin
  1872. emit_reg_reg(A_CMP,S_L,
  1873. p^.right^.location.registerhigh,
  1874. p^.location.registerhigh);
  1875. firstjmp64bitcmp;
  1876. emit_reg_reg(A_CMP,S_L,
  1877. p^.right^.location.registerlow,
  1878. p^.location.registerlow);
  1879. secondjmp64bitcmp;
  1880. end
  1881. else
  1882. begin
  1883. emit_reg_reg(op,S_L,
  1884. p^.right^.location.registerlow,
  1885. p^.location.registerlow);
  1886. emit_reg_reg(op2,S_L,
  1887. p^.right^.location.registerhigh,
  1888. p^.location.registerhigh);
  1889. end;
  1890. ungetregister32(p^.right^.location.registerlow);
  1891. ungetregister32(p^.right^.location.registerhigh);
  1892. end;
  1893. if cmpop then
  1894. begin
  1895. ungetregister32(p^.location.registerlow);
  1896. ungetregister32(p^.location.registerhigh);
  1897. end;
  1898. { only in case of overflow operations }
  1899. { produce overflow code }
  1900. { we must put it here directly, because sign of operation }
  1901. { is in unsigned VAR!! }
  1902. if mboverflow then
  1903. begin
  1904. if cs_check_overflow in aktlocalswitches then
  1905. begin
  1906. getlabel(hl4);
  1907. if unsigned then
  1908. emitjmp(C_NB,hl4)
  1909. else
  1910. emitjmp(C_NO,hl4);
  1911. emitcall('FPC_OVERFLOW');
  1912. emitlab(hl4);
  1913. end;
  1914. end;
  1915. { we have LOC_JUMP as result }
  1916. if cmpop then
  1917. begin
  1918. clear_location(p^.location);
  1919. p^.location.loc:=LOC_JUMP;
  1920. cmpop:=false;
  1921. end;
  1922. end;
  1923. end
  1924. else
  1925. { Floating point }
  1926. if (p^.left^.resulttype^.deftype=floatdef) and
  1927. (pfloatdef(p^.left^.resulttype)^.typ<>f32bit) then
  1928. begin
  1929. { real constants to the right, but only if it
  1930. isn't on the FPU stack, i.e. 1.0 or 0.0! }
  1931. if (p^.left^.treetype=realconstn) and
  1932. (p^.left^.location.loc<>LOC_FPU) then
  1933. swaptree(p);
  1934. cmpop:=false;
  1935. case p^.treetype of
  1936. addn : op:=A_FADDP;
  1937. muln : op:=A_FMULP;
  1938. subn : op:=A_FSUBP;
  1939. slashn : op:=A_FDIVP;
  1940. ltn,lten,gtn,gten,
  1941. equaln,unequaln : begin
  1942. op:=A_FCOMPP;
  1943. cmpop:=true;
  1944. end;
  1945. else CGMessage(type_e_mismatch);
  1946. end;
  1947. if (p^.right^.location.loc<>LOC_FPU) then
  1948. begin
  1949. if p^.right^.location.loc=LOC_CFPUREGISTER then
  1950. begin
  1951. emit_reg( A_FLD,S_NO,
  1952. correct_fpuregister(p^.right^.location.register,fpuvaroffset));
  1953. inc(fpuvaroffset);
  1954. end
  1955. else
  1956. floatload(pfloatdef(p^.right^.resulttype)^.typ,p^.right^.location.reference);
  1957. if (p^.left^.location.loc<>LOC_FPU) then
  1958. begin
  1959. if p^.left^.location.loc=LOC_CFPUREGISTER then
  1960. begin
  1961. emit_reg( A_FLD,S_NO,
  1962. correct_fpuregister(p^.left^.location.register,fpuvaroffset));
  1963. inc(fpuvaroffset);
  1964. end
  1965. else
  1966. floatload(pfloatdef(p^.left^.resulttype)^.typ,p^.left^.location.reference)
  1967. end
  1968. { left was on the stack => swap }
  1969. else
  1970. p^.swaped:=not(p^.swaped);
  1971. { releases the right reference }
  1972. del_reference(p^.right^.location.reference);
  1973. end
  1974. { the nominator in st0 }
  1975. else if (p^.left^.location.loc<>LOC_FPU) then
  1976. begin
  1977. if p^.left^.location.loc=LOC_CFPUREGISTER then
  1978. begin
  1979. emit_reg( A_FLD,S_NO,
  1980. correct_fpuregister(p^.left^.location.register,fpuvaroffset));
  1981. inc(fpuvaroffset);
  1982. end
  1983. else
  1984. floatload(pfloatdef(p^.left^.resulttype)^.typ,p^.left^.location.reference)
  1985. end
  1986. { fpu operands are always in the wrong order on the stack }
  1987. else
  1988. p^.swaped:=not(p^.swaped);
  1989. { releases the left reference }
  1990. if (p^.left^.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  1991. del_reference(p^.left^.location.reference);
  1992. { if we swaped the tree nodes, then use the reverse operator }
  1993. if p^.swaped then
  1994. begin
  1995. if (p^.treetype=slashn) then
  1996. op:=A_FDIVRP
  1997. else if (p^.treetype=subn) then
  1998. op:=A_FSUBRP;
  1999. end;
  2000. { to avoid the pentium bug
  2001. if (op=FDIVP) and (opt_processors=pentium) then
  2002. emitcall('EMUL_FDIVP')
  2003. else
  2004. }
  2005. { the Intel assemblers want operands }
  2006. if op<>A_FCOMPP then
  2007. begin
  2008. emit_reg_reg(op,S_NO,R_ST,R_ST1);
  2009. dec(fpuvaroffset);
  2010. end
  2011. else
  2012. begin
  2013. emit_none(op,S_NO);
  2014. dec(fpuvaroffset,2);
  2015. end;
  2016. { on comparison load flags }
  2017. if cmpop then
  2018. begin
  2019. if not(R_EAX in unused) then
  2020. begin
  2021. {$ifndef noAllocEdi}
  2022. getexplicitregister32(R_EDI);
  2023. {$endif noAllocEdi}
  2024. emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
  2025. end;
  2026. emit_reg(A_FNSTSW,S_NO,R_AX);
  2027. emit_none(A_SAHF,S_NO);
  2028. if not(R_EAX in unused) then
  2029. begin
  2030. emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
  2031. {$ifndef noAllocEdi}
  2032. ungetregister32(R_EDI);
  2033. {$endif noAllocEdi}
  2034. end;
  2035. if p^.swaped then
  2036. begin
  2037. case p^.treetype of
  2038. equaln : flags:=F_E;
  2039. unequaln : flags:=F_NE;
  2040. ltn : flags:=F_A;
  2041. lten : flags:=F_AE;
  2042. gtn : flags:=F_B;
  2043. gten : flags:=F_BE;
  2044. end;
  2045. end
  2046. else
  2047. begin
  2048. case p^.treetype of
  2049. equaln : flags:=F_E;
  2050. unequaln : flags:=F_NE;
  2051. ltn : flags:=F_B;
  2052. lten : flags:=F_BE;
  2053. gtn : flags:=F_A;
  2054. gten : flags:=F_AE;
  2055. end;
  2056. end;
  2057. clear_location(p^.location);
  2058. p^.location.loc:=LOC_FLAGS;
  2059. p^.location.resflags:=flags;
  2060. cmpop:=false;
  2061. end
  2062. else
  2063. begin
  2064. clear_location(p^.location);
  2065. p^.location.loc:=LOC_FPU;
  2066. end;
  2067. end
  2068. {$ifdef SUPPORT_MMX}
  2069. else
  2070. { MMX Arrays }
  2071. if is_mmx_able_array(p^.left^.resulttype) then
  2072. begin
  2073. cmpop:=false;
  2074. mmxbase:=mmx_type(p^.left^.resulttype);
  2075. case p^.treetype of
  2076. addn : begin
  2077. if (cs_mmx_saturation in aktlocalswitches) then
  2078. begin
  2079. case mmxbase of
  2080. mmxs8bit:
  2081. op:=A_PADDSB;
  2082. mmxu8bit:
  2083. op:=A_PADDUSB;
  2084. mmxs16bit,mmxfixed16:
  2085. op:=A_PADDSB;
  2086. mmxu16bit:
  2087. op:=A_PADDUSW;
  2088. end;
  2089. end
  2090. else
  2091. begin
  2092. case mmxbase of
  2093. mmxs8bit,mmxu8bit:
  2094. op:=A_PADDB;
  2095. mmxs16bit,mmxu16bit,mmxfixed16:
  2096. op:=A_PADDW;
  2097. mmxs32bit,mmxu32bit:
  2098. op:=A_PADDD;
  2099. end;
  2100. end;
  2101. end;
  2102. muln : begin
  2103. case mmxbase of
  2104. mmxs16bit,mmxu16bit:
  2105. op:=A_PMULLW;
  2106. mmxfixed16:
  2107. op:=A_PMULHW;
  2108. end;
  2109. end;
  2110. subn : begin
  2111. if (cs_mmx_saturation in aktlocalswitches) then
  2112. begin
  2113. case mmxbase of
  2114. mmxs8bit:
  2115. op:=A_PSUBSB;
  2116. mmxu8bit:
  2117. op:=A_PSUBUSB;
  2118. mmxs16bit,mmxfixed16:
  2119. op:=A_PSUBSB;
  2120. mmxu16bit:
  2121. op:=A_PSUBUSW;
  2122. end;
  2123. end
  2124. else
  2125. begin
  2126. case mmxbase of
  2127. mmxs8bit,mmxu8bit:
  2128. op:=A_PSUBB;
  2129. mmxs16bit,mmxu16bit,mmxfixed16:
  2130. op:=A_PSUBW;
  2131. mmxs32bit,mmxu32bit:
  2132. op:=A_PSUBD;
  2133. end;
  2134. end;
  2135. end;
  2136. {
  2137. ltn,lten,gtn,gten,
  2138. equaln,unequaln :
  2139. begin
  2140. op:=A_CMP;
  2141. cmpop:=true;
  2142. end;
  2143. }
  2144. xorn:
  2145. op:=A_PXOR;
  2146. orn:
  2147. op:=A_POR;
  2148. andn:
  2149. op:=A_PAND;
  2150. else CGMessage(type_e_mismatch);
  2151. end;
  2152. { left and right no register? }
  2153. { then one must be demanded }
  2154. if (p^.left^.location.loc<>LOC_MMXREGISTER) and
  2155. (p^.right^.location.loc<>LOC_MMXREGISTER) then
  2156. begin
  2157. { register variable ? }
  2158. if (p^.left^.location.loc=LOC_CMMXREGISTER) then
  2159. begin
  2160. { it is OK if this is the destination }
  2161. if is_in_dest then
  2162. begin
  2163. hregister:=p^.location.register;
  2164. emit_reg_reg(A_MOVQ,S_NO,p^.left^.location.register,
  2165. hregister);
  2166. end
  2167. else
  2168. begin
  2169. hregister:=getregistermmx;
  2170. emit_reg_reg(A_MOVQ,S_NO,p^.left^.location.register,
  2171. hregister);
  2172. end
  2173. end
  2174. else
  2175. begin
  2176. del_reference(p^.left^.location.reference);
  2177. if is_in_dest then
  2178. begin
  2179. hregister:=p^.location.register;
  2180. emit_ref_reg(A_MOVQ,S_NO,
  2181. newreference(p^.left^.location.reference),hregister);
  2182. end
  2183. else
  2184. begin
  2185. hregister:=getregistermmx;
  2186. emit_ref_reg(A_MOVQ,S_NO,
  2187. newreference(p^.left^.location.reference),hregister);
  2188. end;
  2189. end;
  2190. clear_location(p^.location);
  2191. p^.location.loc:=LOC_MMXREGISTER;
  2192. p^.location.register:=hregister;
  2193. end
  2194. else
  2195. { if on the right the register then swap }
  2196. if (p^.right^.location.loc=LOC_MMXREGISTER) then
  2197. begin
  2198. swap_location(p^.location,p^.right^.location);
  2199. { newly swapped also set swapped flag }
  2200. p^.swaped:=not(p^.swaped);
  2201. end;
  2202. { at this point, p^.location.loc should be LOC_MMXREGISTER }
  2203. { and p^.location.register should be a valid register }
  2204. { containing the left result }
  2205. if p^.right^.location.loc<>LOC_MMXREGISTER then
  2206. begin
  2207. if (p^.treetype=subn) and p^.swaped then
  2208. begin
  2209. if p^.right^.location.loc=LOC_CMMXREGISTER then
  2210. begin
  2211. emit_reg_reg(A_MOVQ,S_NO,p^.right^.location.register,R_MM7);
  2212. emit_reg_reg(op,S_NO,p^.location.register,R_MM0);
  2213. emit_reg_reg(A_MOVQ,S_NO,R_MM7,p^.location.register);
  2214. end
  2215. else
  2216. begin
  2217. emit_ref_reg(A_MOVQ,S_NO,
  2218. newreference(p^.right^.location.reference),R_MM7);
  2219. emit_reg_reg(op,S_NO,p^.location.register,
  2220. R_MM7);
  2221. emit_reg_reg(A_MOVQ,S_NO,
  2222. R_MM7,p^.location.register);
  2223. del_reference(p^.right^.location.reference);
  2224. end;
  2225. end
  2226. else
  2227. begin
  2228. if (p^.right^.location.loc=LOC_CREGISTER) then
  2229. begin
  2230. emit_reg_reg(op,S_NO,p^.right^.location.register,
  2231. p^.location.register);
  2232. end
  2233. else
  2234. begin
  2235. emit_ref_reg(op,S_NO,newreference(
  2236. p^.right^.location.reference),p^.location.register);
  2237. del_reference(p^.right^.location.reference);
  2238. end;
  2239. end;
  2240. end
  2241. else
  2242. begin
  2243. { when swapped another result register }
  2244. if (p^.treetype=subn) and p^.swaped then
  2245. begin
  2246. emit_reg_reg(op,S_NO,
  2247. p^.location.register,p^.right^.location.register);
  2248. swap_location(p^.location,p^.right^.location);
  2249. { newly swapped also set swapped flag }
  2250. { just to maintain ordering }
  2251. p^.swaped:=not(p^.swaped);
  2252. end
  2253. else
  2254. begin
  2255. emit_reg_reg(op,S_NO,
  2256. p^.right^.location.register,
  2257. p^.location.register);
  2258. end;
  2259. ungetregistermmx(p^.right^.location.register);
  2260. end;
  2261. end
  2262. {$endif SUPPORT_MMX}
  2263. else CGMessage(type_e_mismatch);
  2264. end;
  2265. SetResultLocation(cmpop,unsigned,p);
  2266. end;
  2267. end.
  2268. {
  2269. $Log$
  2270. Revision 1.101 2000-04-25 14:43:36 jonas
  2271. - disabled "string_var := string_var + ... " and "string_var + char_var"
  2272. optimizations (were only active with -dnewoptimizations) because of
  2273. several internal issues
  2274. Revision 1.100 2000/04/23 09:28:19 jonas
  2275. * use FPC_SHPRTSTR_CONCAT_LEN for -dnewoptimizations (temp)
  2276. * more precise reg deallocation when calling the above)
  2277. Revision 1.99 2000/04/21 12:35:05 jonas
  2278. + special code for string + char, between -dnewoptimizations
  2279. Revision 1.98 2000/04/10 12:23:19 jonas
  2280. * modified copyshortstring so it takes an extra paramter which allows it
  2281. to delete the sref itself (so the reg deallocations are put in the
  2282. right place for the optimizer)
  2283. Revision 1.97 2000/02/29 23:57:36 pierre
  2284. Use $GOTO ON
  2285. Revision 1.96 2000/02/18 21:25:48 florian
  2286. * fixed a bug in int64/qword handling was a quite ugly one
  2287. Revision 1.95 2000/02/18 16:13:28 florian
  2288. * optimized ansistring compare with ''
  2289. * fixed 852
  2290. Revision 1.94 2000/02/14 22:34:28 florian
  2291. * fixed another internalerror
  2292. Revision 1.93 2000/02/09 13:22:45 peter
  2293. * log truncated
  2294. Revision 1.92 2000/01/23 13:57:52 jonas
  2295. * fixed bug introduced by my regalloc fixed :(
  2296. Revision 1.91 2000/01/23 11:11:36 michael
  2297. + Fixes from Jonas.
  2298. Revision 1.90 2000/01/22 16:02:38 jonas
  2299. * fixed more regalloc bugs (for set adding and unsigned
  2300. multiplication)
  2301. Revision 1.89 2000/01/13 16:52:47 jonas
  2302. * moved deallocation of registers used in reference that points to string after
  2303. copyshortstring (this routine doesn't require extra regs)
  2304. Revision 1.88 2000/01/09 19:44:53 florian
  2305. * bug in secondadd(subn) with swaped mmx operands fixed
  2306. Revision 1.87 2000/01/09 16:35:39 jonas
  2307. + comment about badly placed release_loc calls for a_mul which
  2308. causes wrong regdeallocations. Don't know how to fix :(
  2309. Revision 1.86 2000/01/09 12:34:59 jonas
  2310. * changed edi allocation to use getexplicitregister32/ungetregister
  2311. (adapted tgeni386 a bit for this) and enabled it by default
  2312. * fixed very big and stupid bug of mine in cg386mat that broke the
  2313. include() code (and make cycle :( ) if you compiled without
  2314. -dnewoptimizations
  2315. Revision 1.85 2000/01/09 01:44:18 jonas
  2316. + (de)allocation info for EDI to fix reported bug on mailinglist.
  2317. Also some (de)allocation info for ESI added. Between -dallocEDI
  2318. because at this time of the night bugs could easily slip in ;)
  2319. Revision 1.84 2000/01/07 01:14:20 peter
  2320. * updated copyright to 2000
  2321. Revision 1.83 1999/12/11 18:53:31 jonas
  2322. * fixed type conversions of results of operations with cardinals
  2323. (between -dcardinalmulfix)
  2324. Revision 1.82 1999/11/06 14:34:17 peter
  2325. * truncated log to 20 revs
  2326. Revision 1.81 1999/09/28 19:43:45 florian
  2327. * the maybe_push fix of Pierre wasn't 100%, the tree parameter
  2328. must contain a valid location (which is saved if necessary)
  2329. Revision 1.80 1999/09/26 13:26:01 florian
  2330. * exception patch of Romio nevertheless the excpetion handling
  2331. needs some corections regarding register saving
  2332. * gettempansistring is again a procedure
  2333. Revision 1.79 1999/09/21 20:53:21 florian
  2334. * fixed 1/s problem from mailing list
  2335. Revision 1.78 1999/09/07 07:52:19 peter
  2336. * > < >= <= support for boolean
  2337. * boolean constants are now calculated like integer constants
  2338. Revision 1.77 1999/08/30 12:00:45 pierre
  2339. * problem with maybe_push/restore solved hopefully
  2340. Revision 1.76 1999/08/23 23:31:00 pierre
  2341. * double del_location removed in add_set
  2342. Revision 1.75 1999/08/23 10:35:13 jonas
  2343. * fixed <= and >= for sets
  2344. Revision 1.74 1999/08/19 13:08:43 pierre
  2345. * emit_??? used
  2346. Revision 1.73 1999/08/07 11:29:26 peter
  2347. * better fix for muln register allocation
  2348. }