n386add.pas 59 KB

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