n386add.pas 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771
  1. {
  2. $Id$
  3. Copyright (c) 2000-2002 by Florian Klaempfl
  4. Code generation for add nodes on the i386
  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 n386add;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. node,nadd,cpubase,cginfo;
  23. type
  24. ti386addnode = class(taddnode)
  25. procedure pass_2;override;
  26. protected
  27. function first_addstring : tnode; override;
  28. private
  29. procedure pass_left_and_right(var pushedfpu:boolean);
  30. function getresflags(unsigned : boolean) : tresflags;
  31. procedure left_must_be_reg(opsize:TOpSize;noswap:boolean);
  32. procedure emit_op_right_left(op:TAsmOp;opsize:TOpSize);
  33. procedure emit_generic_code(op:TAsmOp;opsize:TOpSize;unsigned,extra_not,mboverflow:boolean);
  34. procedure set_result_location(cmpop,unsigned:boolean);
  35. procedure second_addstring;
  36. procedure second_addboolean;
  37. procedure second_addfloat;
  38. procedure second_addsmallset;
  39. procedure second_mul;
  40. {$ifdef SUPPORT_MMX}
  41. procedure second_addmmx;
  42. {$endif SUPPORT_MMX}
  43. procedure second_add64bit;
  44. end;
  45. implementation
  46. uses
  47. globtype,systems,
  48. cutils,verbose,globals,
  49. symconst,symdef,paramgr,
  50. aasmbase,aasmtai,aasmcpu,defutil,htypechk,
  51. cgbase,pass_2,regvars,
  52. cpupara,
  53. ncon,nset,
  54. cga,ncgutil,tgobj,rgobj,rgcpu,cgobj,cg64f32;
  55. {*****************************************************************************
  56. Helpers
  57. *****************************************************************************}
  58. const
  59. opsize_2_cgsize : array[S_B..S_L] of tcgsize = (OS_8,OS_16,OS_32);
  60. procedure ti386addnode.pass_left_and_right(var pushedfpu:boolean);
  61. var
  62. pushedregs : tmaybesave;
  63. begin
  64. { calculate the operator which is more difficult }
  65. firstcomplex(self);
  66. { in case of constant put it to the left }
  67. if (left.nodetype=ordconstn) then
  68. swapleftright;
  69. secondpass(left);
  70. { are too few registers free? }
  71. maybe_save(exprasmlist,right.registers32,left.location,pushedregs);
  72. if location.loc=LOC_FPUREGISTER then
  73. pushedfpu:=maybe_pushfpu(exprasmlist,right.registersfpu,left.location)
  74. else
  75. pushedfpu:=false;
  76. secondpass(right);
  77. maybe_restore(exprasmlist,left.location,pushedregs);
  78. end;
  79. function ti386addnode.getresflags(unsigned : boolean) : tresflags;
  80. begin
  81. case nodetype of
  82. equaln : getresflags:=F_E;
  83. unequaln : getresflags:=F_NE;
  84. else
  85. if not(unsigned) then
  86. begin
  87. if nf_swaped in flags then
  88. case nodetype of
  89. ltn : getresflags:=F_G;
  90. lten : getresflags:=F_GE;
  91. gtn : getresflags:=F_L;
  92. gten : getresflags:=F_LE;
  93. end
  94. else
  95. case nodetype of
  96. ltn : getresflags:=F_L;
  97. lten : getresflags:=F_LE;
  98. gtn : getresflags:=F_G;
  99. gten : getresflags:=F_GE;
  100. end;
  101. end
  102. else
  103. begin
  104. if nf_swaped in flags then
  105. case nodetype of
  106. ltn : getresflags:=F_A;
  107. lten : getresflags:=F_AE;
  108. gtn : getresflags:=F_B;
  109. gten : getresflags:=F_BE;
  110. end
  111. else
  112. case nodetype of
  113. ltn : getresflags:=F_B;
  114. lten : getresflags:=F_BE;
  115. gtn : getresflags:=F_A;
  116. gten : getresflags:=F_AE;
  117. end;
  118. end;
  119. end;
  120. end;
  121. procedure ti386addnode.left_must_be_reg(opsize:TOpSize;noswap:boolean);
  122. begin
  123. { left location is not a register? }
  124. if (left.location.loc<>LOC_REGISTER) then
  125. begin
  126. { if right is register then we can swap the locations }
  127. if (not noswap) and
  128. (right.location.loc=LOC_REGISTER) then
  129. begin
  130. location_swap(left.location,right.location);
  131. toggleflag(nf_swaped);
  132. end
  133. else
  134. begin
  135. { maybe we can reuse a constant register when the
  136. operation is a comparison that doesn't change the
  137. value of the register }
  138. location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],(nodetype in [ltn,lten,gtn,gten,equaln,unequaln]));
  139. end;
  140. end;
  141. end;
  142. procedure ti386addnode.emit_op_right_left(op:TAsmOp;opsize:TOpsize);
  143. begin
  144. { left must be a register }
  145. case right.location.loc of
  146. LOC_REGISTER,
  147. LOC_CREGISTER :
  148. exprasmlist.concat(taicpu.op_reg_reg(op,opsize,right.location.register,left.location.register));
  149. LOC_REFERENCE,
  150. LOC_CREFERENCE :
  151. exprasmlist.concat(taicpu.op_ref_reg(op,opsize,right.location.reference,left.location.register));
  152. LOC_CONSTANT :
  153. exprasmlist.concat(taicpu.op_const_reg(op,opsize,right.location.value,left.location.register));
  154. else
  155. internalerror(200203232);
  156. end;
  157. end;
  158. procedure ti386addnode.set_result_location(cmpop,unsigned:boolean);
  159. begin
  160. if cmpop then
  161. begin
  162. location_reset(location,LOC_FLAGS,OS_NO);
  163. location.resflags:=getresflags(unsigned);
  164. end
  165. else
  166. location_copy(location,left.location);
  167. end;
  168. procedure ti386addnode.emit_generic_code(op:TAsmOp;opsize:TOpSize;unsigned,extra_not,mboverflow:boolean);
  169. var
  170. power : longint;
  171. hl4 : tasmlabel;
  172. r:Tregister;
  173. nr:Tnewregister;
  174. begin
  175. { at this point, left.location.loc should be LOC_REGISTER }
  176. if right.location.loc=LOC_REGISTER then
  177. begin
  178. { right.location is a LOC_REGISTER }
  179. { when swapped another result register }
  180. if (nodetype=subn) and (nf_swaped in flags) then
  181. begin
  182. if extra_not then
  183. emit_reg(A_NOT,S_L,left.location.register);
  184. emit_reg_reg(op,opsize,left.location.register,right.location.register);
  185. { newly swapped also set swapped flag }
  186. location_swap(left.location,right.location);
  187. toggleflag(nf_swaped);
  188. end
  189. else
  190. begin
  191. if extra_not then
  192. emit_reg(A_NOT,S_L,right.location.register);
  193. emit_reg_reg(op,opsize,right.location.register,left.location.register);
  194. end;
  195. end
  196. else
  197. begin
  198. { right.location is not a LOC_REGISTER }
  199. if (nodetype=subn) and (nf_swaped in flags) then
  200. begin
  201. if extra_not then
  202. emit_reg(A_NOT,opsize,left.location.register);
  203. r.enum:=R_INTREGISTER;
  204. r.number:=NR_EDI;
  205. rg.getexplicitregisterint(exprasmlist,NR_EDI);
  206. cg.a_load_loc_reg(exprasmlist,right.location,r);
  207. emit_reg_reg(op,opsize,left.location.register,r);
  208. emit_reg_reg(A_MOV,opsize,r,left.location.register);
  209. rg.ungetregisterint(exprasmlist,r);
  210. end
  211. else
  212. begin
  213. { Optimizations when right.location is a constant value }
  214. if (op=A_CMP) and
  215. (nodetype in [equaln,unequaln]) and
  216. (right.location.loc=LOC_CONSTANT) and
  217. (right.location.value=0) then
  218. begin
  219. emit_reg_reg(A_TEST,opsize,left.location.register,left.location.register);
  220. end
  221. else
  222. if (op=A_ADD) and
  223. (right.location.loc=LOC_CONSTANT) and
  224. (right.location.value=1) and
  225. not(cs_check_overflow in aktlocalswitches) then
  226. begin
  227. emit_reg(A_INC,opsize,left.location.register);
  228. end
  229. else
  230. if (op=A_SUB) and
  231. (right.location.loc=LOC_CONSTANT) and
  232. (right.location.value=1) and
  233. not(cs_check_overflow in aktlocalswitches) then
  234. begin
  235. emit_reg(A_DEC,opsize,left.location.register);
  236. end
  237. else
  238. if (op=A_IMUL) and
  239. (right.location.loc=LOC_CONSTANT) and
  240. (ispowerof2(right.location.value,power)) and
  241. not(cs_check_overflow in aktlocalswitches) then
  242. begin
  243. emit_const_reg(A_SHL,opsize,power,left.location.register);
  244. end
  245. else
  246. begin
  247. if extra_not then
  248. begin
  249. rg.getexplicitregisterint(exprasmlist,NR_EDI);
  250. r.enum:=R_INTREGISTER;
  251. r.number:=NR_EDI;
  252. cg.a_load_loc_reg(exprasmlist,right.location,r);
  253. emit_reg(A_NOT,S_L,r);
  254. emit_reg_reg(A_AND,S_L,r,left.location.register);
  255. rg.ungetregisterint(exprasmlist,r);
  256. end
  257. else
  258. begin
  259. emit_op_right_left(op,opsize);
  260. end;
  261. end;
  262. end;
  263. end;
  264. { only in case of overflow operations }
  265. { produce overflow code }
  266. { we must put it here directly, because sign of operation }
  267. { is in unsigned VAR!! }
  268. if mboverflow then
  269. begin
  270. if cs_check_overflow in aktlocalswitches then
  271. begin
  272. objectlibrary.getlabel(hl4);
  273. if unsigned then
  274. emitjmp(C_NB,hl4)
  275. else
  276. emitjmp(C_NO,hl4);
  277. cg.a_call_name(exprasmlist,'FPC_OVERFLOW');
  278. cg.a_label(exprasmlist,hl4);
  279. end;
  280. end;
  281. end;
  282. {*****************************************************************************
  283. Addstring
  284. *****************************************************************************}
  285. { note: if you implemented an fpc_shortstr_concat similar to the }
  286. { one in i386.inc, you have to override first_addstring like in }
  287. { ti386addnode.first_string and implement the shortstring concat }
  288. { manually! The generic routine is different from the i386 one (JM) }
  289. function ti386addnode.first_addstring : tnode;
  290. begin
  291. { special cases for shortstrings, handled in pass_2 (JM) }
  292. { can't handle fpc_shortstr_compare with compilerproc either because it }
  293. { returns its results in the flags instead of in eax }
  294. if (((nodetype = addn) and
  295. is_shortstring(resulttype.def)) or
  296. ((nodetype in [ltn,lten,gtn,gten,equaln,unequaln]) and
  297. not(((left.nodetype=stringconstn) and (str_length(left)=0)) or
  298. ((right.nodetype=stringconstn) and (str_length(right)=0))) and
  299. is_shortstring(left.resulttype.def))) then
  300. begin
  301. if nodetype = addn then
  302. location_reset(location,LOC_CREFERENCE,def_cgsize(resulttype.def))
  303. else
  304. location_reset(location,LOC_FLAGS,OS_NO);
  305. calcregisters(self,0,0,0);
  306. result := nil;
  307. exit;
  308. end;
  309. { otherwise, use the generic code }
  310. result := inherited first_addstring;
  311. end;
  312. procedure ti386addnode.second_addstring;
  313. var
  314. href : treference;
  315. cmpop : boolean;
  316. pushed : Tpushedsavedint;
  317. regstopush : Tsupregset;
  318. begin
  319. { string operations are not commutative }
  320. if nf_swaped in flags then
  321. swapleftright;
  322. case tstringdef(left.resulttype.def).string_typ of
  323. st_shortstring:
  324. begin
  325. case nodetype of
  326. addn:
  327. begin
  328. cmpop:=false;
  329. secondpass(left);
  330. { if str_concat is set in expr
  331. s:=s+ ... no need to create a temp string (PM) }
  332. { the tempstring can also come from a typeconversion }
  333. { or a function result, so simply check for a }
  334. { temp of 256 bytes(JM) }
  335. if not(tg.istemp(left.location.reference) and
  336. (tg.SizeOfTemp(exprasmlist,left.location.reference) = 256)) and
  337. not(nf_use_strconcat in flags) then
  338. begin
  339. tg.GetTemp(exprasmlist,256,tt_normal,href);
  340. cg.g_copyshortstring(exprasmlist,left.location.reference,href,255,true,false);
  341. { location is released by copyshortstring }
  342. location_freetemp(exprasmlist,left.location);
  343. location_reset(left.location,LOC_CREFERENCE,def_cgsize(resulttype.def));
  344. left.location.reference:=href;
  345. end;
  346. secondpass(right);
  347. { on the right we do not need the register anymore too }
  348. { Instead of releasing them already, simply do not }
  349. { push them (so the release is in the right place, }
  350. { because emitpushreferenceaddr doesn't need extra }
  351. { registers) (JM) }
  352. regstopush := all_intregisters;
  353. remove_non_regvars_from_loc(right.location,regstopush);
  354. rg.saveusedintregisters(exprasmlist,pushed,regstopush);
  355. { push the maximum possible length of the result }
  356. cg.a_paramaddr_ref(exprasmlist,left.location.reference,paramanager.getintparaloc(2));
  357. { the optimizer can more easily put the }
  358. { deallocations in the right place if it happens }
  359. { too early than when it happens too late (if }
  360. { the pushref needs a "lea (..),edi; push edi") }
  361. location_release(exprasmlist,right.location);
  362. cg.a_paramaddr_ref(exprasmlist,right.location.reference,paramanager.getintparaloc(1));
  363. rg.saveintregvars(exprasmlist,regstopush);
  364. cg.a_call_name(exprasmlist,'FPC_SHORTSTR_CONCAT');
  365. tg.ungetiftemp(exprasmlist,right.location.reference);
  366. cg.g_maybe_loadself(exprasmlist);
  367. rg.restoreusedintregisters(exprasmlist,pushed);
  368. location_copy(location,left.location);
  369. end;
  370. ltn,lten,gtn,gten,equaln,unequaln :
  371. begin
  372. cmpop := true;
  373. rg.saveusedintregisters(exprasmlist,pushed,all_intregisters);
  374. secondpass(left);
  375. location_release(exprasmlist,left.location);
  376. cg.a_paramaddr_ref(exprasmlist,left.location.reference,paramanager.getintparaloc(2));
  377. secondpass(right);
  378. location_release(exprasmlist,right.location);
  379. cg.a_paramaddr_ref(exprasmlist,right.location.reference,paramanager.getintparaloc(1));
  380. rg.saveintregvars(exprasmlist,all_intregisters);
  381. cg.a_call_name(exprasmlist,'FPC_SHORTSTR_COMPARE');
  382. cg.g_maybe_loadself(exprasmlist);
  383. rg.restoreusedintregisters(exprasmlist,pushed);
  384. location_freetemp(exprasmlist,left.location);
  385. location_freetemp(exprasmlist,right.location);
  386. end;
  387. end;
  388. set_result_location(cmpop,true);
  389. end;
  390. else
  391. { rest should be handled in first pass (JM) }
  392. internalerror(200108303);
  393. end;
  394. end;
  395. {*****************************************************************************
  396. AddBoolean
  397. *****************************************************************************}
  398. procedure ti386addnode.second_addboolean;
  399. var
  400. op : TAsmOp;
  401. opsize : TOpsize;
  402. cmpop,
  403. isjump : boolean;
  404. otl,ofl : tasmlabel;
  405. pushedregs : tmaybesave;
  406. begin
  407. { calculate the operator which is more difficult }
  408. firstcomplex(self);
  409. cmpop:=false;
  410. if (torddef(left.resulttype.def).typ=bool8bit) or
  411. (torddef(right.resulttype.def).typ=bool8bit) then
  412. opsize:=S_B
  413. else
  414. if (torddef(left.resulttype.def).typ=bool16bit) or
  415. (torddef(right.resulttype.def).typ=bool16bit) then
  416. opsize:=S_W
  417. else
  418. opsize:=S_L;
  419. if (cs_full_boolean_eval in aktlocalswitches) or
  420. (nodetype in [unequaln,ltn,lten,gtn,gten,equaln,xorn]) then
  421. begin
  422. if left.nodetype in [ordconstn,realconstn] then
  423. swapleftright;
  424. isjump:=(left.location.loc=LOC_JUMP);
  425. if isjump then
  426. begin
  427. otl:=truelabel;
  428. objectlibrary.getlabel(truelabel);
  429. ofl:=falselabel;
  430. objectlibrary.getlabel(falselabel);
  431. end;
  432. secondpass(left);
  433. if left.location.loc in [LOC_FLAGS,LOC_JUMP] then
  434. location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],false);
  435. if isjump then
  436. begin
  437. truelabel:=otl;
  438. falselabel:=ofl;
  439. end;
  440. maybe_save(exprasmlist,right.registers32,left.location,pushedregs);
  441. isjump:=(right.location.loc=LOC_JUMP);
  442. if isjump then
  443. begin
  444. otl:=truelabel;
  445. objectlibrary.getlabel(truelabel);
  446. ofl:=falselabel;
  447. objectlibrary.getlabel(falselabel);
  448. end;
  449. secondpass(right);
  450. maybe_restore(exprasmlist,left.location,pushedregs);
  451. if right.location.loc in [LOC_FLAGS,LOC_JUMP] then
  452. location_force_reg(exprasmlist,right.location,opsize_2_cgsize[opsize],false);
  453. if isjump then
  454. begin
  455. truelabel:=otl;
  456. falselabel:=ofl;
  457. end;
  458. { left must be a register }
  459. left_must_be_reg(opsize,false);
  460. { compare the }
  461. case nodetype of
  462. ltn,lten,gtn,gten,
  463. equaln,unequaln :
  464. begin
  465. op:=A_CMP;
  466. cmpop:=true;
  467. end;
  468. xorn :
  469. op:=A_XOR;
  470. orn :
  471. op:=A_OR;
  472. andn :
  473. op:=A_AND;
  474. else
  475. internalerror(200203247);
  476. end;
  477. emit_op_right_left(op,opsize);
  478. location_freetemp(exprasmlist,right.location);
  479. location_release(exprasmlist,right.location);
  480. if cmpop then
  481. begin
  482. location_freetemp(exprasmlist,left.location);
  483. location_release(exprasmlist,left.location);
  484. end;
  485. set_result_location(cmpop,true);
  486. end
  487. else
  488. begin
  489. case nodetype of
  490. andn,
  491. orn :
  492. begin
  493. location_reset(location,LOC_JUMP,OS_NO);
  494. case nodetype of
  495. andn :
  496. begin
  497. otl:=truelabel;
  498. objectlibrary.getlabel(truelabel);
  499. secondpass(left);
  500. maketojumpbool(exprasmlist,left,lr_load_regvars);
  501. cg.a_label(exprasmlist,truelabel);
  502. truelabel:=otl;
  503. end;
  504. orn :
  505. begin
  506. ofl:=falselabel;
  507. objectlibrary.getlabel(falselabel);
  508. secondpass(left);
  509. maketojumpbool(exprasmlist,left,lr_load_regvars);
  510. cg.a_label(exprasmlist,falselabel);
  511. falselabel:=ofl;
  512. end;
  513. else
  514. CGMessage(type_e_mismatch);
  515. end;
  516. secondpass(right);
  517. maketojumpbool(exprasmlist,right,lr_load_regvars);
  518. end;
  519. else
  520. CGMessage(type_e_mismatch);
  521. end;
  522. end;
  523. end;
  524. {*****************************************************************************
  525. AddFloat
  526. *****************************************************************************}
  527. procedure ti386addnode.second_addfloat;
  528. var
  529. op : TAsmOp;
  530. resflags : tresflags;
  531. pushedfpu,
  532. cmpop : boolean;
  533. r,r2:Tregister;
  534. begin
  535. pass_left_and_right(pushedfpu);
  536. cmpop:=false;
  537. case nodetype of
  538. addn :
  539. op:=A_FADDP;
  540. muln :
  541. op:=A_FMULP;
  542. subn :
  543. op:=A_FSUBP;
  544. slashn :
  545. op:=A_FDIVP;
  546. ltn,lten,gtn,gten,
  547. equaln,unequaln :
  548. begin
  549. op:=A_FCOMPP;
  550. cmpop:=true;
  551. end;
  552. else
  553. CGMessage(type_e_mismatch);
  554. end;
  555. if (right.location.loc<>LOC_FPUREGISTER) then
  556. begin
  557. r.enum:=R_ST;
  558. cg.a_loadfpu_loc_reg(exprasmlist,right.location,r);
  559. if (right.location.loc <> LOC_CFPUREGISTER) and
  560. pushedfpu then
  561. location_freetemp(exprasmlist,left.location);
  562. if (left.location.loc<>LOC_FPUREGISTER) then
  563. begin
  564. cg.a_loadfpu_loc_reg(exprasmlist,left.location,r);
  565. if (left.location.loc <> LOC_CFPUREGISTER) and
  566. pushedfpu then
  567. location_freetemp(exprasmlist,left.location);
  568. end
  569. else
  570. begin
  571. { left was on the stack => swap }
  572. toggleflag(nf_swaped);
  573. end;
  574. { releases the right reference }
  575. location_release(exprasmlist,right.location);
  576. end
  577. { the nominator in st0 }
  578. else if (left.location.loc<>LOC_FPUREGISTER) then
  579. begin
  580. r.enum:=R_ST;
  581. cg.a_loadfpu_loc_reg(exprasmlist,left.location,r);
  582. if (left.location.loc <> LOC_CFPUREGISTER) and
  583. pushedfpu then
  584. location_freetemp(exprasmlist,left.location);
  585. end
  586. else
  587. begin
  588. { fpu operands are always in the wrong order on the stack }
  589. toggleflag(nf_swaped);
  590. end;
  591. { releases the left reference }
  592. if (left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  593. location_release(exprasmlist,left.location);
  594. { if we swaped the tree nodes, then use the reverse operator }
  595. if nf_swaped in flags then
  596. begin
  597. if (nodetype=slashn) then
  598. op:=A_FDIVRP
  599. else if (nodetype=subn) then
  600. op:=A_FSUBRP;
  601. end;
  602. { to avoid the pentium bug
  603. if (op=FDIVP) and (opt_processors=pentium) then
  604. cg.a_call_name(exprasmlist,'EMUL_FDIVP')
  605. else
  606. }
  607. { the Intel assemblers want operands }
  608. if op<>A_FCOMPP then
  609. begin
  610. r.enum:=R_ST;
  611. r2.enum:=R_ST1;
  612. emit_reg_reg(op,S_NO,r,r2);
  613. dec(trgcpu(rg).fpuvaroffset);
  614. end
  615. else
  616. begin
  617. emit_none(op,S_NO);
  618. dec(trgcpu(rg).fpuvaroffset,2);
  619. end;
  620. { on comparison load flags }
  621. if cmpop then
  622. begin
  623. if not(RS_EAX in rg.unusedregsint) then
  624. begin
  625. rg.getexplicitregisterint(exprasmlist,NR_EDI);
  626. r.enum:=R_EAX;
  627. r2.enum:=R_EDI;
  628. emit_reg_reg(A_MOV,S_L,r,r2);
  629. end;
  630. r.enum:=R_AX;
  631. emit_reg(A_FNSTSW,S_NO,r);
  632. emit_none(A_SAHF,S_NO);
  633. if not(RS_EAX in rg.unusedregsint) then
  634. begin
  635. r.enum:=R_EAX;
  636. r2.enum:=R_EDI;
  637. emit_reg_reg(A_MOV,S_L,r2,r);
  638. rg.ungetregisterint(exprasmlist,r2);
  639. end;
  640. if nf_swaped in flags then
  641. begin
  642. case nodetype of
  643. equaln : resflags:=F_E;
  644. unequaln : resflags:=F_NE;
  645. ltn : resflags:=F_A;
  646. lten : resflags:=F_AE;
  647. gtn : resflags:=F_B;
  648. gten : resflags:=F_BE;
  649. end;
  650. end
  651. else
  652. begin
  653. case nodetype of
  654. equaln : resflags:=F_E;
  655. unequaln : resflags:=F_NE;
  656. ltn : resflags:=F_B;
  657. lten : resflags:=F_BE;
  658. gtn : resflags:=F_A;
  659. gten : resflags:=F_AE;
  660. end;
  661. end;
  662. location_reset(location,LOC_FLAGS,OS_NO);
  663. location.resflags:=resflags;
  664. end
  665. else
  666. begin
  667. location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
  668. location.register.enum:=R_ST;
  669. end;
  670. end;
  671. {*****************************************************************************
  672. AddSmallSet
  673. *****************************************************************************}
  674. procedure ti386addnode.second_addsmallset;
  675. var
  676. opsize : TOpSize;
  677. op : TAsmOp;
  678. cmpop,
  679. pushedfpu,
  680. extra_not,
  681. noswap : boolean;
  682. begin
  683. pass_left_and_right(pushedfpu);
  684. { when a setdef is passed, it has to be a smallset }
  685. if ((left.resulttype.def.deftype=setdef) and
  686. (tsetdef(left.resulttype.def).settype<>smallset)) or
  687. ((right.resulttype.def.deftype=setdef) and
  688. (tsetdef(right.resulttype.def).settype<>smallset)) then
  689. internalerror(200203301);
  690. cmpop:=false;
  691. noswap:=false;
  692. extra_not:=false;
  693. opsize:=S_L;
  694. case nodetype of
  695. addn :
  696. begin
  697. { this is a really ugly hack!!!!!!!!!! }
  698. { this could be done later using EDI }
  699. { as it is done for subn }
  700. { instead of two registers!!!! }
  701. { adding elements is not commutative }
  702. if (nf_swaped in flags) and (left.nodetype=setelementn) then
  703. swapleftright;
  704. { are we adding set elements ? }
  705. if right.nodetype=setelementn then
  706. begin
  707. { no range support for smallsets! }
  708. if assigned(tsetelementnode(right).right) then
  709. internalerror(43244);
  710. { bts requires both elements to be registers }
  711. location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],false);
  712. location_force_reg(exprasmlist,right.location,opsize_2_cgsize[opsize],true);
  713. op:=A_BTS;
  714. noswap:=true;
  715. end
  716. else
  717. op:=A_OR;
  718. end;
  719. symdifn :
  720. op:=A_XOR;
  721. muln :
  722. op:=A_AND;
  723. subn :
  724. begin
  725. op:=A_AND;
  726. if (not(nf_swaped in flags)) and
  727. (right.location.loc=LOC_CONSTANT) then
  728. right.location.value := not(right.location.value)
  729. else if (nf_swaped in flags) and
  730. (left.location.loc=LOC_CONSTANT) then
  731. left.location.value := not(left.location.value)
  732. else
  733. extra_not:=true;
  734. end;
  735. equaln,
  736. unequaln :
  737. begin
  738. op:=A_CMP;
  739. cmpop:=true;
  740. end;
  741. lten,gten:
  742. begin
  743. If (not(nf_swaped in flags) and
  744. (nodetype = lten)) or
  745. ((nf_swaped in flags) and
  746. (nodetype = gten)) then
  747. swapleftright;
  748. location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],true);
  749. emit_op_right_left(A_AND,opsize);
  750. op:=A_CMP;
  751. cmpop:=true;
  752. { warning: ugly hack, we need a JE so change the node to equaln }
  753. nodetype:=equaln;
  754. end;
  755. xorn :
  756. op:=A_XOR;
  757. orn :
  758. op:=A_OR;
  759. andn :
  760. op:=A_AND;
  761. else
  762. begin
  763. { no < or > support for sets }
  764. CGMessage(type_e_mismatch);
  765. end;
  766. end;
  767. { left must be a register }
  768. left_must_be_reg(opsize,noswap);
  769. emit_generic_code(op,opsize,true,extra_not,false);
  770. location_freetemp(exprasmlist,right.location);
  771. location_release(exprasmlist,right.location);
  772. if cmpop then
  773. begin
  774. location_freetemp(exprasmlist,left.location);
  775. location_release(exprasmlist,left.location);
  776. end;
  777. set_result_location(cmpop,true);
  778. end;
  779. {*****************************************************************************
  780. Add64bit
  781. *****************************************************************************}
  782. procedure ti386addnode.second_add64bit;
  783. var
  784. op : TOpCG;
  785. op1,op2 : TAsmOp;
  786. opsize : TOpSize;
  787. hregister,
  788. hregister2 : tregister;
  789. href : treference;
  790. hl4 : tasmlabel;
  791. pushedfpu,
  792. mboverflow,
  793. cmpop,
  794. unsigned : boolean;
  795. r:Tregister;
  796. procedure firstjmp64bitcmp;
  797. var
  798. oldnodetype : tnodetype;
  799. begin
  800. load_all_regvars(exprasmlist);
  801. { the jump the sequence is a little bit hairy }
  802. case nodetype of
  803. ltn,gtn:
  804. begin
  805. emitjmp(flags_to_cond(getresflags(unsigned)),truelabel);
  806. { cheat a little bit for the negative test }
  807. toggleflag(nf_swaped);
  808. emitjmp(flags_to_cond(getresflags(unsigned)),falselabel);
  809. toggleflag(nf_swaped);
  810. end;
  811. lten,gten:
  812. begin
  813. oldnodetype:=nodetype;
  814. if nodetype=lten then
  815. nodetype:=ltn
  816. else
  817. nodetype:=gtn;
  818. emitjmp(flags_to_cond(getresflags(unsigned)),truelabel);
  819. { cheat for the negative test }
  820. if nodetype=ltn then
  821. nodetype:=gtn
  822. else
  823. nodetype:=ltn;
  824. emitjmp(flags_to_cond(getresflags(unsigned)),falselabel);
  825. nodetype:=oldnodetype;
  826. end;
  827. equaln:
  828. emitjmp(C_NE,falselabel);
  829. unequaln:
  830. emitjmp(C_NE,truelabel);
  831. end;
  832. end;
  833. procedure secondjmp64bitcmp;
  834. begin
  835. { the jump the sequence is a little bit hairy }
  836. case nodetype of
  837. ltn,gtn,lten,gten:
  838. begin
  839. { the comparisaion of the low dword have to be }
  840. { always unsigned! }
  841. emitjmp(flags_to_cond(getresflags(true)),truelabel);
  842. cg.a_jmp_always(exprasmlist,falselabel);
  843. end;
  844. equaln:
  845. begin
  846. emitjmp(C_NE,falselabel);
  847. cg.a_jmp_always(exprasmlist,truelabel);
  848. end;
  849. unequaln:
  850. begin
  851. emitjmp(C_NE,truelabel);
  852. cg.a_jmp_always(exprasmlist,falselabel);
  853. end;
  854. end;
  855. end;
  856. begin
  857. firstcomplex(self);
  858. pass_left_and_right(pushedfpu);
  859. op1:=A_NONE;
  860. op2:=A_NONE;
  861. mboverflow:=false;
  862. cmpop:=false;
  863. opsize:=S_L;
  864. unsigned:=((left.resulttype.def.deftype=orddef) and
  865. (torddef(left.resulttype.def).typ=u64bit)) or
  866. ((right.resulttype.def.deftype=orddef) and
  867. (torddef(right.resulttype.def).typ=u64bit));
  868. case nodetype of
  869. addn :
  870. begin
  871. op:=OP_ADD;
  872. mboverflow:=true;
  873. end;
  874. subn :
  875. begin
  876. op:=OP_SUB;
  877. op1:=A_SUB;
  878. op2:=A_SBB;
  879. mboverflow:=true;
  880. end;
  881. ltn,lten,
  882. gtn,gten,
  883. equaln,unequaln:
  884. begin
  885. op:=OP_NONE;
  886. cmpop:=true;
  887. end;
  888. xorn:
  889. op:=OP_XOR;
  890. orn:
  891. op:=OP_OR;
  892. andn:
  893. op:=OP_AND;
  894. muln:
  895. begin
  896. { should be handled in pass_1 (JM) }
  897. internalerror(200109051);
  898. end;
  899. else
  900. CGMessage(type_e_mismatch);
  901. end;
  902. { left and right no register? }
  903. { then one must be demanded }
  904. if (left.location.loc<>LOC_REGISTER) then
  905. begin
  906. if (right.location.loc<>LOC_REGISTER) then
  907. begin
  908. { we can reuse a CREGISTER for comparison }
  909. if not((left.location.loc=LOC_CREGISTER) and cmpop) then
  910. begin
  911. if (left.location.loc<>LOC_CREGISTER) then
  912. begin
  913. location_freetemp(exprasmlist,left.location);
  914. location_release(exprasmlist,left.location);
  915. end;
  916. hregister:=rg.getregisterint(exprasmlist,OS_INT);
  917. hregister2:=rg.getregisterint(exprasmlist,OS_INT);
  918. cg64.a_load64_loc_reg(exprasmlist,left.location,joinreg64(hregister,hregister2));
  919. location_reset(left.location,LOC_REGISTER,OS_64);
  920. left.location.registerlow:=hregister;
  921. left.location.registerhigh:=hregister2;
  922. end;
  923. end
  924. else
  925. begin
  926. location_swap(left.location,right.location);
  927. toggleflag(nf_swaped);
  928. end;
  929. end;
  930. { at this point, left.location.loc should be LOC_REGISTER }
  931. if right.location.loc=LOC_REGISTER then
  932. begin
  933. { when swapped another result register }
  934. if (nodetype=subn) and (nf_swaped in flags) then
  935. begin
  936. cg64.a_op64_reg_reg(exprasmlist,op,
  937. left.location.register64,
  938. right.location.register64);
  939. location_swap(left.location,right.location);
  940. toggleflag(nf_swaped);
  941. end
  942. else if cmpop then
  943. begin
  944. emit_reg_reg(A_CMP,S_L,right.location.registerhigh,left.location.registerhigh);
  945. firstjmp64bitcmp;
  946. emit_reg_reg(A_CMP,S_L,right.location.registerlow,left.location.registerlow);
  947. secondjmp64bitcmp;
  948. end
  949. else
  950. begin
  951. cg64.a_op64_reg_reg(exprasmlist,op,
  952. right.location.register64,
  953. left.location.register64);
  954. end;
  955. location_release(exprasmlist,right.location);
  956. end
  957. else
  958. begin
  959. { right.location<>LOC_REGISTER }
  960. if (nodetype=subn) and (nf_swaped in flags) then
  961. begin
  962. rg.getexplicitregisterint(exprasmlist,NR_EDI);
  963. r.enum:=R_INTREGISTER;
  964. r.number:=NR_EDI;
  965. cg64.a_load64low_loc_reg(exprasmlist,right.location,r);
  966. emit_reg_reg(op1,opsize,left.location.registerlow,r);
  967. emit_reg_reg(A_MOV,opsize,r,left.location.registerlow);
  968. cg64.a_load64high_loc_reg(exprasmlist,right.location,r);
  969. { the carry flag is still ok }
  970. emit_reg_reg(op2,opsize,left.location.registerhigh,r);
  971. emit_reg_reg(A_MOV,opsize,r,left.location.registerhigh);
  972. rg.ungetregisterint(exprasmlist,r);
  973. if right.location.loc<>LOC_CREGISTER then
  974. begin
  975. location_freetemp(exprasmlist,right.location);
  976. location_release(exprasmlist,right.location);
  977. end;
  978. end
  979. else if cmpop then
  980. begin
  981. case right.location.loc of
  982. LOC_CREGISTER :
  983. begin
  984. emit_reg_reg(A_CMP,S_L,right.location.registerhigh,left.location.registerhigh);
  985. firstjmp64bitcmp;
  986. emit_reg_reg(A_CMP,S_L,right.location.registerlow,left.location.registerlow);
  987. secondjmp64bitcmp;
  988. end;
  989. LOC_CREFERENCE,
  990. LOC_REFERENCE :
  991. begin
  992. href:=right.location.reference;
  993. inc(href.offset,4);
  994. emit_ref_reg(A_CMP,S_L,href,left.location.registerhigh);
  995. firstjmp64bitcmp;
  996. emit_ref_reg(A_CMP,S_L,right.location.reference,left.location.registerlow);
  997. secondjmp64bitcmp;
  998. cg.a_jmp_always(exprasmlist,falselabel);
  999. location_freetemp(exprasmlist,right.location);
  1000. location_release(exprasmlist,right.location);
  1001. end;
  1002. LOC_CONSTANT :
  1003. begin
  1004. exprasmlist.concat(taicpu.op_const_reg(A_CMP,S_L,hi(right.location.valueqword),left.location.registerhigh));
  1005. firstjmp64bitcmp;
  1006. exprasmlist.concat(taicpu.op_const_reg(A_CMP,S_L,lo(right.location.valueqword),left.location.registerlow));
  1007. secondjmp64bitcmp;
  1008. end;
  1009. else
  1010. internalerror(200203282);
  1011. end;
  1012. end
  1013. else
  1014. begin
  1015. cg64.a_op64_loc_reg(exprasmlist,op,right.location,
  1016. left.location.register64);
  1017. if (right.location.loc<>LOC_CREGISTER) then
  1018. begin
  1019. location_freetemp(exprasmlist,right.location);
  1020. location_release(exprasmlist,right.location);
  1021. end;
  1022. end;
  1023. end;
  1024. if (left.location.loc<>LOC_CREGISTER) and cmpop then
  1025. begin
  1026. location_freetemp(exprasmlist,left.location);
  1027. location_release(exprasmlist,left.location);
  1028. end;
  1029. { only in case of overflow operations }
  1030. { produce overflow code }
  1031. { we must put it here directly, because sign of operation }
  1032. { is in unsigned VAR!! }
  1033. if mboverflow then
  1034. begin
  1035. if cs_check_overflow in aktlocalswitches then
  1036. begin
  1037. objectlibrary.getlabel(hl4);
  1038. if unsigned then
  1039. emitjmp(C_NB,hl4)
  1040. else
  1041. emitjmp(C_NO,hl4);
  1042. cg.a_call_name(exprasmlist,'FPC_OVERFLOW');
  1043. cg.a_label(exprasmlist,hl4);
  1044. end;
  1045. end;
  1046. { we have LOC_JUMP as result }
  1047. if cmpop then
  1048. location_reset(location,LOC_JUMP,OS_NO)
  1049. else
  1050. location_copy(location,left.location);
  1051. end;
  1052. {*****************************************************************************
  1053. AddMMX
  1054. *****************************************************************************}
  1055. {$ifdef SUPPORT_MMX}
  1056. procedure ti386addnode.second_addmmx;
  1057. var
  1058. op : TAsmOp;
  1059. pushedfpu,
  1060. cmpop : boolean;
  1061. mmxbase : tmmxtype;
  1062. r,hregister : tregister;
  1063. begin
  1064. pass_left_and_right(pushedfpu);
  1065. cmpop:=false;
  1066. mmxbase:=mmx_type(left.resulttype.def);
  1067. case nodetype of
  1068. addn :
  1069. begin
  1070. if (cs_mmx_saturation in aktlocalswitches) then
  1071. begin
  1072. case mmxbase of
  1073. mmxs8bit:
  1074. op:=A_PADDSB;
  1075. mmxu8bit:
  1076. op:=A_PADDUSB;
  1077. mmxs16bit,mmxfixed16:
  1078. op:=A_PADDSB;
  1079. mmxu16bit:
  1080. op:=A_PADDUSW;
  1081. end;
  1082. end
  1083. else
  1084. begin
  1085. case mmxbase of
  1086. mmxs8bit,mmxu8bit:
  1087. op:=A_PADDB;
  1088. mmxs16bit,mmxu16bit,mmxfixed16:
  1089. op:=A_PADDW;
  1090. mmxs32bit,mmxu32bit:
  1091. op:=A_PADDD;
  1092. end;
  1093. end;
  1094. end;
  1095. muln :
  1096. begin
  1097. case mmxbase of
  1098. mmxs16bit,mmxu16bit:
  1099. op:=A_PMULLW;
  1100. mmxfixed16:
  1101. op:=A_PMULHW;
  1102. end;
  1103. end;
  1104. subn :
  1105. begin
  1106. if (cs_mmx_saturation in aktlocalswitches) then
  1107. begin
  1108. case mmxbase of
  1109. mmxs8bit:
  1110. op:=A_PSUBSB;
  1111. mmxu8bit:
  1112. op:=A_PSUBUSB;
  1113. mmxs16bit,mmxfixed16:
  1114. op:=A_PSUBSB;
  1115. mmxu16bit:
  1116. op:=A_PSUBUSW;
  1117. end;
  1118. end
  1119. else
  1120. begin
  1121. case mmxbase of
  1122. mmxs8bit,mmxu8bit:
  1123. op:=A_PSUBB;
  1124. mmxs16bit,mmxu16bit,mmxfixed16:
  1125. op:=A_PSUBW;
  1126. mmxs32bit,mmxu32bit:
  1127. op:=A_PSUBD;
  1128. end;
  1129. end;
  1130. end;
  1131. xorn:
  1132. op:=A_PXOR;
  1133. orn:
  1134. op:=A_POR;
  1135. andn:
  1136. op:=A_PAND;
  1137. else
  1138. CGMessage(type_e_mismatch);
  1139. end;
  1140. { left and right no register? }
  1141. { then one must be demanded }
  1142. if (left.location.loc<>LOC_MMXREGISTER) then
  1143. begin
  1144. if (right.location.loc=LOC_MMXREGISTER) then
  1145. begin
  1146. location_swap(left.location,right.location);
  1147. toggleflag(nf_swaped);
  1148. end
  1149. else
  1150. begin
  1151. { register variable ? }
  1152. if (left.location.loc=LOC_CMMXREGISTER) then
  1153. begin
  1154. hregister:=rg.getregistermm(exprasmlist);
  1155. emit_reg_reg(A_MOVQ,S_NO,left.location.register,hregister);
  1156. end
  1157. else
  1158. begin
  1159. if not(left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  1160. internalerror(200203245);
  1161. location_release(exprasmlist,left.location);
  1162. hregister:=rg.getregistermm(exprasmlist);
  1163. emit_ref_reg(A_MOVQ,S_NO,left.location.reference,hregister);
  1164. end;
  1165. location_reset(left.location,LOC_MMXREGISTER,OS_NO);
  1166. left.location.register:=hregister;
  1167. end;
  1168. end;
  1169. { at this point, left.location.loc should be LOC_MMXREGISTER }
  1170. if right.location.loc<>LOC_MMXREGISTER then
  1171. begin
  1172. if (nodetype=subn) and (nf_swaped in flags) then
  1173. begin
  1174. r.enum:=R_MM7;
  1175. if right.location.loc=LOC_CMMXREGISTER then
  1176. begin
  1177. emit_reg_reg(A_MOVQ,S_NO,right.location.register,r);
  1178. emit_reg_reg(op,S_NO,left.location.register,r);
  1179. emit_reg_reg(A_MOVQ,S_NO,r,left.location.register);
  1180. end
  1181. else
  1182. begin
  1183. if not(left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  1184. internalerror(200203247);
  1185. emit_ref_reg(A_MOVQ,S_NO,right.location.reference,r);
  1186. emit_reg_reg(op,S_NO,left.location.register,r);
  1187. emit_reg_reg(A_MOVQ,S_NO,r,left.location.register);
  1188. location_release(exprasmlist,right.location);
  1189. end;
  1190. end
  1191. else
  1192. begin
  1193. if (right.location.loc=LOC_CMMXREGISTER) then
  1194. begin
  1195. emit_reg_reg(op,S_NO,right.location.register,left.location.register);
  1196. end
  1197. else
  1198. begin
  1199. if not(right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  1200. internalerror(200203246);
  1201. emit_ref_reg(op,S_NO,right.location.reference,left.location.register);
  1202. location_release(exprasmlist,right.location);
  1203. end;
  1204. end;
  1205. end
  1206. else
  1207. begin
  1208. { right.location=LOC_MMXREGISTER }
  1209. if (nodetype=subn) and (nf_swaped in flags) then
  1210. begin
  1211. emit_reg_reg(op,S_NO,left.location.register,right.location.register);
  1212. location_swap(left.location,right.location);
  1213. toggleflag(nf_swaped);
  1214. end
  1215. else
  1216. begin
  1217. emit_reg_reg(op,S_NO,right.location.register,left.location.register);
  1218. end;
  1219. end;
  1220. location_freetemp(exprasmlist,right.location);
  1221. location_release(exprasmlist,right.location);
  1222. if cmpop then
  1223. begin
  1224. location_freetemp(exprasmlist,left.location);
  1225. location_release(exprasmlist,left.location);
  1226. end;
  1227. set_result_location(cmpop,true);
  1228. end;
  1229. {$endif SUPPORT_MMX}
  1230. {*****************************************************************************
  1231. MUL
  1232. *****************************************************************************}
  1233. {$ifdef newra}
  1234. procedure ti386addnode.second_mul;
  1235. var r,r_eax:Tregister;
  1236. begin
  1237. {The location.register will be filled in later (JM)}
  1238. location_reset(location,LOC_REGISTER,OS_INT);
  1239. {Get a temp register and load the left value into it
  1240. and free the location.}
  1241. r:=rg.getregisterint(exprasmlist,OS_INT);
  1242. cg.a_load_loc_reg(exprasmlist,left.location,r);
  1243. location_release(exprasmlist,left.location);
  1244. {Allocate EAX.}
  1245. rg.getexplicitregisterint(exprasmlist,NR_EAX);
  1246. r_eax.enum:=R_INTREGISTER;
  1247. r_eax.number:=NR_EAX;
  1248. {Load the right value.}
  1249. cg.a_load_loc_reg(exprasmlist,right.location,r_eax);
  1250. location_release(exprasmlist,right.location);
  1251. {Also allocate EDX, since it is also modified by a mul (JM).}
  1252. rg.getexplicitregisterint(exprasmlist,NR_EDX);
  1253. emit_reg(A_MUL,S_L,r);
  1254. rg.ungetregisterint(exprasmlist,r);
  1255. {Free EDX}
  1256. r.enum:=R_INTREGISTER;
  1257. r.number:=NR_EDX;
  1258. rg.ungetregisterint(exprasmlist,r);
  1259. {Free EAX}
  1260. rg.ungetregisterint(exprasmlist,r_eax);
  1261. location.register:=rg.getregisterint(exprasmlist,OS_INT);
  1262. emit_reg_reg(A_MOV,S_L,r_eax,location.register);
  1263. location_freetemp(exprasmlist,left.location);
  1264. location_freetemp(exprasmlist,right.location);
  1265. end;
  1266. {$else}
  1267. procedure ti386addnode.second_mul;
  1268. var popeax,popedx:boolean;
  1269. regstopush:Tsupregset;
  1270. r:Tregister;
  1271. begin
  1272. popeax:=false;
  1273. popedx:=false;
  1274. { here you need to free the symbol first }
  1275. { left.location and right.location must }
  1276. { only be freed when they are really released, }
  1277. { because the optimizer NEEDS correct regalloc }
  1278. { info!!! (JM) }
  1279. { the location.register will be filled in later (JM) }
  1280. location_reset(location,LOC_REGISTER,OS_INT);
  1281. regstopush := all_intregisters;
  1282. remove_non_regvars_from_loc(right.location,regstopush);
  1283. remove_non_regvars_from_loc(left.location,regstopush);
  1284. { now, regstopush does NOT contain EAX and/or EDX if they are }
  1285. { used in either the left or the right location, excepts if }
  1286. {they are regvars. It DOES contain them if they are used in }
  1287. { another location (JM) }
  1288. r.enum:=R_INTREGISTER;
  1289. if not(RS_EAX in rg.unusedregsint) and
  1290. (RS_EAX in regstopush) then
  1291. begin
  1292. r.number:=NR_EAX;
  1293. emit_reg(A_PUSH,S_L,r);
  1294. popeax:=true;
  1295. end;
  1296. if not(RS_EDX in rg.unusedregsint) and
  1297. (RS_EDX in regstopush) then
  1298. begin
  1299. r.number:=NR_EDX;
  1300. emit_reg(A_PUSH,S_L,r);
  1301. popedx:=true;
  1302. end;
  1303. { left.location can be R_EAX !!! }
  1304. rg.getexplicitregisterint(exprasmlist,NR_EDI);
  1305. { load the left value }
  1306. r.number:=NR_EDI;
  1307. cg.a_load_loc_reg(exprasmlist,left.location,r);
  1308. location_release(exprasmlist,left.location);
  1309. { allocate EAX }
  1310. r.number:=NR_EAX;
  1311. if RS_EAX in rg.unusedregsint then
  1312. exprasmList.concat(tai_regalloc.Alloc(r));
  1313. { load he right value }
  1314. cg.a_load_loc_reg(exprasmlist,right.location,r);
  1315. location_release(exprasmlist,right.location);
  1316. { allocate EAX if it isn't yet allocated (JM) }
  1317. if (RS_EAX in rg.unusedregsint) then
  1318. exprasmlist.concat(tai_regalloc.Alloc(r));
  1319. { also allocate EDX, since it is also modified by }
  1320. { a mul (JM) }
  1321. r.number:=NR_EDX;
  1322. if RS_EDX in rg.unusedregsint then
  1323. exprasmlist.concat(tai_regalloc.Alloc(r));
  1324. r.number:=NR_EDI;
  1325. emit_reg(A_MUL,S_L,r);
  1326. rg.ungetregisterint(exprasmlist,r);
  1327. r.enum:=R_INTREGISTER;
  1328. r.number:=NR_EDX;
  1329. if RS_EDX in rg.unusedregsint then
  1330. exprasmlist.concat(tai_regalloc.DeAlloc(r));
  1331. r.number:=NR_EAX;
  1332. if RS_EAX in rg.unusedregsint then
  1333. exprasmlist.concat(tai_regalloc.DeAlloc(r));
  1334. location.register:=rg.getregisterint(exprasmlist,OS_INT);
  1335. r.number:=NR_EAX;
  1336. emit_reg_reg(A_MOV,S_L,r,location.register);
  1337. r.number:=NR_EDX;
  1338. if popedx then
  1339. emit_reg(A_POP,S_L,r);
  1340. r.number:=NR_EAX;
  1341. if popeax then
  1342. emit_reg(A_POP,S_L,r);
  1343. location_freetemp(exprasmlist,left.location);
  1344. location_freetemp(exprasmlist,right.location);
  1345. end;
  1346. {$endif}
  1347. {*****************************************************************************
  1348. pass_2
  1349. *****************************************************************************}
  1350. procedure ti386addnode.pass_2;
  1351. { is also being used for xor, and "mul", "sub, or and comparative }
  1352. { operators }
  1353. var
  1354. pushedfpu,
  1355. mboverflow,cmpop : boolean;
  1356. op : tasmop;
  1357. power : longint;
  1358. opsize : topsize;
  1359. { true, if unsigned types are compared }
  1360. unsigned : boolean;
  1361. { is_in_dest if the result is put directly into }
  1362. { the resulting refernce or varregister }
  1363. {is_in_dest : boolean;}
  1364. { true, if for sets subtractions the extra not should generated }
  1365. extra_not : boolean;
  1366. begin
  1367. { to make it more readable, string and set (not smallset!) have their
  1368. own procedures }
  1369. case left.resulttype.def.deftype of
  1370. orddef :
  1371. begin
  1372. { handling boolean expressions }
  1373. if is_boolean(left.resulttype.def) and
  1374. is_boolean(right.resulttype.def) then
  1375. begin
  1376. second_addboolean;
  1377. exit;
  1378. end
  1379. { 64bit operations }
  1380. else if is_64bitint(left.resulttype.def) then
  1381. begin
  1382. second_add64bit;
  1383. exit;
  1384. end;
  1385. end;
  1386. stringdef :
  1387. begin
  1388. second_addstring;
  1389. exit;
  1390. end;
  1391. setdef :
  1392. begin
  1393. { normalsets are already handled in pass1 }
  1394. if (tsetdef(left.resulttype.def).settype<>smallset) then
  1395. internalerror(200109041);
  1396. second_addsmallset;
  1397. exit;
  1398. end;
  1399. arraydef :
  1400. begin
  1401. {$ifdef SUPPORT_MMX}
  1402. if is_mmx_able_array(left.resulttype.def) then
  1403. begin
  1404. second_addmmx;
  1405. exit;
  1406. end;
  1407. {$endif SUPPORT_MMX}
  1408. end;
  1409. floatdef :
  1410. begin
  1411. second_addfloat;
  1412. exit;
  1413. end;
  1414. end;
  1415. { defaults }
  1416. {is_in_dest:=false;}
  1417. extra_not:=false;
  1418. mboverflow:=false;
  1419. cmpop:=false;
  1420. unsigned:=not(is_signed(left.resulttype.def)) or
  1421. not(is_signed(right.resulttype.def));
  1422. opsize:=def_opsize(left.resulttype.def);
  1423. pass_left_and_right(pushedfpu);
  1424. if (left.resulttype.def.deftype=pointerdef) or
  1425. (right.resulttype.def.deftype=pointerdef) or
  1426. (is_class_or_interface(right.resulttype.def) and is_class_or_interface(left.resulttype.def)) or
  1427. (left.resulttype.def.deftype=classrefdef) or
  1428. (left.resulttype.def.deftype=procvardef) or
  1429. ((left.resulttype.def.deftype=enumdef) and
  1430. (left.resulttype.def.size=4)) or
  1431. ((left.resulttype.def.deftype=orddef) and
  1432. (torddef(left.resulttype.def).typ in [s32bit,u32bit])) or
  1433. ((right.resulttype.def.deftype=orddef) and
  1434. (torddef(right.resulttype.def).typ in [s32bit,u32bit])) then
  1435. begin
  1436. case nodetype of
  1437. addn :
  1438. begin
  1439. op:=A_ADD;
  1440. mboverflow:=true;
  1441. end;
  1442. muln :
  1443. begin
  1444. if unsigned then
  1445. op:=A_MUL
  1446. else
  1447. op:=A_IMUL;
  1448. mboverflow:=true;
  1449. end;
  1450. subn :
  1451. begin
  1452. op:=A_SUB;
  1453. mboverflow:=true;
  1454. end;
  1455. ltn,lten,
  1456. gtn,gten,
  1457. equaln,unequaln :
  1458. begin
  1459. op:=A_CMP;
  1460. cmpop:=true;
  1461. end;
  1462. xorn :
  1463. op:=A_XOR;
  1464. orn :
  1465. op:=A_OR;
  1466. andn :
  1467. op:=A_AND;
  1468. else
  1469. CGMessage(type_e_mismatch);
  1470. end;
  1471. { filter MUL, which requires special handling }
  1472. if op=A_MUL then
  1473. begin
  1474. second_mul;
  1475. exit;
  1476. end;
  1477. { Convert flags to register first }
  1478. if (left.location.loc=LOC_FLAGS) then
  1479. location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],false);
  1480. if (right.location.loc=LOC_FLAGS) then
  1481. location_force_reg(exprasmlist,right.location,opsize_2_cgsize[opsize],false);
  1482. left_must_be_reg(opsize,false);
  1483. emit_generic_code(op,opsize,unsigned,extra_not,mboverflow);
  1484. location_freetemp(exprasmlist,right.location);
  1485. location_release(exprasmlist,right.location);
  1486. if cmpop and
  1487. (left.location.loc<>LOC_CREGISTER) then
  1488. begin
  1489. location_freetemp(exprasmlist,left.location);
  1490. location_release(exprasmlist,left.location);
  1491. end;
  1492. set_result_location(cmpop,unsigned);
  1493. end
  1494. { 8/16 bit enum,char,wchar types }
  1495. else
  1496. if ((left.resulttype.def.deftype=orddef) and
  1497. (torddef(left.resulttype.def).typ in [uchar,uwidechar])) or
  1498. ((left.resulttype.def.deftype=enumdef) and
  1499. ((left.resulttype.def.size=1) or
  1500. (left.resulttype.def.size=2))) then
  1501. begin
  1502. case nodetype of
  1503. ltn,lten,gtn,gten,
  1504. equaln,unequaln :
  1505. cmpop:=true;
  1506. else
  1507. CGMessage(type_e_mismatch);
  1508. end;
  1509. left_must_be_reg(opsize,false);
  1510. emit_op_right_left(A_CMP,opsize);
  1511. location_freetemp(exprasmlist,right.location);
  1512. location_release(exprasmlist,right.location);
  1513. if left.location.loc<>LOC_CREGISTER then
  1514. begin
  1515. location_freetemp(exprasmlist,left.location);
  1516. location_release(exprasmlist,left.location);
  1517. end;
  1518. set_result_location(true,true);
  1519. end
  1520. else
  1521. CGMessage(type_e_mismatch);
  1522. end;
  1523. begin
  1524. caddnode:=ti386addnode;
  1525. end.
  1526. {
  1527. $Log$
  1528. Revision 1.56 2003-03-08 10:53:48 daniel
  1529. * Created newra version of secondmul in n386add.pas
  1530. Revision 1.55 2003/02/19 22:00:15 daniel
  1531. * Code generator converted to new register notation
  1532. - Horribily outdated todo.txt removed
  1533. Revision 1.54 2003/01/13 18:37:44 daniel
  1534. * Work on register conversion
  1535. Revision 1.53 2003/01/08 18:43:57 daniel
  1536. * Tregister changed into a record
  1537. Revision 1.52 2002/11/25 17:43:26 peter
  1538. * splitted defbase in defutil,symutil,defcmp
  1539. * merged isconvertable and is_equal into compare_defs(_ext)
  1540. * made operator search faster by walking the list only once
  1541. Revision 1.51 2002/11/15 01:58:56 peter
  1542. * merged changes from 1.0.7 up to 04-11
  1543. - -V option for generating bug report tracing
  1544. - more tracing for option parsing
  1545. - errors for cdecl and high()
  1546. - win32 import stabs
  1547. - win32 records<=8 are returned in eax:edx (turned off by default)
  1548. - heaptrc update
  1549. - more info for temp management in .s file with EXTDEBUG
  1550. Revision 1.50 2002/10/20 13:11:27 jonas
  1551. * re-enabled optimized version of comparisons with the empty string that
  1552. I accidentally disabled in revision 1.26
  1553. Revision 1.49 2002/08/23 16:14:49 peter
  1554. * tempgen cleanup
  1555. * tt_noreuse temp type added that will be used in genentrycode
  1556. Revision 1.48 2002/08/14 18:41:48 jonas
  1557. - remove valuelow/valuehigh fields from tlocation, because they depend
  1558. on the endianess of the host operating system -> difficult to get
  1559. right. Use lo/hi(location.valueqword) instead (remember to use
  1560. valueqword and not value!!)
  1561. Revision 1.47 2002/08/11 14:32:29 peter
  1562. * renamed current_library to objectlibrary
  1563. Revision 1.46 2002/08/11 13:24:16 peter
  1564. * saving of asmsymbols in ppu supported
  1565. * asmsymbollist global is removed and moved into a new class
  1566. tasmlibrarydata that will hold the info of a .a file which
  1567. corresponds with a single module. Added librarydata to tmodule
  1568. to keep the library info stored for the module. In the future the
  1569. objectfiles will also be stored to the tasmlibrarydata class
  1570. * all getlabel/newasmsymbol and friends are moved to the new class
  1571. Revision 1.45 2002/07/26 11:17:52 jonas
  1572. * the optimization of converting a multiplication with a power of two to
  1573. a shl is moved from n386add/secondpass to nadd/resulttypepass
  1574. Revision 1.44 2002/07/20 11:58:00 florian
  1575. * types.pas renamed to defbase.pas because D6 contains a types
  1576. unit so this would conflicts if D6 programms are compiled
  1577. + Willamette/SSE2 instructions to assembler added
  1578. Revision 1.43 2002/07/11 14:41:32 florian
  1579. * start of the new generic parameter handling
  1580. Revision 1.42 2002/07/07 09:52:33 florian
  1581. * powerpc target fixed, very simple units can be compiled
  1582. * some basic stuff for better callparanode handling, far from being finished
  1583. Revision 1.41 2002/07/01 18:46:31 peter
  1584. * internal linker
  1585. * reorganized aasm layer
  1586. Revision 1.40 2002/07/01 16:23:55 peter
  1587. * cg64 patch
  1588. * basics for currency
  1589. * asnode updates for class and interface (not finished)
  1590. Revision 1.39 2002/05/18 13:34:22 peter
  1591. * readded missing revisions
  1592. Revision 1.38 2002/05/16 19:46:51 carl
  1593. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  1594. + try to fix temp allocation (still in ifdef)
  1595. + generic constructor calls
  1596. + start of tassembler / tmodulebase class cleanup
  1597. Revision 1.36 2002/05/13 19:54:37 peter
  1598. * removed n386ld and n386util units
  1599. * maybe_save/maybe_restore added instead of the old maybe_push
  1600. Revision 1.35 2002/05/12 16:53:17 peter
  1601. * moved entry and exitcode to ncgutil and cgobj
  1602. * foreach gets extra argument for passing local data to the
  1603. iterator function
  1604. * -CR checks also class typecasts at runtime by changing them
  1605. into as
  1606. * fixed compiler to cycle with the -CR option
  1607. * fixed stabs with elf writer, finally the global variables can
  1608. be watched
  1609. * removed a lot of routines from cga unit and replaced them by
  1610. calls to cgobj
  1611. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  1612. u32bit then the other is typecasted also to u32bit without giving
  1613. a rangecheck warning/error.
  1614. * fixed pascal calling method with reversing also the high tree in
  1615. the parast, detected by tcalcst3 test
  1616. Revision 1.34 2002/04/25 20:16:40 peter
  1617. * moved more routines from cga/n386util
  1618. Revision 1.33 2002/04/05 15:09:13 jonas
  1619. * fixed web bug 1915
  1620. Revision 1.32 2002/04/04 19:06:10 peter
  1621. * removed unused units
  1622. * use tlocation.size in cg.a_*loc*() routines
  1623. Revision 1.31 2002/04/02 17:11:35 peter
  1624. * tlocation,treference update
  1625. * LOC_CONSTANT added for better constant handling
  1626. * secondadd splitted in multiple routines
  1627. * location_force_reg added for loading a location to a register
  1628. of a specified size
  1629. * secondassignment parses now first the right and then the left node
  1630. (this is compatible with Kylix). This saves a lot of push/pop especially
  1631. with string operations
  1632. * adapted some routines to use the new cg methods
  1633. Revision 1.29 2002/03/04 19:10:13 peter
  1634. * removed compiler warnings
  1635. }