n386add.pas 64 KB

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