n386add.pas 65 KB

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