cg386add.pas 68 KB

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