n386add.pas 64 KB

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