cg386add.pas 68 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 by Florian Klaempfl
  4. Generate i386 assembler for in add node
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit cg386add;
  19. interface
  20. {$define usecreateset}
  21. uses
  22. tree;
  23. procedure secondadd(var p : ptree);
  24. implementation
  25. uses
  26. cobjects,verbose,globals,systems,
  27. symtable,aasm,types,
  28. hcodegen,temp_gen,pass_2,
  29. i386,cgai386,tgeni386;
  30. {*****************************************************************************
  31. Helpers
  32. *****************************************************************************}
  33. procedure SetResultLocation(cmpop,unsigned:boolean;var p :ptree);
  34. var
  35. flags : tresflags;
  36. begin
  37. { remove temporary location if not a set or string }
  38. { that's a bad hack (FK) who did this ? }
  39. if (p^.left^.resulttype^.deftype<>stringdef) and
  40. ((p^.left^.resulttype^.deftype<>setdef) or (psetdef(p^.left^.resulttype)^.settype=smallset)) and
  41. (p^.left^.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  42. ungetiftemp(p^.left^.location.reference);
  43. if (p^.right^.resulttype^.deftype<>stringdef) and
  44. ((p^.right^.resulttype^.deftype<>setdef) or (psetdef(p^.right^.resulttype)^.settype=smallset)) and
  45. (p^.right^.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  46. ungetiftemp(p^.right^.location.reference);
  47. { in case of comparison operation the put result in the flags }
  48. if cmpop then
  49. begin
  50. if not(unsigned) then
  51. begin
  52. if p^.swaped then
  53. case p^.treetype of
  54. equaln : flags:=F_E;
  55. unequaln : flags:=F_NE;
  56. ltn : flags:=F_G;
  57. lten : flags:=F_GE;
  58. gtn : flags:=F_L;
  59. gten : flags:=F_LE;
  60. end
  61. else
  62. case p^.treetype of
  63. equaln : flags:=F_E;
  64. unequaln : flags:=F_NE;
  65. ltn : flags:=F_L;
  66. lten : flags:=F_LE;
  67. gtn : flags:=F_G;
  68. gten : flags:=F_GE;
  69. end;
  70. end
  71. else
  72. begin
  73. if p^.swaped then
  74. case p^.treetype of
  75. equaln : flags:=F_E;
  76. unequaln : flags:=F_NE;
  77. ltn : flags:=F_A;
  78. lten : flags:=F_AE;
  79. gtn : flags:=F_B;
  80. gten : flags:=F_BE;
  81. end
  82. else
  83. case p^.treetype of
  84. equaln : flags:=F_E;
  85. unequaln : flags:=F_NE;
  86. ltn : flags:=F_B;
  87. lten : flags:=F_BE;
  88. gtn : flags:=F_A;
  89. gten : flags:=F_AE;
  90. end;
  91. end;
  92. clear_location(p^.location);
  93. p^.location.loc:=LOC_FLAGS;
  94. p^.location.resflags:=flags;
  95. end;
  96. end;
  97. {*****************************************************************************
  98. Addstring
  99. *****************************************************************************}
  100. procedure addstring(var p : ptree);
  101. var
  102. pushedregs : tpushed;
  103. href : treference;
  104. pushed,
  105. cmpop : boolean;
  106. savedunused : tregisterset;
  107. hr : treference;
  108. begin
  109. { string operations are not commutative }
  110. if p^.swaped then
  111. swaptree(p);
  112. case pstringdef(p^.left^.resulttype)^.string_typ of
  113. st_ansistring:
  114. begin
  115. case p^.treetype of
  116. addn:
  117. begin
  118. cmpop:=false;
  119. secondpass(p^.left);
  120. pushed:=maybe_push(p^.right^.registers32,p);
  121. secondpass(p^.right);
  122. if pushed then restore(p);
  123. { release used registers }
  124. case p^.right^.location.loc of
  125. LOC_REFERENCE,LOC_MEM:
  126. del_reference(p^.right^.location.reference);
  127. LOC_REGISTER,LOC_CREGISTER:
  128. ungetregister32(p^.right^.location.register);
  129. end;
  130. case p^.left^.location.loc of
  131. LOC_REFERENCE,LOC_MEM:
  132. del_reference(p^.left^.location.reference);
  133. LOC_REGISTER,LOC_CREGISTER:
  134. ungetregister32(p^.left^.location.register);
  135. end;
  136. savedunused:=unused;
  137. { push the still used registers }
  138. pushusedregisters(pushedregs,$ff);
  139. { push data }
  140. emit_push_loc(p^.right^.location);
  141. emit_push_loc(p^.left^.location);
  142. emitcall('FPC_ANSISTR_CONCAT',true);
  143. unused:=savedunused;
  144. clear_location(p^.location);
  145. p^.location.register:=getexplicitregister32(R_EAX);
  146. p^.location.loc:=LOC_REGISTER;
  147. emit_reg_reg(A_MOV,S_L,R_EAX,p^.location.register);
  148. popusedregisters(pushedregs);
  149. maybe_loadesi;
  150. ungetiftemp(p^.left^.location.reference);
  151. ungetiftemp(p^.right^.location.reference);
  152. reset_reference(hr);
  153. gettempansistringreference(hr);
  154. {temptoremove^.concat(new(ptemptodestroy,init(hr,p^.resulttype)));}
  155. exprasmlist^.concat(new(pai386,op_reg_ref(A_MOV,S_L,p^.location.register,
  156. newreference(hr))));
  157. end;
  158. ltn,lten,gtn,gten,
  159. equaln,unequaln:
  160. begin
  161. secondpass(p^.left);
  162. pushed:=maybe_push(p^.right^.registers32,p);
  163. secondpass(p^.right);
  164. if pushed then restore(p);
  165. { release used registers }
  166. case p^.right^.location.loc of
  167. LOC_REFERENCE,LOC_MEM:
  168. del_reference(p^.right^.location.reference);
  169. LOC_REGISTER,LOC_CREGISTER:
  170. ungetregister32(p^.right^.location.register);
  171. end;
  172. case p^.left^.location.loc of
  173. LOC_REFERENCE,LOC_MEM:
  174. del_reference(p^.left^.location.reference);
  175. LOC_REGISTER,LOC_CREGISTER:
  176. ungetregister32(p^.left^.location.register);
  177. end;
  178. { push the still used registers }
  179. pushusedregisters(pushedregs,$ff);
  180. { push data }
  181. case p^.right^.location.loc of
  182. LOC_REFERENCE,LOC_MEM:
  183. emit_push_mem(p^.right^.location.reference);
  184. LOC_REGISTER,LOC_CREGISTER:
  185. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,p^.right^.location.register)));
  186. end;
  187. case p^.left^.location.loc of
  188. LOC_REFERENCE,LOC_MEM:
  189. emit_push_mem(p^.left^.location.reference);
  190. LOC_REGISTER,LOC_CREGISTER:
  191. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,p^.left^.location.register)));
  192. end;
  193. emitcall('FPC_ANSISTR_COMPARE',true);
  194. emit_reg_reg(A_OR,S_L,R_EAX,R_EAX);
  195. popusedregisters(pushedregs);
  196. maybe_loadesi;
  197. ungetiftemp(p^.left^.location.reference);
  198. ungetiftemp(p^.right^.location.reference);
  199. end;
  200. end;
  201. { the result of ansicompare is signed }
  202. SetResultLocation(cmpop,false,p);
  203. end;
  204. st_shortstring:
  205. begin
  206. case p^.treetype of
  207. addn:
  208. begin
  209. cmpop:=false;
  210. secondpass(p^.left);
  211. { if str_concat is set in expr
  212. s:=s+ ... no need to create a temp string (PM) }
  213. if (p^.left^.treetype<>addn) and not (p^.use_strconcat) then
  214. begin
  215. { can only reference be }
  216. { string in register would be funny }
  217. { therefore produce a temporary string }
  218. { release the registers }
  219. del_reference(p^.left^.location.reference);
  220. gettempofsizereference(256,href);
  221. copyshortstring(href,p^.left^.location.reference,255,false);
  222. ungetiftemp(p^.left^.location.reference);
  223. { does not hurt: }
  224. clear_location(p^.left^.location);
  225. p^.left^.location.loc:=LOC_MEM;
  226. p^.left^.location.reference:=href;
  227. end;
  228. secondpass(p^.right);
  229. { on the right we do not need the register anymore too }
  230. del_reference(p^.right^.location.reference);
  231. pushusedregisters(pushedregs,$ff);
  232. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  233. emitpushreferenceaddr(exprasmlist,p^.right^.location.reference);
  234. emitcall('FPC_SHORTSTR_CONCAT',true);
  235. maybe_loadesi;
  236. popusedregisters(pushedregs);
  237. set_location(p^.location,p^.left^.location);
  238. ungetiftemp(p^.right^.location.reference);
  239. end;
  240. ltn,lten,gtn,gten,
  241. equaln,unequaln :
  242. begin
  243. cmpop:=true;
  244. { generate better code for s='' and s<>'' }
  245. if (p^.treetype in [equaln,unequaln]) and
  246. (((p^.left^.treetype=stringconstn) and (str_length(p^.left)=0)) or
  247. ((p^.right^.treetype=stringconstn) and (str_length(p^.right)=0))) then
  248. begin
  249. secondpass(p^.left);
  250. { are too few registers free? }
  251. pushed:=maybe_push(p^.right^.registers32,p);
  252. secondpass(p^.right);
  253. if pushed then restore(p);
  254. del_reference(p^.right^.location.reference);
  255. del_reference(p^.left^.location.reference);
  256. { only one node can be stringconstn }
  257. { else pass 1 would have evaluted }
  258. { this node }
  259. if p^.left^.treetype=stringconstn then
  260. exprasmlist^.concat(new(pai386,op_const_ref(
  261. A_CMP,S_B,0,newreference(p^.right^.location.reference))))
  262. else
  263. exprasmlist^.concat(new(pai386,op_const_ref(
  264. A_CMP,S_B,0,newreference(p^.left^.location.reference))));
  265. end
  266. else
  267. begin
  268. pushusedregisters(pushedregs,$ff);
  269. secondpass(p^.left);
  270. del_reference(p^.left^.location.reference);
  271. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  272. secondpass(p^.right);
  273. del_reference(p^.right^.location.reference);
  274. emitpushreferenceaddr(exprasmlist,p^.right^.location.reference);
  275. emitcall('FPC_SHORTSTR_COMPARE',true);
  276. maybe_loadesi;
  277. popusedregisters(pushedregs);
  278. end;
  279. ungetiftemp(p^.left^.location.reference);
  280. ungetiftemp(p^.right^.location.reference);
  281. end;
  282. else CGMessage(type_e_mismatch);
  283. end;
  284. SetResultLocation(cmpop,true,p);
  285. end;
  286. end;
  287. end;
  288. {*****************************************************************************
  289. Addset
  290. *****************************************************************************}
  291. procedure addset(var p : ptree);
  292. var
  293. createset,
  294. cmpop,
  295. pushed : boolean;
  296. href : treference;
  297. pushedregs : tpushed;
  298. begin
  299. cmpop:=false;
  300. { not commutative }
  301. if p^.swaped then
  302. swaptree(p);
  303. { optimize first loading of a set }
  304. {$ifdef usecreateset}
  305. if (p^.right^.treetype=setelementn) and
  306. is_emptyset(p^.left) then
  307. createset:=true
  308. else
  309. {$endif}
  310. begin
  311. createset:=false;
  312. secondpass(p^.left);
  313. end;
  314. { are too few registers free? }
  315. pushed:=maybe_push(p^.right^.registers32,p);
  316. secondpass(p^.right);
  317. if codegenerror then
  318. exit;
  319. if pushed then
  320. restore(p);
  321. set_location(p^.location,p^.left^.location);
  322. { handle operations }
  323. case p^.treetype of
  324. equaln,
  325. unequaln : begin
  326. cmpop:=true;
  327. del_reference(p^.left^.location.reference);
  328. del_reference(p^.right^.location.reference);
  329. pushusedregisters(pushedregs,$ff);
  330. emitpushreferenceaddr(exprasmlist,p^.right^.location.reference);
  331. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  332. emitcall('FPC_SET_COMP_SETS',true);
  333. maybe_loadesi;
  334. popusedregisters(pushedregs);
  335. ungetiftemp(p^.left^.location.reference);
  336. ungetiftemp(p^.right^.location.reference);
  337. end;
  338. addn : begin
  339. { add can be an other SET or Range or Element ! }
  340. del_reference(p^.left^.location.reference);
  341. del_reference(p^.right^.location.reference);
  342. pushusedregisters(pushedregs,$ff);
  343. href.symbol:=nil;
  344. gettempofsizereference(32,href);
  345. if createset then
  346. begin
  347. pushsetelement(p^.right^.left);
  348. emitpushreferenceaddr(exprasmlist,href);
  349. emitcall('FPC_SET_CREATE_ELEMENT',true);
  350. end
  351. else
  352. begin
  353. { add a range or a single element? }
  354. if p^.right^.treetype=setelementn then
  355. begin
  356. concatcopy(p^.left^.location.reference,href,32,false,false);
  357. if assigned(p^.right^.right) then
  358. begin
  359. pushsetelement(p^.right^.right);
  360. pushsetelement(p^.right^.left);
  361. emitpushreferenceaddr(exprasmlist,href);
  362. emitcall('FPC_SET_SET_RANGE',true);
  363. end
  364. else
  365. begin
  366. pushsetelement(p^.right^.left);
  367. emitpushreferenceaddr(exprasmlist,href);
  368. emitcall('FPC_SET_SET_BYTE',true);
  369. end;
  370. end
  371. else
  372. begin
  373. { must be an other set }
  374. emitpushreferenceaddr(exprasmlist,href);
  375. emitpushreferenceaddr(exprasmlist,p^.right^.location.reference);
  376. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  377. emitcall('FPC_SET_ADD_SETS',true);
  378. end;
  379. end;
  380. maybe_loadesi;
  381. popusedregisters(pushedregs);
  382. ungetiftemp(p^.left^.location.reference);
  383. ungetiftemp(p^.right^.location.reference);
  384. p^.location.loc:=LOC_MEM;
  385. stringdispose(p^.location.reference.symbol);
  386. p^.location.reference:=href;
  387. end;
  388. subn,
  389. symdifn,
  390. muln : begin
  391. del_reference(p^.left^.location.reference);
  392. del_reference(p^.right^.location.reference);
  393. href.symbol:=nil;
  394. pushusedregisters(pushedregs,$ff);
  395. gettempofsizereference(32,href);
  396. emitpushreferenceaddr(exprasmlist,href);
  397. emitpushreferenceaddr(exprasmlist,p^.right^.location.reference);
  398. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  399. case p^.treetype of
  400. subn : emitcall('FPC_SET_SUB_SETS',true);
  401. symdifn : emitcall('FPC_SET_SYMDIF_SETS',true);
  402. muln : emitcall('FPC_SET_MUL_SETS',true);
  403. end;
  404. maybe_loadesi;
  405. popusedregisters(pushedregs);
  406. ungetiftemp(p^.left^.location.reference);
  407. ungetiftemp(p^.right^.location.reference);
  408. p^.location.loc:=LOC_MEM;
  409. stringdispose(p^.location.reference.symbol);
  410. p^.location.reference:=href;
  411. end;
  412. else
  413. CGMessage(type_e_mismatch);
  414. end;
  415. SetResultLocation(cmpop,true,p);
  416. end;
  417. {*****************************************************************************
  418. SecondAdd
  419. *****************************************************************************}
  420. procedure secondadd(var p : ptree);
  421. { is also being used for xor, and "mul", "sub, or and comparative }
  422. { operators }
  423. label do_normal;
  424. var
  425. hregister : tregister;
  426. noswap,popeax,popedx,
  427. pushed,mboverflow,cmpop : boolean;
  428. op : tasmop;
  429. flags : tresflags;
  430. otl,ofl : plabel;
  431. power : longint;
  432. opsize : topsize;
  433. hl4: plabel;
  434. { true, if unsigned types are compared }
  435. unsigned : boolean;
  436. { true, if a small set is handled with the longint code }
  437. is_set : boolean;
  438. { is_in_dest if the result is put directly into }
  439. { the resulting refernce or varregister }
  440. is_in_dest : boolean;
  441. { true, if for sets subtractions the extra not should generated }
  442. extra_not : boolean;
  443. {$ifdef SUPPORT_MMX}
  444. mmxbase : tmmxtype;
  445. {$endif SUPPORT_MMX}
  446. begin
  447. { to make it more readable, string and set (not smallset!) have their
  448. own procedures }
  449. case p^.left^.resulttype^.deftype of
  450. stringdef : begin
  451. addstring(p);
  452. exit;
  453. end;
  454. setdef : begin
  455. { normalsets are handled separate }
  456. if not(psetdef(p^.left^.resulttype)^.settype=smallset) then
  457. begin
  458. addset(p);
  459. exit;
  460. end;
  461. end;
  462. end;
  463. { defaults }
  464. unsigned:=false;
  465. is_in_dest:=false;
  466. extra_not:=false;
  467. noswap:=false;
  468. opsize:=S_L;
  469. { are we a (small)set, must be set here because the side can be
  470. swapped ! (PFV) }
  471. is_set:=(p^.left^.resulttype^.deftype=setdef);
  472. { calculate the operator which is more difficult }
  473. firstcomplex(p);
  474. { handling boolean expressions extra: }
  475. if ((p^.left^.resulttype^.deftype=orddef) and
  476. (porddef(p^.left^.resulttype)^.typ in [bool8bit,bool16bit,bool32bit])) or
  477. ((p^.right^.resulttype^.deftype=orddef) and
  478. (porddef(p^.right^.resulttype)^.typ in [bool8bit,bool16bit,bool32bit])) then
  479. begin
  480. if (porddef(p^.left^.resulttype)^.typ=bool8bit) or
  481. (porddef(p^.right^.resulttype)^.typ=bool8bit) then
  482. opsize:=S_B
  483. else
  484. if (porddef(p^.left^.resulttype)^.typ=bool16bit) or
  485. (porddef(p^.right^.resulttype)^.typ=bool16bit) then
  486. opsize:=S_W
  487. else
  488. opsize:=S_L;
  489. case p^.treetype of
  490. andn,
  491. orn : begin
  492. clear_location(p^.location);
  493. p^.location.loc:=LOC_JUMP;
  494. cmpop:=false;
  495. case p^.treetype of
  496. andn : begin
  497. otl:=truelabel;
  498. getlabel(truelabel);
  499. secondpass(p^.left);
  500. maketojumpbool(p^.left);
  501. emitl(A_LABEL,truelabel);
  502. truelabel:=otl;
  503. end;
  504. orn : begin
  505. ofl:=falselabel;
  506. getlabel(falselabel);
  507. secondpass(p^.left);
  508. maketojumpbool(p^.left);
  509. emitl(A_LABEL,falselabel);
  510. falselabel:=ofl;
  511. end;
  512. else
  513. CGMessage(type_e_mismatch);
  514. end;
  515. secondpass(p^.right);
  516. maketojumpbool(p^.right);
  517. end;
  518. unequaln,
  519. equaln,xorn : begin
  520. if p^.left^.treetype=ordconstn then
  521. swaptree(p);
  522. secondpass(p^.left);
  523. set_location(p^.location,p^.left^.location);
  524. {p^.location:=p^.left^.location;
  525. created a bug !!! PM
  526. because symbol was used twice }
  527. { are enough registers free ? }
  528. pushed:=maybe_push(p^.right^.registers32,p);
  529. secondpass(p^.right);
  530. if pushed then restore(p);
  531. goto do_normal;
  532. end
  533. else
  534. CGMessage(type_e_mismatch);
  535. end
  536. end
  537. else
  538. begin
  539. { in case of constant put it to the left }
  540. if (p^.left^.treetype=ordconstn) then
  541. swaptree(p);
  542. secondpass(p^.left);
  543. { this will be complicated as
  544. a lot of code below assumes that
  545. p^.location and p^.left^.location are the same }
  546. {$ifdef test_dest_loc}
  547. if dest_loc_known and (dest_loc_tree=p) and
  548. ((dest_loc.loc=LOC_REGISTER) or (dest_loc.loc=LOC_CREGISTER)) then
  549. begin
  550. set_location(p^.location,dest_loc);
  551. in_dest_loc:=true;
  552. is_in_dest:=true;
  553. end
  554. else
  555. {$endif test_dest_loc}
  556. set_location(p^.location,p^.left^.location);
  557. { are too few registers free? }
  558. pushed:=maybe_push(p^.right^.registers32,p);
  559. secondpass(p^.right);
  560. if pushed then
  561. restore(p);
  562. if (p^.left^.resulttype^.deftype=pointerdef) or
  563. (p^.right^.resulttype^.deftype=pointerdef) or
  564. ((p^.right^.resulttype^.deftype=objectdef) and
  565. pobjectdef(p^.right^.resulttype)^.isclass and
  566. (p^.left^.resulttype^.deftype=objectdef) and
  567. pobjectdef(p^.left^.resulttype)^.isclass
  568. ) or
  569. (p^.left^.resulttype^.deftype=classrefdef) or
  570. (p^.left^.resulttype^.deftype=procvardef) or
  571. (p^.left^.resulttype^.deftype=enumdef) or
  572. ((p^.left^.resulttype^.deftype=orddef) and
  573. (porddef(p^.left^.resulttype)^.typ=s32bit)) or
  574. ((p^.right^.resulttype^.deftype=orddef) and
  575. (porddef(p^.right^.resulttype)^.typ=s32bit)) or
  576. ((p^.left^.resulttype^.deftype=orddef) and
  577. (porddef(p^.left^.resulttype)^.typ=u32bit)) or
  578. ((p^.right^.resulttype^.deftype=orddef) and
  579. (porddef(p^.right^.resulttype)^.typ=u32bit)) or
  580. { as well as small sets }
  581. is_set then
  582. begin
  583. do_normal:
  584. mboverflow:=false;
  585. cmpop:=false;
  586. if (p^.left^.resulttype^.deftype=pointerdef) or
  587. (p^.right^.resulttype^.deftype=pointerdef) or
  588. ((p^.left^.resulttype^.deftype=orddef) and
  589. (porddef(p^.left^.resulttype)^.typ=u32bit)) or
  590. ((p^.right^.resulttype^.deftype=orddef) and
  591. (porddef(p^.right^.resulttype)^.typ=u32bit)) then
  592. unsigned:=true;
  593. case p^.treetype of
  594. addn : begin
  595. if is_set then
  596. begin
  597. { adding elements is not commutative }
  598. if p^.swaped and (p^.left^.treetype=setelementn) then
  599. swaptree(p);
  600. { are we adding set elements ? }
  601. if p^.right^.treetype=setelementn then
  602. begin
  603. { no range support for smallsets! }
  604. if assigned(p^.right^.right) then
  605. internalerror(43244);
  606. { bts requires both elements to be registers }
  607. if p^.left^.location.loc in [LOC_MEM,LOC_REFERENCE] then
  608. begin
  609. ungetiftemp(p^.left^.location.reference);
  610. del_reference(p^.left^.location.reference);
  611. hregister:=getregister32;
  612. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  613. newreference(p^.left^.location.reference),hregister)));
  614. clear_location(p^.left^.location);
  615. p^.left^.location.loc:=LOC_REGISTER;
  616. p^.left^.location.register:=hregister;
  617. set_location(p^.location,p^.left^.location);
  618. end;
  619. if p^.right^.location.loc in [LOC_MEM,LOC_REFERENCE] then
  620. begin
  621. ungetiftemp(p^.right^.location.reference);
  622. del_reference(p^.right^.location.reference);
  623. hregister:=getregister32;
  624. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  625. newreference(p^.right^.location.reference),hregister)));
  626. clear_location(p^.right^.location);
  627. p^.right^.location.loc:=LOC_REGISTER;
  628. p^.right^.location.register:=hregister;
  629. end;
  630. op:=A_BTS;
  631. noswap:=true;
  632. end
  633. else
  634. op:=A_OR;
  635. mboverflow:=false;
  636. unsigned:=false;
  637. end
  638. else
  639. begin
  640. op:=A_ADD;
  641. mboverflow:=true;
  642. end;
  643. end;
  644. symdifn : begin
  645. { the symetric diff is only for sets }
  646. if is_set then
  647. begin
  648. op:=A_XOR;
  649. mboverflow:=false;
  650. unsigned:=false;
  651. end
  652. else
  653. CGMessage(type_e_mismatch);
  654. end;
  655. muln : begin
  656. if is_set then
  657. begin
  658. op:=A_AND;
  659. mboverflow:=false;
  660. unsigned:=false;
  661. end
  662. else
  663. begin
  664. if unsigned then
  665. op:=A_MUL
  666. else
  667. op:=A_IMUL;
  668. mboverflow:=true;
  669. end;
  670. end;
  671. subn : begin
  672. if is_set then
  673. begin
  674. op:=A_AND;
  675. mboverflow:=false;
  676. unsigned:=false;
  677. extra_not:=true;
  678. end
  679. else
  680. begin
  681. op:=A_SUB;
  682. mboverflow:=true;
  683. end;
  684. end;
  685. ltn,lten,
  686. gtn,gten,
  687. equaln,unequaln : begin
  688. op:=A_CMP;
  689. cmpop:=true;
  690. end;
  691. xorn : op:=A_XOR;
  692. orn : op:=A_OR;
  693. andn : op:=A_AND;
  694. else
  695. CGMessage(type_e_mismatch);
  696. end;
  697. { filter MUL, which requires special handling }
  698. if op=A_MUL then
  699. begin
  700. popeax:=false;
  701. popedx:=false;
  702. { here you need to free the symbol first }
  703. clear_location(p^.location);
  704. p^.location.register:=getregister32;
  705. p^.location.loc:=LOC_REGISTER;
  706. if not(R_EAX in unused) and (p^.location.register<>R_EAX) then
  707. begin
  708. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_EAX)));
  709. popeax:=true;
  710. end;
  711. if not(R_EDX in unused) and (p^.location.register<>R_EDX) then
  712. begin
  713. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_EDX)));
  714. popedx:=true;
  715. end;
  716. emitloadord2reg(p^.left^.location,u32bitdef,R_EDI,true);
  717. emitloadord2reg(p^.right^.location,u32bitdef,R_EAX,true);
  718. exprasmlist^.concat(new(pai386,op_reg(A_MUL,S_L,R_EDI)));
  719. emit_reg_reg(A_MOV,S_L,R_EAX,p^.location.register);
  720. if popeax then
  721. exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_EAX)));
  722. if popedx then
  723. exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_EDX)));
  724. SetResultLocation(false,true,p);
  725. exit;
  726. end;
  727. { left and right no register? }
  728. { then one must be demanded }
  729. if (p^.left^.location.loc<>LOC_REGISTER) and
  730. (p^.right^.location.loc<>LOC_REGISTER) then
  731. begin
  732. { register variable ? }
  733. if (p^.left^.location.loc=LOC_CREGISTER) then
  734. begin
  735. { it is OK if this is the destination }
  736. if is_in_dest then
  737. begin
  738. hregister:=p^.location.register;
  739. emit_reg_reg(A_MOV,opsize,p^.left^.location.register,
  740. hregister);
  741. end
  742. else
  743. if cmpop then
  744. begin
  745. { do not disturb the register }
  746. hregister:=p^.location.register;
  747. end
  748. else
  749. begin
  750. case opsize of
  751. S_L : hregister:=getregister32;
  752. S_B : hregister:=reg32toreg8(getregister32);
  753. end;
  754. emit_reg_reg(A_MOV,opsize,p^.left^.location.register,
  755. hregister);
  756. end
  757. end
  758. else
  759. begin
  760. ungetiftemp(p^.left^.location.reference);
  761. del_reference(p^.left^.location.reference);
  762. if is_in_dest then
  763. begin
  764. hregister:=p^.location.register;
  765. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  766. newreference(p^.left^.location.reference),hregister)));
  767. end
  768. else
  769. begin
  770. { first give free, then demand new register }
  771. case opsize of
  772. S_L : hregister:=getregister32;
  773. S_W : hregister:=reg32toreg16(getregister32);
  774. S_B : hregister:=reg32toreg8(getregister32);
  775. end;
  776. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  777. newreference(p^.left^.location.reference),hregister)));
  778. end;
  779. end;
  780. clear_location(p^.location);
  781. p^.location.loc:=LOC_REGISTER;
  782. p^.location.register:=hregister;
  783. end
  784. else
  785. { if on the right the register then swap }
  786. if not(noswap) and (p^.right^.location.loc=LOC_REGISTER) then
  787. begin
  788. swap_location(p^.location,p^.right^.location);
  789. { newly swapped also set swapped flag }
  790. p^.swaped:=not(p^.swaped);
  791. end;
  792. { at this point, p^.location.loc should be LOC_REGISTER }
  793. { and p^.location.register should be a valid register }
  794. { containing the left result }
  795. if p^.right^.location.loc<>LOC_REGISTER then
  796. begin
  797. if (p^.treetype=subn) and p^.swaped then
  798. begin
  799. if p^.right^.location.loc=LOC_CREGISTER then
  800. begin
  801. if extra_not then
  802. exprasmlist^.concat(new(pai386,op_reg(A_NOT,opsize,p^.location.register)));
  803. emit_reg_reg(A_MOV,opsize,p^.right^.location.register,R_EDI);
  804. emit_reg_reg(op,opsize,p^.location.register,R_EDI);
  805. emit_reg_reg(A_MOV,opsize,R_EDI,p^.location.register);
  806. end
  807. else
  808. begin
  809. if extra_not then
  810. exprasmlist^.concat(new(pai386,op_reg(A_NOT,opsize,p^.location.register)));
  811. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  812. newreference(p^.right^.location.reference),R_EDI)));
  813. exprasmlist^.concat(new(pai386,op_reg_reg(op,opsize,p^.location.register,R_EDI)));
  814. exprasmlist^.concat(new(pai386,op_reg_reg(A_MOV,opsize,R_EDI,p^.location.register)));
  815. ungetiftemp(p^.right^.location.reference);
  816. del_reference(p^.right^.location.reference);
  817. end;
  818. end
  819. else
  820. begin
  821. if (p^.right^.treetype=ordconstn) and
  822. (op=A_CMP) and
  823. (p^.right^.value=0) then
  824. begin
  825. exprasmlist^.concat(new(pai386,op_reg_reg(A_TEST,opsize,p^.location.register,
  826. p^.location.register)));
  827. end
  828. else if (p^.right^.treetype=ordconstn) and
  829. (op=A_ADD) and
  830. (p^.right^.value=1) then
  831. begin
  832. exprasmlist^.concat(new(pai386,op_reg(A_INC,opsize,
  833. p^.location.register)));
  834. end
  835. else if (p^.right^.treetype=ordconstn) and
  836. (op=A_SUB) and
  837. (p^.right^.value=1) then
  838. begin
  839. exprasmlist^.concat(new(pai386,op_reg(A_DEC,opsize,
  840. p^.location.register)));
  841. end
  842. else if (p^.right^.treetype=ordconstn) and
  843. (op=A_IMUL) and
  844. (ispowerof2(p^.right^.value,power)) then
  845. begin
  846. exprasmlist^.concat(new(pai386,op_const_reg(A_SHL,opsize,power,
  847. p^.location.register)));
  848. end
  849. else
  850. begin
  851. if (p^.right^.location.loc=LOC_CREGISTER) then
  852. begin
  853. if extra_not then
  854. begin
  855. emit_reg_reg(A_MOV,S_L,p^.right^.location.register,R_EDI);
  856. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,R_EDI)));
  857. emit_reg_reg(A_AND,S_L,R_EDI,
  858. p^.location.register);
  859. end
  860. else
  861. begin
  862. emit_reg_reg(op,opsize,p^.right^.location.register,
  863. p^.location.register);
  864. end;
  865. end
  866. else
  867. begin
  868. if extra_not then
  869. begin
  870. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,newreference(
  871. p^.right^.location.reference),R_EDI)));
  872. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,R_EDI)));
  873. emit_reg_reg(A_AND,S_L,R_EDI,
  874. p^.location.register);
  875. end
  876. else
  877. begin
  878. exprasmlist^.concat(new(pai386,op_ref_reg(op,opsize,newreference(
  879. p^.right^.location.reference),p^.location.register)));
  880. end;
  881. ungetiftemp(p^.right^.location.reference);
  882. del_reference(p^.right^.location.reference);
  883. end;
  884. end;
  885. end;
  886. end
  887. else
  888. begin
  889. { when swapped another result register }
  890. if (p^.treetype=subn) and p^.swaped then
  891. begin
  892. if extra_not then
  893. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,p^.location.register)));
  894. exprasmlist^.concat(new(pai386,op_reg_reg(op,opsize,
  895. p^.location.register,p^.right^.location.register)));
  896. swap_location(p^.location,p^.right^.location);
  897. { newly swapped also set swapped flag }
  898. { just to maintain ordering }
  899. p^.swaped:=not(p^.swaped);
  900. end
  901. else
  902. begin
  903. if extra_not then
  904. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,p^.right^.location.register)));
  905. exprasmlist^.concat(new(pai386,op_reg_reg(op,opsize,
  906. p^.right^.location.register,
  907. p^.location.register)));
  908. end;
  909. case opsize of
  910. S_L : ungetregister32(p^.right^.location.register);
  911. S_B : ungetregister32(reg8toreg32(p^.right^.location.register));
  912. end;
  913. end;
  914. if cmpop then
  915. case opsize of
  916. S_L : ungetregister32(p^.location.register);
  917. S_B : ungetregister32(reg8toreg32(p^.location.register));
  918. end;
  919. { only in case of overflow operations }
  920. { produce overflow code }
  921. { we must put it here directly, because sign of operation }
  922. { is in unsigned VAR!! }
  923. if mboverflow then
  924. begin
  925. if cs_check_overflow in aktlocalswitches then
  926. begin
  927. getlabel(hl4);
  928. if unsigned then
  929. emitl(A_JNB,hl4)
  930. else
  931. emitl(A_JNO,hl4);
  932. emitcall('FPC_OVERFLOW',true);
  933. emitl(A_LABEL,hl4);
  934. end;
  935. end;
  936. end
  937. else
  938. { Char type }
  939. if ((p^.left^.resulttype^.deftype=orddef) and
  940. (porddef(p^.left^.resulttype)^.typ=uchar)) then
  941. begin
  942. case p^.treetype of
  943. ltn,lten,gtn,gten,
  944. equaln,unequaln :
  945. cmpop:=true;
  946. else CGMessage(type_e_mismatch);
  947. end;
  948. unsigned:=true;
  949. { left and right no register? }
  950. { the one must be demanded }
  951. if (p^.location.loc<>LOC_REGISTER) and
  952. (p^.right^.location.loc<>LOC_REGISTER) then
  953. begin
  954. if p^.location.loc=LOC_CREGISTER then
  955. begin
  956. if cmpop then
  957. { do not disturb register }
  958. hregister:=p^.location.register
  959. else
  960. begin
  961. hregister:=reg32toreg8(getregister32);
  962. emit_reg_reg(A_MOV,S_B,p^.location.register,
  963. hregister);
  964. end;
  965. end
  966. else
  967. begin
  968. del_reference(p^.location.reference);
  969. { first give free then demand new register }
  970. hregister:=reg32toreg8(getregister32);
  971. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_B,newreference(p^.location.reference),
  972. hregister)));
  973. end;
  974. clear_location(p^.location);
  975. p^.location.loc:=LOC_REGISTER;
  976. p^.location.register:=hregister;
  977. end;
  978. { now p always a register }
  979. if (p^.right^.location.loc=LOC_REGISTER) and
  980. (p^.location.loc<>LOC_REGISTER) then
  981. begin
  982. swap_location(p^.location,p^.right^.location);
  983. { newly swapped also set swapped flag }
  984. p^.swaped:=not(p^.swaped);
  985. end;
  986. if p^.right^.location.loc<>LOC_REGISTER then
  987. begin
  988. if p^.right^.location.loc=LOC_CREGISTER then
  989. begin
  990. emit_reg_reg(A_CMP,S_B,
  991. p^.right^.location.register,p^.location.register);
  992. end
  993. else
  994. begin
  995. exprasmlist^.concat(new(pai386,op_ref_reg(A_CMP,S_B,newreference(
  996. p^.right^.location.reference),p^.location.register)));
  997. del_reference(p^.right^.location.reference);
  998. end;
  999. end
  1000. else
  1001. begin
  1002. emit_reg_reg(A_CMP,S_B,p^.right^.location.register,
  1003. p^.location.register);
  1004. ungetregister32(reg8toreg32(p^.right^.location.register));
  1005. end;
  1006. ungetregister32(reg8toreg32(p^.location.register));
  1007. end
  1008. else
  1009. { Floating point }
  1010. if (p^.left^.resulttype^.deftype=floatdef) and
  1011. (pfloatdef(p^.left^.resulttype)^.typ<>f32bit) then
  1012. begin
  1013. { real constants to the left }
  1014. if p^.left^.treetype=realconstn then
  1015. swaptree(p);
  1016. cmpop:=false;
  1017. case p^.treetype of
  1018. addn : op:=A_FADDP;
  1019. muln : op:=A_FMULP;
  1020. subn : op:=A_FSUBP;
  1021. slashn : op:=A_FDIVP;
  1022. ltn,lten,gtn,gten,
  1023. equaln,unequaln : begin
  1024. op:=A_FCOMPP;
  1025. cmpop:=true;
  1026. end;
  1027. else CGMessage(type_e_mismatch);
  1028. end;
  1029. if (p^.right^.location.loc<>LOC_FPU) then
  1030. begin
  1031. floatload(pfloatdef(p^.right^.resulttype)^.typ,p^.right^.location.reference);
  1032. if (p^.left^.location.loc<>LOC_FPU) then
  1033. floatload(pfloatdef(p^.left^.resulttype)^.typ,p^.left^.location.reference)
  1034. { left was on the stack => swap }
  1035. else
  1036. p^.swaped:=not(p^.swaped);
  1037. { releases the right reference }
  1038. del_reference(p^.right^.location.reference);
  1039. end
  1040. { the nominator in st0 }
  1041. else if (p^.left^.location.loc<>LOC_FPU) then
  1042. floatload(pfloatdef(p^.left^.resulttype)^.typ,p^.left^.location.reference)
  1043. { fpu operands are always in the wrong order on the stack }
  1044. else
  1045. p^.swaped:=not(p^.swaped);
  1046. { releases the left reference }
  1047. if (p^.left^.location.loc<>LOC_FPU) then
  1048. del_reference(p^.left^.location.reference);
  1049. { if we swaped the tree nodes, then use the reverse operator }
  1050. if p^.swaped then
  1051. begin
  1052. if (p^.treetype=slashn) then
  1053. op:=A_FDIVRP
  1054. else if (p^.treetype=subn) then
  1055. op:=A_FSUBRP;
  1056. end;
  1057. { to avoid the pentium bug
  1058. if (op=FDIVP) and (opt_processors=pentium) then
  1059. exprasmlist^.concat(new(pai386,op_CALL,S_NO,'EMUL_FDIVP')
  1060. else
  1061. }
  1062. { the Intel assemblers want operands }
  1063. if op<>A_FCOMPP then
  1064. exprasmlist^.concat(new(pai386,op_reg_reg(op,S_NO,R_ST,R_ST1)))
  1065. else
  1066. exprasmlist^.concat(new(pai386,op_none(op,S_NO)));
  1067. { on comparison load flags }
  1068. if cmpop then
  1069. begin
  1070. if not(R_EAX in unused) then
  1071. emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
  1072. exprasmlist^.concat(new(pai386,op_reg(A_FNSTSW,S_NO,R_AX)));
  1073. exprasmlist^.concat(new(pai386,op_none(A_SAHF,S_NO)));
  1074. if not(R_EAX in unused) then
  1075. emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
  1076. if p^.swaped then
  1077. begin
  1078. case p^.treetype of
  1079. equaln : flags:=F_E;
  1080. unequaln : flags:=F_NE;
  1081. ltn : flags:=F_A;
  1082. lten : flags:=F_AE;
  1083. gtn : flags:=F_B;
  1084. gten : flags:=F_BE;
  1085. end;
  1086. end
  1087. else
  1088. begin
  1089. case p^.treetype of
  1090. equaln : flags:=F_E;
  1091. unequaln : flags:=F_NE;
  1092. ltn : flags:=F_B;
  1093. lten : flags:=F_BE;
  1094. gtn : flags:=F_A;
  1095. gten : flags:=F_AE;
  1096. end;
  1097. end;
  1098. clear_location(p^.location);
  1099. p^.location.loc:=LOC_FLAGS;
  1100. p^.location.resflags:=flags;
  1101. cmpop:=false;
  1102. end
  1103. else
  1104. begin
  1105. clear_location(p^.location);
  1106. p^.location.loc:=LOC_FPU;
  1107. end;
  1108. end
  1109. {$ifdef SUPPORT_MMX}
  1110. else
  1111. { MMX Arrays }
  1112. if is_mmx_able_array(p^.left^.resulttype) then
  1113. begin
  1114. cmpop:=false;
  1115. mmxbase:=mmx_type(p^.left^.resulttype);
  1116. case p^.treetype of
  1117. addn : begin
  1118. if (cs_mmx_saturation in aktlocalswitches) then
  1119. begin
  1120. case mmxbase of
  1121. mmxs8bit:
  1122. op:=A_PADDSB;
  1123. mmxu8bit:
  1124. op:=A_PADDUSB;
  1125. mmxs16bit,mmxfixed16:
  1126. op:=A_PADDSB;
  1127. mmxu16bit:
  1128. op:=A_PADDUSW;
  1129. end;
  1130. end
  1131. else
  1132. begin
  1133. case mmxbase of
  1134. mmxs8bit,mmxu8bit:
  1135. op:=A_PADDB;
  1136. mmxs16bit,mmxu16bit,mmxfixed16:
  1137. op:=A_PADDW;
  1138. mmxs32bit,mmxu32bit:
  1139. op:=A_PADDD;
  1140. end;
  1141. end;
  1142. end;
  1143. muln : begin
  1144. case mmxbase of
  1145. mmxs16bit,mmxu16bit:
  1146. op:=A_PMULLW;
  1147. mmxfixed16:
  1148. op:=A_PMULHW;
  1149. end;
  1150. end;
  1151. subn : begin
  1152. if (cs_mmx_saturation in aktlocalswitches) then
  1153. begin
  1154. case mmxbase of
  1155. mmxs8bit:
  1156. op:=A_PSUBSB;
  1157. mmxu8bit:
  1158. op:=A_PSUBUSB;
  1159. mmxs16bit,mmxfixed16:
  1160. op:=A_PSUBSB;
  1161. mmxu16bit:
  1162. op:=A_PSUBUSW;
  1163. end;
  1164. end
  1165. else
  1166. begin
  1167. case mmxbase of
  1168. mmxs8bit,mmxu8bit:
  1169. op:=A_PSUBB;
  1170. mmxs16bit,mmxu16bit,mmxfixed16:
  1171. op:=A_PSUBW;
  1172. mmxs32bit,mmxu32bit:
  1173. op:=A_PSUBD;
  1174. end;
  1175. end;
  1176. end;
  1177. {
  1178. ltn,lten,gtn,gten,
  1179. equaln,unequaln :
  1180. begin
  1181. op:=A_CMP;
  1182. cmpop:=true;
  1183. end;
  1184. }
  1185. xorn:
  1186. op:=A_PXOR;
  1187. orn:
  1188. op:=A_POR;
  1189. andn:
  1190. op:=A_PAND;
  1191. else CGMessage(type_e_mismatch);
  1192. end;
  1193. { left and right no register? }
  1194. { then one must be demanded }
  1195. if (p^.left^.location.loc<>LOC_MMXREGISTER) and
  1196. (p^.right^.location.loc<>LOC_MMXREGISTER) then
  1197. begin
  1198. { register variable ? }
  1199. if (p^.left^.location.loc=LOC_CMMXREGISTER) then
  1200. begin
  1201. { it is OK if this is the destination }
  1202. if is_in_dest then
  1203. begin
  1204. hregister:=p^.location.register;
  1205. emit_reg_reg(A_MOVQ,S_NO,p^.left^.location.register,
  1206. hregister);
  1207. end
  1208. else
  1209. begin
  1210. hregister:=getregistermmx;
  1211. emit_reg_reg(A_MOVQ,S_NO,p^.left^.location.register,
  1212. hregister);
  1213. end
  1214. end
  1215. else
  1216. begin
  1217. del_reference(p^.left^.location.reference);
  1218. if is_in_dest then
  1219. begin
  1220. hregister:=p^.location.register;
  1221. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOVQ,S_NO,
  1222. newreference(p^.left^.location.reference),hregister)));
  1223. end
  1224. else
  1225. begin
  1226. hregister:=getregistermmx;
  1227. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOVQ,S_NO,
  1228. newreference(p^.left^.location.reference),hregister)));
  1229. end;
  1230. end;
  1231. clear_location(p^.location);
  1232. p^.location.loc:=LOC_MMXREGISTER;
  1233. p^.location.register:=hregister;
  1234. end
  1235. else
  1236. { if on the right the register then swap }
  1237. if (p^.right^.location.loc=LOC_MMXREGISTER) then
  1238. begin
  1239. swap_location(p^.location,p^.right^.location);
  1240. { newly swapped also set swapped flag }
  1241. p^.swaped:=not(p^.swaped);
  1242. end;
  1243. { at this point, p^.location.loc should be LOC_MMXREGISTER }
  1244. { and p^.location.register should be a valid register }
  1245. { containing the left result }
  1246. if p^.right^.location.loc<>LOC_MMXREGISTER then
  1247. begin
  1248. if (p^.treetype=subn) and p^.swaped then
  1249. begin
  1250. if p^.right^.location.loc=LOC_CMMXREGISTER then
  1251. begin
  1252. emit_reg_reg(A_MOVQ,S_NO,p^.right^.location.register,R_MM7);
  1253. emit_reg_reg(op,S_NO,p^.location.register,R_EDI);
  1254. emit_reg_reg(A_MOVQ,S_NO,R_MM7,p^.location.register);
  1255. end
  1256. else
  1257. begin
  1258. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOVQ,S_NO,
  1259. newreference(p^.right^.location.reference),R_MM7)));
  1260. exprasmlist^.concat(new(pai386,op_reg_reg(op,S_NO,p^.location.register,
  1261. R_MM7)));
  1262. exprasmlist^.concat(new(pai386,op_reg_reg(A_MOVQ,S_NO,
  1263. R_MM7,p^.location.register)));
  1264. del_reference(p^.right^.location.reference);
  1265. end;
  1266. end
  1267. else
  1268. begin
  1269. if (p^.right^.location.loc=LOC_CREGISTER) then
  1270. begin
  1271. emit_reg_reg(op,S_NO,p^.right^.location.register,
  1272. p^.location.register);
  1273. end
  1274. else
  1275. begin
  1276. exprasmlist^.concat(new(pai386,op_ref_reg(op,S_NO,newreference(
  1277. p^.right^.location.reference),p^.location.register)));
  1278. del_reference(p^.right^.location.reference);
  1279. end;
  1280. end;
  1281. end
  1282. else
  1283. begin
  1284. { when swapped another result register }
  1285. if (p^.treetype=subn) and p^.swaped then
  1286. begin
  1287. exprasmlist^.concat(new(pai386,op_reg_reg(op,S_NO,
  1288. p^.location.register,p^.right^.location.register)));
  1289. swap_location(p^.location,p^.right^.location);
  1290. { newly swapped also set swapped flag }
  1291. { just to maintain ordering }
  1292. p^.swaped:=not(p^.swaped);
  1293. end
  1294. else
  1295. begin
  1296. exprasmlist^.concat(new(pai386,op_reg_reg(op,S_NO,
  1297. p^.right^.location.register,
  1298. p^.location.register)));
  1299. end;
  1300. ungetregistermmx(p^.right^.location.register);
  1301. end;
  1302. end
  1303. {$endif SUPPORT_MMX}
  1304. else CGMessage(type_e_mismatch);
  1305. end;
  1306. SetResultLocation(cmpop,unsigned,p);
  1307. end;
  1308. end.
  1309. {
  1310. $Log$
  1311. Revision 1.31 1998-11-30 09:42:59 pierre
  1312. * some range check bugs fixed (still not working !)
  1313. + added DLL writing support for win32 (also accepts variables)
  1314. + TempAnsi for code that could be used for Temporary ansi strings
  1315. handling
  1316. Revision 1.30 1998/11/24 12:52:40 peter
  1317. * sets are not written twice anymore
  1318. * optimize for emptyset+single element which uses a new routine from
  1319. set.inc FPC_SET_CREATE_ELEMENT
  1320. Revision 1.29 1998/11/18 15:44:05 peter
  1321. * VALUEPARA for tp7 compatible value parameters
  1322. Revision 1.28 1998/11/18 09:18:01 pierre
  1323. + automatic loading of profile unit with -pg option
  1324. in go32v2 mode (also defines FPC_PROFILE)
  1325. * some memory leaks removed
  1326. * unreleased temp problem with sets solved
  1327. Revision 1.27 1998/11/17 00:36:38 peter
  1328. * more ansistring fixes
  1329. Revision 1.26 1998/11/16 16:17:16 peter
  1330. * fixed ansistring temp which forgot a reset
  1331. Revision 1.25 1998/11/16 15:35:35 peter
  1332. * rename laod/copystring -> load/copyshortstring
  1333. * fixed int-bool cnv bug
  1334. + char-ansistring conversion
  1335. Revision 1.24 1998/11/07 12:49:30 peter
  1336. * fixed ansicompare which returns signed
  1337. Revision 1.23 1998/10/29 15:42:43 florian
  1338. + partial disposing of temp. ansistrings
  1339. Revision 1.22 1998/10/28 18:26:12 pierre
  1340. * removed some erros after other errors (introduced by useexcept)
  1341. * stabs works again correctly (for how long !)
  1342. Revision 1.21 1998/10/25 23:32:48 peter
  1343. * fixed unsigned mul
  1344. Revision 1.20 1998/10/21 08:39:56 florian
  1345. + ansistring operator +
  1346. + $h and string[n] for n>255 added
  1347. * small problem with TP fixed
  1348. Revision 1.19 1998/10/20 15:09:21 florian
  1349. + binary operators for ansi strings
  1350. Revision 1.18 1998/10/20 08:06:38 pierre
  1351. * several memory corruptions due to double freemem solved
  1352. => never use p^.loc.location:=p^.left^.loc.location;
  1353. + finally I added now by default
  1354. that ra386dir translates global and unit symbols
  1355. + added a first field in tsymtable and
  1356. a nextsym field in tsym
  1357. (this allows to obtain ordered type info for
  1358. records and objects in gdb !)
  1359. Revision 1.17 1998/10/09 11:47:45 pierre
  1360. * still more memory leaks fixes !!
  1361. Revision 1.16 1998/10/09 08:56:21 pierre
  1362. * several memory leaks fixed
  1363. Revision 1.15 1998/10/08 17:17:10 pierre
  1364. * current_module old scanner tagged as invalid if unit is recompiled
  1365. + added ppheap for better info on tracegetmem of heaptrc
  1366. (adds line column and file index)
  1367. * several memory leaks removed ith help of heaptrc !!
  1368. Revision 1.14 1998/09/28 16:57:13 pierre
  1369. * changed all length(p^.value_str^) into str_length(p)
  1370. to get it work with and without ansistrings
  1371. * changed sourcefiles field of tmodule to a pointer
  1372. Revision 1.13 1998/09/17 09:42:09 peter
  1373. + pass_2 for cg386
  1374. * Message() -> CGMessage() for pass_1/pass_2
  1375. Revision 1.12 1998/09/14 10:43:44 peter
  1376. * all internal RTL functions start with FPC_
  1377. Revision 1.11 1998/09/07 18:45:52 peter
  1378. * update smartlinking, uses getdatalabel
  1379. * renamed ptree.value vars to value_str,value_real,value_set
  1380. Revision 1.10 1998/09/04 10:05:04 florian
  1381. * ugly fix for STRCAT, nevertheless it needs more fixing !!!!!!!
  1382. we need an new version of STRCAT which takes a length parameter
  1383. Revision 1.9 1998/09/04 08:41:36 peter
  1384. * updated some error CGMessages
  1385. Revision 1.8 1998/08/28 10:54:18 peter
  1386. * fixed smallset generation from elements, it has never worked before!
  1387. Revision 1.7 1998/08/19 14:56:59 peter
  1388. * forgot to removed some unused code in addset for set<>set
  1389. Revision 1.6 1998/08/18 09:24:35 pierre
  1390. * small warning position bug fixed
  1391. * support_mmx switches splitting was missing
  1392. * rhide error and warning output corrected
  1393. Revision 1.5 1998/08/14 18:18:37 peter
  1394. + dynamic set contruction
  1395. * smallsets are now working (always longint size)
  1396. Revision 1.4 1998/08/10 14:49:42 peter
  1397. + localswitches, moduleswitches, globalswitches splitting
  1398. Revision 1.3 1998/06/25 08:48:04 florian
  1399. * first version of rtti support
  1400. Revision 1.2 1998/06/08 13:13:28 pierre
  1401. + temporary variables now in temp_gen.pas unit
  1402. because it is processor independent
  1403. * mppc68k.bat modified to undefine i386 and support_mmx
  1404. (which are defaults for i386)
  1405. Revision 1.1 1998/06/05 17:44:10 peter
  1406. * splitted cgi386
  1407. }