n386cnv.pas 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. Generate i386 assembler for type converting nodes
  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 n386cnv;
  19. {$i defines.inc}
  20. interface
  21. uses
  22. node,ncnv,types;
  23. type
  24. ti386typeconvnode = class(ttypeconvnode)
  25. procedure second_int_to_int;virtual;
  26. procedure second_string_to_string;virtual;
  27. procedure second_cstring_to_pchar;virtual;
  28. procedure second_string_to_chararray;virtual;
  29. procedure second_array_to_pointer;virtual;
  30. procedure second_pointer_to_array;virtual;
  31. procedure second_chararray_to_string;virtual;
  32. procedure second_char_to_string;virtual;
  33. procedure second_int_to_real;virtual;
  34. procedure second_real_to_fix;virtual;
  35. procedure second_real_to_real;virtual;
  36. procedure second_fix_to_real;virtual;
  37. procedure second_cord_to_pointer;virtual;
  38. procedure second_int_to_fix;virtual;
  39. procedure second_proc_to_procvar;virtual;
  40. procedure second_bool_to_int;virtual;
  41. procedure second_int_to_bool;virtual;
  42. procedure second_load_smallset;virtual;
  43. procedure second_ansistring_to_pchar;virtual;
  44. procedure second_pchar_to_string;virtual;
  45. procedure second_nothing;virtual;
  46. procedure pass_2;override;
  47. procedure second_call_helper(c : tconverttype);
  48. end;
  49. ti386asnode = class(tasnode)
  50. procedure pass_2;override;
  51. end;
  52. ti386isnode = class(tisnode)
  53. procedure pass_2;override;
  54. end;
  55. implementation
  56. uses
  57. cobjects,verbose,globtype,globals,systems,
  58. symconst,symdef,aasm,
  59. hcodegen,temp_gen,pass_2,pass_1,
  60. ncon,ncal,
  61. cpubase,cpuasm,
  62. cgai386,tgeni386,n386util;
  63. {*****************************************************************************
  64. SecondTypeConv
  65. *****************************************************************************}
  66. procedure ti386typeconvnode.second_int_to_int;
  67. var
  68. op : tasmop;
  69. opsize : topsize;
  70. hregister,
  71. hregister2 : tregister;
  72. l : pasmlabel;
  73. begin
  74. { insert range check if not explicit conversion }
  75. if not(nf_explizit in flags) then
  76. emitrangecheck(left,resulttype);
  77. { is the result size smaller ? }
  78. if resulttype^.size<left.resulttype^.size then
  79. begin
  80. { only need to set the new size of a register }
  81. if (left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  82. begin
  83. case resulttype^.size of
  84. 1 : location.register:=makereg8(left.location.register);
  85. 2 : location.register:=makereg16(left.location.register);
  86. 4 : location.register:=makereg32(left.location.register);
  87. end;
  88. { we can release the upper register }
  89. if is_64bitint(left.resulttype) then
  90. ungetregister32(left.location.registerhigh);
  91. end;
  92. end
  93. { is the result size bigger ? }
  94. else if resulttype^.size>left.resulttype^.size then
  95. begin
  96. { remove reference }
  97. if not(left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  98. begin
  99. del_reference(left.location.reference);
  100. { we can do this here as we need no temp inside }
  101. ungetiftemp(left.location.reference);
  102. end;
  103. { get op and opsize, handle separate for constants, because
  104. movz doesn't support constant values }
  105. if (left.location.loc=LOC_MEM) and (left.location.reference.is_immediate) then
  106. begin
  107. if is_64bitint(resulttype) then
  108. opsize:=S_L
  109. else
  110. opsize:=def_opsize(resulttype);
  111. op:=A_MOV;
  112. end
  113. else
  114. begin
  115. opsize:=def2def_opsize(left.resulttype,resulttype);
  116. if opsize in [S_B,S_W,S_L] then
  117. op:=A_MOV
  118. else
  119. if is_signed(left.resulttype) then
  120. op:=A_MOVSX
  121. else
  122. op:=A_MOVZX;
  123. end;
  124. { load the register we need }
  125. if left.location.loc<>LOC_REGISTER then
  126. hregister:=getregister32
  127. else
  128. hregister:=left.location.register;
  129. { set the correct register size and location }
  130. clear_location(location);
  131. location.loc:=LOC_REGISTER;
  132. { do we need a second register for a 64 bit type ? }
  133. if is_64bitint(resulttype) then
  134. begin
  135. hregister2:=getregister32;
  136. location.registerhigh:=hregister2;
  137. end;
  138. case resulttype^.size of
  139. 1:
  140. location.register:=makereg8(hregister);
  141. 2:
  142. location.register:=makereg16(hregister);
  143. 4,8:
  144. location.register:=makereg32(hregister);
  145. end;
  146. { insert the assembler code }
  147. if left.location.loc in [LOC_CREGISTER,LOC_REGISTER] then
  148. emit_reg_reg(op,opsize,left.location.register,location.register)
  149. else
  150. emit_ref_reg(op,opsize,
  151. newreference(left.location.reference),location.register);
  152. { do we need a sign extension for int64? }
  153. if is_64bitint(resulttype) then
  154. begin
  155. emit_reg_reg(A_XOR,S_L,
  156. hregister2,hregister2);
  157. if (porddef(resulttype)^.typ=s64bit) and
  158. is_signed(left.resulttype) then
  159. begin
  160. getlabel(l);
  161. emit_const_reg(A_TEST,S_L,$80000000,makereg32(hregister));
  162. emitjmp(C_Z,l);
  163. emit_reg(A_NOT,S_L,
  164. hregister2);
  165. emitlab(l);
  166. end;
  167. end;
  168. end;
  169. end;
  170. procedure ti386typeconvnode.second_string_to_string;
  171. var
  172. pushed : tpushed;
  173. regs_to_push: byte;
  174. begin
  175. { does anybody know a better solution than this big case statement ? }
  176. { ok, a proc table would do the job }
  177. case pstringdef(resulttype)^.string_typ of
  178. st_shortstring:
  179. case pstringdef(left.resulttype)^.string_typ of
  180. st_shortstring:
  181. begin
  182. gettempofsizereference(resulttype^.size,location.reference);
  183. copyshortstring(location.reference,left.location.reference,
  184. pstringdef(resulttype)^.len,false,true);
  185. { done by copyshortstring now (JM) }
  186. { del_reference(left.location.reference); }
  187. ungetiftemp(left.location.reference);
  188. end;
  189. st_longstring:
  190. begin
  191. {!!!!!!!}
  192. internalerror(8888);
  193. end;
  194. st_ansistring:
  195. begin
  196. gettempofsizereference(resulttype^.size,location.reference);
  197. loadansi2short(left,self);
  198. { this is done in secondtypeconv (FK)
  199. removetemps(exprasmlist,temptoremove);
  200. destroys:=true;
  201. }
  202. end;
  203. st_widestring:
  204. begin
  205. {!!!!!!!}
  206. internalerror(8888);
  207. end;
  208. end;
  209. st_longstring:
  210. case pstringdef(left.resulttype)^.string_typ of
  211. st_shortstring:
  212. begin
  213. {!!!!!!!}
  214. internalerror(8888);
  215. end;
  216. st_ansistring:
  217. begin
  218. {!!!!!!!}
  219. internalerror(8888);
  220. end;
  221. st_widestring:
  222. begin
  223. {!!!!!!!}
  224. internalerror(8888);
  225. end;
  226. end;
  227. st_ansistring:
  228. case pstringdef(left.resulttype)^.string_typ of
  229. st_shortstring:
  230. begin
  231. clear_location(location);
  232. location.loc:=LOC_REFERENCE;
  233. gettempansistringreference(location.reference);
  234. decrstringref(cansistringdef,location.reference);
  235. { We don't need the source regs anymore (JM) }
  236. regs_to_push := $ff;
  237. remove_non_regvars_from_loc(left.location,regs_to_push);
  238. pushusedregisters(pushed,regs_to_push);
  239. release_loc(left.location);
  240. emit_push_lea_loc(left.location,true);
  241. emit_push_lea_loc(location,false);
  242. emitcall('FPC_SHORTSTR_TO_ANSISTR');
  243. maybe_loadesi;
  244. popusedregisters(pushed);
  245. end;
  246. st_longstring:
  247. begin
  248. {!!!!!!!}
  249. internalerror(8888);
  250. end;
  251. st_widestring:
  252. begin
  253. {!!!!!!!}
  254. internalerror(8888);
  255. end;
  256. end;
  257. st_widestring:
  258. case pstringdef(left.resulttype)^.string_typ of
  259. st_shortstring:
  260. begin
  261. {!!!!!!!}
  262. internalerror(8888);
  263. end;
  264. st_longstring:
  265. begin
  266. {!!!!!!!}
  267. internalerror(8888);
  268. end;
  269. st_ansistring:
  270. begin
  271. {!!!!!!!}
  272. internalerror(8888);
  273. end;
  274. st_widestring:
  275. begin
  276. {!!!!!!!}
  277. internalerror(8888);
  278. end;
  279. end;
  280. end;
  281. end;
  282. procedure ti386typeconvnode.second_cstring_to_pchar;
  283. var
  284. hr : preference;
  285. begin
  286. clear_location(location);
  287. location.loc:=LOC_REGISTER;
  288. location.register:=getregister32;
  289. case pstringdef(left.resulttype)^.string_typ of
  290. st_shortstring :
  291. begin
  292. inc(left.location.reference.offset);
  293. emit_ref_reg(A_LEA,S_L,newreference(left.location.reference),
  294. location.register);
  295. end;
  296. st_ansistring :
  297. begin
  298. if (left.nodetype=stringconstn) and
  299. (str_length(left)=0) then
  300. begin
  301. new(hr);
  302. reset_reference(hr^);
  303. hr^.symbol:=newasmsymbol('FPC_EMPTYCHAR');
  304. emit_ref_reg(A_LEA,S_L,hr,location.register);
  305. end
  306. else
  307. emit_ref_reg(A_MOV,S_L,newreference(left.location.reference),
  308. location.register);
  309. end;
  310. st_longstring:
  311. begin
  312. {!!!!!!!}
  313. internalerror(8888);
  314. end;
  315. st_widestring:
  316. begin
  317. {!!!!!!!}
  318. internalerror(8888);
  319. end;
  320. end;
  321. end;
  322. procedure ti386typeconvnode.second_string_to_chararray;
  323. var
  324. pushedregs: tpushed;
  325. //l1 : pasmlabel;
  326. //hr : preference;
  327. arrsize, strtype: longint;
  328. regstopush: byte;
  329. begin
  330. with parraydef(resulttype)^ do
  331. arrsize := highrange-lowrange+1;
  332. if (left.nodetype = stringconstn) and
  333. { left.length+1 since there's always a terminating #0 character (JM) }
  334. (tstringconstnode(left).len+1 >= arrsize) and
  335. (pstringdef(left.resulttype)^.string_typ=st_shortstring) then
  336. begin
  337. inc(location.reference.offset);
  338. exit;
  339. end;
  340. clear_location(location);
  341. location.loc := LOC_REFERENCE;
  342. gettempofsizereference(arrsize,location.reference);
  343. regstopush := $ff;
  344. remove_non_regvars_from_loc(left.location,regstopush);
  345. pushusedregisters(pushedregs,regstopush);
  346. emit_push_lea_loc(location,false);
  347. case pstringdef(left.resulttype)^.string_typ of
  348. st_shortstring :
  349. begin
  350. { 0 means shortstring }
  351. strtype := 0;
  352. del_reference(left.location.reference);
  353. emit_push_lea_loc(left.location,true);
  354. ungetiftemp(left.location.reference);
  355. end;
  356. st_ansistring :
  357. begin
  358. { 1 means ansistring }
  359. strtype := 1;
  360. case left.location.loc of
  361. LOC_CREGISTER,LOC_REGISTER:
  362. begin
  363. ungetregister(left.location.register);
  364. emit_push_loc(left.location);
  365. end;
  366. LOC_MEM,LOC_REFERENCE:
  367. begin
  368. del_reference(left.location.reference);
  369. emit_push_loc(left.location);
  370. ungetiftemp(left.location.reference);
  371. end;
  372. end;
  373. end;
  374. st_longstring:
  375. begin
  376. {!!!!!!!}
  377. { 2 means longstring, but still needs support in FPC_STR_TO_CHARARRAY,
  378. which is in i386.inc and/or generic.inc (JM) }
  379. strtype := 2;
  380. internalerror(8888);
  381. end;
  382. st_widestring:
  383. begin
  384. {!!!!!!!}
  385. { 3 means widestring, but still needs support in FPC_STR_TO_CHARARRAY,
  386. which is in i386.inc and/or generic.inc (JM) }
  387. strtype := 3;
  388. internalerror(8888);
  389. end;
  390. end;
  391. push_int(arrsize);
  392. push_int(strtype);
  393. emitcall('FPC_STR_TO_CHARARRAY');
  394. popusedregisters(pushedregs);
  395. end;
  396. procedure ti386typeconvnode.second_array_to_pointer;
  397. begin
  398. del_reference(left.location.reference);
  399. clear_location(location);
  400. location.loc:=LOC_REGISTER;
  401. location.register:=getregister32;
  402. emit_ref_reg(A_LEA,S_L,newreference(left.location.reference),
  403. location.register);
  404. end;
  405. procedure ti386typeconvnode.second_pointer_to_array;
  406. begin
  407. clear_location(location);
  408. location.loc:=LOC_REFERENCE;
  409. reset_reference(location.reference);
  410. case left.location.loc of
  411. LOC_REGISTER :
  412. location.reference.base:=left.location.register;
  413. LOC_CREGISTER :
  414. begin
  415. location.reference.base:=getregister32;
  416. emit_reg_reg(A_MOV,S_L,left.location.register,location.reference.base);
  417. end
  418. else
  419. begin
  420. del_reference(left.location.reference);
  421. location.reference.base:=getregister32;
  422. emit_ref_reg(A_MOV,S_L,newreference(left.location.reference),
  423. location.reference.base);
  424. end;
  425. end;
  426. end;
  427. { generates the code for the type conversion from an array of char }
  428. { to a string }
  429. procedure ti386typeconvnode.second_chararray_to_string;
  430. var
  431. pushed : tpushed;
  432. regstopush: byte;
  433. l : longint;
  434. begin
  435. { calc the length of the array }
  436. l:=parraydef(left.resulttype)^.highrange-parraydef(left.resulttype)^.lowrange+1;
  437. { this is a type conversion which copies the data, so we can't }
  438. { return a reference }
  439. clear_location(location);
  440. location.loc:=LOC_MEM;
  441. case pstringdef(resulttype)^.string_typ of
  442. st_shortstring :
  443. begin
  444. if l>255 then
  445. begin
  446. CGMessage(type_e_mismatch);
  447. l:=255;
  448. end;
  449. gettempofsizereference(resulttype^.size,location.reference);
  450. { we've also to release the registers ... }
  451. { Yes, but before pushusedregisters since that one resets unused! }
  452. { This caused web bug 1073 (JM) }
  453. regstopush := $ff;
  454. remove_non_regvars_from_loc(left.location,regstopush);
  455. pushusedregisters(pushed,regstopush);
  456. if l>=resulttype^.size then
  457. push_int(resulttype^.size-1)
  458. else
  459. push_int(l);
  460. { ... here only the temp. location is released }
  461. emit_push_lea_loc(left.location,true);
  462. del_reference(left.location.reference);
  463. emitpushreferenceaddr(location.reference);
  464. emitcall('FPC_CHARARRAY_TO_SHORTSTR');
  465. maybe_loadesi;
  466. popusedregisters(pushed);
  467. end;
  468. st_ansistring :
  469. begin
  470. gettempansistringreference(location.reference);
  471. decrstringref(cansistringdef,location.reference);
  472. regstopush := $ff;
  473. remove_non_regvars_from_loc(left.location,regstopush);
  474. pushusedregisters(pushed,regstopush);
  475. push_int(l);
  476. emitpushreferenceaddr(left.location.reference);
  477. release_loc(left.location);
  478. emitpushreferenceaddr(location.reference);
  479. emitcall('FPC_CHARARRAY_TO_ANSISTR');
  480. popusedregisters(pushed);
  481. maybe_loadesi;
  482. end;
  483. st_longstring:
  484. begin
  485. {!!!!!!!}
  486. internalerror(8888);
  487. end;
  488. st_widestring:
  489. begin
  490. {!!!!!!!}
  491. internalerror(8888);
  492. end;
  493. end;
  494. end;
  495. procedure ti386typeconvnode.second_char_to_string;
  496. var
  497. pushed : tpushed;
  498. begin
  499. clear_location(location);
  500. location.loc:=LOC_MEM;
  501. case pstringdef(resulttype)^.string_typ of
  502. st_shortstring :
  503. begin
  504. gettempofsizereference(256,location.reference);
  505. loadshortstring(left,self);
  506. end;
  507. st_ansistring :
  508. begin
  509. gettempansistringreference(location.reference);
  510. decrstringref(cansistringdef,location.reference);
  511. release_loc(left.location);
  512. pushusedregisters(pushed,$ff);
  513. emit_pushw_loc(left.location);
  514. emitpushreferenceaddr(location.reference);
  515. emitcall('FPC_CHAR_TO_ANSISTR');
  516. popusedregisters(pushed);
  517. maybe_loadesi;
  518. end;
  519. else
  520. internalerror(4179);
  521. end;
  522. end;
  523. procedure ti386typeconvnode.second_int_to_real;
  524. var
  525. r : preference;
  526. hregister : tregister;
  527. l1,l2 : pasmlabel;
  528. begin
  529. { for u32bit a solution is to push $0 and to load a comp }
  530. { does this first, it destroys maybe EDI }
  531. hregister:=R_EDI;
  532. if porddef(left.resulttype)^.typ=u32bit then
  533. push_int(0);
  534. if (left.location.loc=LOC_REGISTER) or
  535. (left.location.loc=LOC_CREGISTER) then
  536. begin
  537. {$ifndef noAllocEdi}
  538. if not (porddef(left.resulttype)^.typ in [u32bit,s32bit,u64bit,s64bit]) then
  539. getexplicitregister32(R_EDI);
  540. {$endif noAllocEdi}
  541. case porddef(left.resulttype)^.typ of
  542. s8bit : emit_reg_reg(A_MOVSX,S_BL,left.location.register,R_EDI);
  543. u8bit : emit_reg_reg(A_MOVZX,S_BL,left.location.register,R_EDI);
  544. s16bit : emit_reg_reg(A_MOVSX,S_WL,left.location.register,R_EDI);
  545. u16bit : emit_reg_reg(A_MOVZX,S_WL,left.location.register,R_EDI);
  546. u32bit,s32bit:
  547. hregister:=left.location.register;
  548. u64bit,s64bit:
  549. begin
  550. emit_reg(A_PUSH,S_L,left.location.registerhigh);
  551. hregister:=left.location.registerlow;
  552. end;
  553. end;
  554. ungetregister(left.location.register);
  555. end
  556. else
  557. begin
  558. r:=newreference(left.location.reference);
  559. {$ifndef noAllocEdi}
  560. getexplicitregister32(R_EDI);
  561. {$endif noAllocEdi}
  562. case porddef(left.resulttype)^.typ of
  563. s8bit:
  564. emit_ref_reg(A_MOVSX,S_BL,r,R_EDI);
  565. u8bit:
  566. emit_ref_reg(A_MOVZX,S_BL,r,R_EDI);
  567. s16bit:
  568. emit_ref_reg(A_MOVSX,S_WL,r,R_EDI);
  569. u16bit:
  570. emit_ref_reg(A_MOVZX,S_WL,r,R_EDI);
  571. u32bit,s32bit:
  572. emit_ref_reg(A_MOV,S_L,r,R_EDI);
  573. u64bit,s64bit:
  574. begin
  575. inc(r^.offset,4);
  576. emit_ref_reg(A_MOV,S_L,r,R_EDI);
  577. emit_reg(A_PUSH,S_L,R_EDI);
  578. r:=newreference(left.location.reference);
  579. emit_ref_reg(A_MOV,S_L,r,R_EDI);
  580. end;
  581. end;
  582. del_reference(left.location.reference);
  583. ungetiftemp(left.location.reference);
  584. end;
  585. { for 64 bit integers, the high dword is already pushed }
  586. emit_reg(A_PUSH,S_L,hregister);
  587. {$ifndef noAllocEdi}
  588. if hregister = R_EDI then
  589. ungetregister32(R_EDI);
  590. {$endif noAllocEdi}
  591. r:=new_reference(R_ESP,0);
  592. case porddef(left.resulttype)^.typ of
  593. u32bit:
  594. begin
  595. emit_ref(A_FILD,S_IQ,r);
  596. emit_const_reg(A_ADD,S_L,8,R_ESP);
  597. end;
  598. s64bit:
  599. begin
  600. emit_ref(A_FILD,S_IQ,r);
  601. emit_const_reg(A_ADD,S_L,8,R_ESP);
  602. end;
  603. u64bit:
  604. begin
  605. { unsigned 64 bit ints are harder to handle: }
  606. { we load bits 0..62 and then check bit 63: }
  607. { if it is 1 then we add $80000000 000000000 }
  608. { as double }
  609. inc(r^.offset,4);
  610. {$ifndef noAllocEdi}
  611. getexplicitregister32(R_EDI);
  612. {$endif noAllocEdi}
  613. emit_ref_reg(A_MOV,S_L,r,R_EDI);
  614. r:=new_reference(R_ESP,4);
  615. emit_const_ref(A_AND,S_L,$7fffffff,r);
  616. emit_const_reg(A_TEST,S_L,$80000000,R_EDI);
  617. {$ifndef noAllocEdi}
  618. ungetregister32(R_EDI);
  619. {$endif noAllocEdi}
  620. r:=new_reference(R_ESP,0);
  621. emit_ref(A_FILD,S_IQ,r);
  622. getdatalabel(l1);
  623. getlabel(l2);
  624. emitjmp(C_Z,l2);
  625. consts^.concat(new(pai_label,init(l1)));
  626. { I got this constant from a test progtram (FK) }
  627. consts^.concat(new(pai_const,init_32bit(0)));
  628. consts^.concat(new(pai_const,init_32bit(1138753536)));
  629. r:=new_reference(R_NO,0);
  630. r^.symbol:=l1;
  631. emit_ref(A_FADD,S_FL,r);
  632. emitlab(l2);
  633. emit_const_reg(A_ADD,S_L,8,R_ESP);
  634. end
  635. else
  636. begin
  637. emit_ref(A_FILD,S_IL,r);
  638. {$ifndef noAllocEdi}
  639. getexplicitregister32(R_EDI);
  640. {$endif noAllocEdi}
  641. emit_reg(A_POP,S_L,R_EDI);
  642. {$ifndef noAllocEdi}
  643. ungetregister32(R_EDI);
  644. {$endif noAllocEdi}
  645. end;
  646. end;
  647. inc(fpuvaroffset);
  648. clear_location(location);
  649. location.loc:=LOC_FPU;
  650. end;
  651. procedure ti386typeconvnode.second_real_to_fix;
  652. var
  653. rreg : tregister;
  654. ref : treference;
  655. begin
  656. { real must be on fpu stack }
  657. if (left.location.loc<>LOC_FPU) then
  658. emit_ref(A_FLD,S_FL,newreference(left.location.reference));
  659. push_int($1f3f);
  660. push_int(65536);
  661. reset_reference(ref);
  662. ref.base:=R_ESP;
  663. emit_ref(A_FIMUL,S_IL,newreference(ref));
  664. ref.offset:=4;
  665. emit_ref(A_FSTCW,S_NO,newreference(ref));
  666. ref.offset:=6;
  667. emit_ref(A_FLDCW,S_NO,newreference(ref));
  668. ref.offset:=0;
  669. emit_ref(A_FISTP,S_IL,newreference(ref));
  670. ref.offset:=4;
  671. emit_ref(A_FLDCW,S_NO,newreference(ref));
  672. rreg:=getregister32;
  673. emit_reg(A_POP,S_L,rreg);
  674. { better than an add on all processors }
  675. {$ifndef noAllocEdi}
  676. getexplicitregister32(R_EDI);
  677. {$endif noAllocEdi}
  678. emit_reg(A_POP,S_L,R_EDI);
  679. {$ifndef noAllocEdi}
  680. ungetregister32(R_EDI);
  681. {$endif noAllocEdi}
  682. clear_location(location);
  683. location.loc:=LOC_REGISTER;
  684. location.register:=rreg;
  685. inc(fpuvaroffset);
  686. end;
  687. procedure ti386typeconvnode.second_real_to_real;
  688. begin
  689. case left.location.loc of
  690. LOC_FPU : ;
  691. LOC_CFPUREGISTER:
  692. begin
  693. location:=left.location;
  694. exit;
  695. end;
  696. LOC_MEM,
  697. LOC_REFERENCE:
  698. begin
  699. floatload(pfloatdef(left.resulttype)^.typ,
  700. left.location.reference);
  701. { we have to free the reference }
  702. del_reference(left.location.reference);
  703. end;
  704. end;
  705. clear_location(location);
  706. location.loc:=LOC_FPU;
  707. end;
  708. procedure ti386typeconvnode.second_fix_to_real;
  709. var
  710. popeax,popebx,popecx,popedx : boolean;
  711. startreg : tregister;
  712. hl : pasmlabel;
  713. r : treference;
  714. begin
  715. if (left.location.loc=LOC_REGISTER) or
  716. (left.location.loc=LOC_CREGISTER) then
  717. begin
  718. startreg:=left.location.register;
  719. ungetregister(startreg);
  720. popeax:=(startreg<>R_EAX) and not (R_EAX in unused);
  721. if popeax then
  722. emit_reg(A_PUSH,S_L,R_EAX);
  723. { mov eax,eax is removed by emit_reg_reg }
  724. emit_reg_reg(A_MOV,S_L,startreg,R_EAX);
  725. end
  726. else
  727. begin
  728. emit_ref_reg(A_MOV,S_L,newreference(
  729. left.location.reference),R_EAX);
  730. del_reference(left.location.reference);
  731. startreg:=R_NO;
  732. end;
  733. popebx:=(startreg<>R_EBX) and not (R_EBX in unused);
  734. if popebx then
  735. emit_reg(A_PUSH,S_L,R_EBX);
  736. popecx:=(startreg<>R_ECX) and not (R_ECX in unused);
  737. if popecx then
  738. emit_reg(A_PUSH,S_L,R_ECX);
  739. popedx:=(startreg<>R_EDX) and not (R_EDX in unused);
  740. if popedx then
  741. emit_reg(A_PUSH,S_L,R_EDX);
  742. emit_none(A_CDQ,S_NO);
  743. emit_reg_reg(A_XOR,S_L,R_EDX,R_EAX);
  744. emit_reg_reg(A_MOV,S_L,R_EAX,R_EBX);
  745. emit_reg_reg(A_SUB,S_L,R_EDX,R_EAX);
  746. getlabel(hl);
  747. emitjmp(C_Z,hl);
  748. emit_const_reg(A_RCL,S_L,1,R_EBX);
  749. emit_reg_reg(A_BSR,S_L,R_EAX,R_EDX);
  750. emit_const_reg(A_MOV,S_B,32,R_CL);
  751. emit_reg_reg(A_SUB,S_B,R_DL,R_CL);
  752. emit_reg_reg(A_SHL,S_L,R_CL,R_EAX);
  753. emit_const_reg(A_ADD,S_W,1007,R_DX);
  754. emit_const_reg(A_SHL,S_W,5,R_DX);
  755. emit_const_reg_reg(A_SHLD,S_W,11,R_DX,R_BX);
  756. emit_const_reg_reg(A_SHLD,S_L,20,R_EAX,R_EBX);
  757. emit_const_reg(A_SHL,S_L,20,R_EAX);
  758. emitlab(hl);
  759. { better than an add on all processors }
  760. emit_reg(A_PUSH,S_L,R_EBX);
  761. emit_reg(A_PUSH,S_L,R_EAX);
  762. reset_reference(r);
  763. r.base:=R_ESP;
  764. emit_ref(A_FLD,S_FL,newreference(r));
  765. emit_const_reg(A_ADD,S_L,8,R_ESP);
  766. if popedx then
  767. emit_reg(A_POP,S_L,R_EDX);
  768. if popecx then
  769. emit_reg(A_POP,S_L,R_ECX);
  770. if popebx then
  771. emit_reg(A_POP,S_L,R_EBX);
  772. if popeax then
  773. emit_reg(A_POP,S_L,R_EAX);
  774. clear_location(location);
  775. location.loc:=LOC_FPU;
  776. end;
  777. procedure ti386typeconvnode.second_cord_to_pointer;
  778. begin
  779. { this can't happend, because constants are already processed in
  780. pass 1 }
  781. internalerror(47423985);
  782. end;
  783. procedure ti386typeconvnode.second_int_to_fix;
  784. var
  785. hregister : tregister;
  786. begin
  787. if (left.location.loc=LOC_REGISTER) then
  788. hregister:=left.location.register
  789. else if (left.location.loc=LOC_CREGISTER) then
  790. hregister:=getregister32
  791. else
  792. begin
  793. del_reference(left.location.reference);
  794. hregister:=getregister32;
  795. case porddef(left.resulttype)^.typ of
  796. s8bit : emit_ref_reg(A_MOVSX,S_BL,newreference(left.location.reference),
  797. hregister);
  798. u8bit : emit_ref_reg(A_MOVZX,S_BL,newreference(left.location.reference),
  799. hregister);
  800. s16bit : emit_ref_reg(A_MOVSX,S_WL,newreference(left.location.reference),
  801. hregister);
  802. u16bit : emit_ref_reg(A_MOVZX,S_WL,newreference(left.location.reference),
  803. hregister);
  804. u32bit,s32bit : emit_ref_reg(A_MOV,S_L,newreference(left.location.reference),
  805. hregister);
  806. {!!!! u32bit }
  807. end;
  808. end;
  809. emit_const_reg(A_SHL,S_L,16,hregister);
  810. clear_location(location);
  811. location.loc:=LOC_REGISTER;
  812. location.register:=hregister;
  813. end;
  814. procedure ti386typeconvnode.second_proc_to_procvar;
  815. begin
  816. { method pointer ? }
  817. if assigned(tcallnode(left).left) then
  818. begin
  819. set_location(location,left.location);
  820. end
  821. else
  822. begin
  823. clear_location(location);
  824. location.loc:=LOC_REGISTER;
  825. location.register:=getregister32;
  826. del_reference(left.location.reference);
  827. emit_ref_reg(A_LEA,S_L,
  828. newreference(left.location.reference),location.register);
  829. end;
  830. end;
  831. procedure ti386typeconvnode.second_bool_to_int;
  832. var
  833. oldtruelabel,oldfalselabel,hlabel : pasmlabel;
  834. hregister : tregister;
  835. newsize,
  836. opsize : topsize;
  837. op : tasmop;
  838. begin
  839. oldtruelabel:=truelabel;
  840. oldfalselabel:=falselabel;
  841. getlabel(truelabel);
  842. getlabel(falselabel);
  843. secondpass(left);
  844. { byte(boolean) or word(wordbool) or longint(longbool) must
  845. be accepted for var parameters }
  846. if (nf_explizit in flags) and
  847. (left.resulttype^.size=resulttype^.size) and
  848. (left.location.loc in [LOC_REFERENCE,LOC_MEM,LOC_CREGISTER]) then
  849. begin
  850. set_location(location,left.location);
  851. truelabel:=oldtruelabel;
  852. falselabel:=oldfalselabel;
  853. exit;
  854. end;
  855. clear_location(location);
  856. location.loc:=LOC_REGISTER;
  857. del_reference(left.location.reference);
  858. case left.resulttype^.size of
  859. 1 : begin
  860. case resulttype^.size of
  861. 1 : opsize:=S_B;
  862. 2 : opsize:=S_BW;
  863. 4 : opsize:=S_BL;
  864. end;
  865. end;
  866. 2 : begin
  867. case resulttype^.size of
  868. 1 : begin
  869. if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  870. left.location.register:=reg16toreg8(left.location.register);
  871. opsize:=S_B;
  872. end;
  873. 2 : opsize:=S_W;
  874. 4 : opsize:=S_WL;
  875. end;
  876. end;
  877. 4 : begin
  878. case resulttype^.size of
  879. 1 : begin
  880. if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  881. left.location.register:=reg32toreg8(left.location.register);
  882. opsize:=S_B;
  883. end;
  884. 2 : begin
  885. if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  886. left.location.register:=reg32toreg16(left.location.register);
  887. opsize:=S_W;
  888. end;
  889. 4 : opsize:=S_L;
  890. end;
  891. end;
  892. end;
  893. if opsize in [S_B,S_W,S_L] then
  894. op:=A_MOV
  895. else
  896. if is_signed(resulttype) then
  897. op:=A_MOVSX
  898. else
  899. op:=A_MOVZX;
  900. hregister:=getregister32;
  901. case resulttype^.size of
  902. 1 : begin
  903. location.register:=reg32toreg8(hregister);
  904. newsize:=S_B;
  905. end;
  906. 2 : begin
  907. location.register:=reg32toreg16(hregister);
  908. newsize:=S_W;
  909. end;
  910. 4 : begin
  911. location.register:=hregister;
  912. newsize:=S_L;
  913. end;
  914. else
  915. internalerror(10060);
  916. end;
  917. case left.location.loc of
  918. LOC_MEM,
  919. LOC_REFERENCE : emit_ref_reg(op,opsize,
  920. newreference(left.location.reference),location.register);
  921. LOC_REGISTER,
  922. LOC_CREGISTER : begin
  923. { remove things like movb %al,%al }
  924. if left.location.register<>location.register then
  925. emit_reg_reg(op,opsize,
  926. left.location.register,location.register);
  927. end;
  928. LOC_FLAGS : begin
  929. emit_flag2reg(left.location.resflags,location.register);
  930. end;
  931. LOC_JUMP : begin
  932. getlabel(hlabel);
  933. emitlab(truelabel);
  934. emit_const_reg(A_MOV,newsize,1,location.register);
  935. emitjmp(C_None,hlabel);
  936. emitlab(falselabel);
  937. emit_reg_reg(A_XOR,newsize,location.register,
  938. location.register);
  939. emitlab(hlabel);
  940. end;
  941. else
  942. internalerror(10061);
  943. end;
  944. truelabel:=oldtruelabel;
  945. falselabel:=oldfalselabel;
  946. end;
  947. procedure ti386typeconvnode.second_int_to_bool;
  948. var
  949. hregister : tregister;
  950. resflags : tresflags;
  951. opsize : topsize;
  952. begin
  953. clear_location(location);
  954. { byte(boolean) or word(wordbool) or longint(longbool) must
  955. be accepted for var parameters }
  956. if (nf_explizit in flags) and
  957. (left.resulttype^.size=resulttype^.size) and
  958. (left.location.loc in [LOC_REFERENCE,LOC_MEM,LOC_CREGISTER]) then
  959. begin
  960. set_location(location,left.location);
  961. exit;
  962. end;
  963. location.loc:=LOC_REGISTER;
  964. del_reference(left.location.reference);
  965. opsize:=def_opsize(left.resulttype);
  966. case left.location.loc of
  967. LOC_MEM,LOC_REFERENCE :
  968. begin
  969. hregister:=def_getreg(left.resulttype);
  970. emit_ref_reg(A_MOV,opsize,
  971. newreference(left.location.reference),hregister);
  972. emit_reg_reg(A_OR,opsize,hregister,hregister);
  973. resflags:=F_NE;
  974. end;
  975. LOC_FLAGS :
  976. begin
  977. hregister:=getregister32;
  978. resflags:=left.location.resflags;
  979. end;
  980. LOC_REGISTER,LOC_CREGISTER :
  981. begin
  982. hregister:=left.location.register;
  983. emit_reg_reg(A_OR,opsize,hregister,hregister);
  984. resflags:=F_NE;
  985. end;
  986. else
  987. internalerror(10062);
  988. end;
  989. case resulttype^.size of
  990. 1 : location.register:=makereg8(hregister);
  991. 2 : location.register:=makereg16(hregister);
  992. 4 : location.register:=makereg32(hregister);
  993. else
  994. internalerror(10064);
  995. end;
  996. emit_flag2reg(resflags,location.register);
  997. end;
  998. procedure ti386typeconvnode.second_load_smallset;
  999. var
  1000. href : treference;
  1001. pushedregs : tpushed;
  1002. begin
  1003. href.symbol:=nil;
  1004. pushusedregisters(pushedregs,$ff);
  1005. gettempofsizereference(32,href);
  1006. emitpushreferenceaddr(left.location.reference);
  1007. emitpushreferenceaddr(href);
  1008. emitcall('FPC_SET_LOAD_SMALL');
  1009. maybe_loadesi;
  1010. popusedregisters(pushedregs);
  1011. clear_location(location);
  1012. location.loc:=LOC_MEM;
  1013. location.reference:=href;
  1014. end;
  1015. procedure ti386typeconvnode.second_ansistring_to_pchar;
  1016. var
  1017. l1 : pasmlabel;
  1018. hr : preference;
  1019. begin
  1020. clear_location(location);
  1021. location.loc:=LOC_REGISTER;
  1022. getlabel(l1);
  1023. case left.location.loc of
  1024. LOC_CREGISTER,LOC_REGISTER:
  1025. location.register:=left.location.register;
  1026. LOC_MEM,LOC_REFERENCE:
  1027. begin
  1028. location.register:=getregister32;
  1029. emit_ref_reg(A_MOV,S_L,newreference(left.location.reference),
  1030. location.register);
  1031. del_reference(left.location.reference);
  1032. end;
  1033. end;
  1034. emit_const_reg(A_CMP,S_L,0,location.register);
  1035. emitjmp(C_NZ,l1);
  1036. new(hr);
  1037. reset_reference(hr^);
  1038. hr^.symbol:=newasmsymbol('FPC_EMPTYCHAR');
  1039. emit_ref_reg(A_LEA,S_L,hr,location.register);
  1040. emitlab(l1);
  1041. end;
  1042. procedure ti386typeconvnode.second_pchar_to_string;
  1043. var
  1044. pushed : tpushed;
  1045. regs_to_push: byte;
  1046. begin
  1047. case pstringdef(resulttype)^.string_typ of
  1048. st_shortstring:
  1049. begin
  1050. location.loc:=LOC_REFERENCE;
  1051. gettempofsizereference(resulttype^.size,location.reference);
  1052. pushusedregisters(pushed,$ff);
  1053. case left.location.loc of
  1054. LOC_REGISTER,LOC_CREGISTER:
  1055. begin
  1056. emit_reg(A_PUSH,S_L,left.location.register);
  1057. ungetregister32(left.location.register);
  1058. end;
  1059. LOC_REFERENCE,LOC_MEM:
  1060. begin
  1061. { Now release the registers (see cgai386.pas: }
  1062. { loadansistring for more info on the order) (JM) }
  1063. del_reference(left.location.reference);
  1064. emit_push_mem(left.location.reference);
  1065. end;
  1066. end;
  1067. emitpushreferenceaddr(location.reference);
  1068. emitcall('FPC_PCHAR_TO_SHORTSTR');
  1069. maybe_loadesi;
  1070. popusedregisters(pushed);
  1071. end;
  1072. st_ansistring:
  1073. begin
  1074. location.loc:=LOC_REFERENCE;
  1075. gettempansistringreference(location.reference);
  1076. decrstringref(cansistringdef,location.reference);
  1077. { Find out which regs have to be pushed (JM) }
  1078. regs_to_push := $ff;
  1079. remove_non_regvars_from_loc(left.location,regs_to_push);
  1080. pushusedregisters(pushed,regs_to_push);
  1081. case left.location.loc of
  1082. LOC_REFERENCE,LOC_MEM:
  1083. begin
  1084. { Now release the registers (see cgai386.pas: }
  1085. { loadansistring for more info on the order) (JM) }
  1086. del_reference(left.location.reference);
  1087. emit_push_mem(left.location.reference);
  1088. end;
  1089. LOC_REGISTER,LOC_CREGISTER:
  1090. begin
  1091. { Now release the registers (see cgai386.pas: }
  1092. { loadansistring for more info on the order) (JM) }
  1093. emit_reg(A_PUSH,S_L,left.location.register);
  1094. ungetregister32(left.location.register);
  1095. end;
  1096. end;
  1097. emitpushreferenceaddr(location.reference);
  1098. emitcall('FPC_PCHAR_TO_ANSISTR');
  1099. maybe_loadesi;
  1100. popusedregisters(pushed);
  1101. end;
  1102. else
  1103. begin
  1104. internalerror(12121);
  1105. end;
  1106. end;
  1107. end;
  1108. procedure ti386typeconvnode.second_nothing;
  1109. begin
  1110. end;
  1111. {****************************************************************************
  1112. TI386TYPECONVNODE
  1113. ****************************************************************************}
  1114. procedure ti386typeconvnode.second_call_helper(c : tconverttype);
  1115. const
  1116. secondconvert : array[tconverttype] of pointer = (
  1117. @ti386typeconvnode.second_nothing, {equal}
  1118. @ti386typeconvnode.second_nothing, {not_possible}
  1119. @ti386typeconvnode.second_string_to_string,
  1120. @ti386typeconvnode.second_char_to_string,
  1121. @ti386typeconvnode.second_pchar_to_string,
  1122. @ti386typeconvnode.second_nothing, {cchar_to_pchar}
  1123. @ti386typeconvnode.second_cstring_to_pchar,
  1124. @ti386typeconvnode.second_ansistring_to_pchar,
  1125. @ti386typeconvnode.second_string_to_chararray,
  1126. @ti386typeconvnode.second_chararray_to_string,
  1127. @ti386typeconvnode.second_array_to_pointer,
  1128. @ti386typeconvnode.second_pointer_to_array,
  1129. @ti386typeconvnode.second_int_to_int,
  1130. @ti386typeconvnode.second_int_to_bool,
  1131. @ti386typeconvnode.second_bool_to_int, { bool_to_bool }
  1132. @ti386typeconvnode.second_bool_to_int,
  1133. @ti386typeconvnode.second_real_to_real,
  1134. @ti386typeconvnode.second_int_to_real,
  1135. @ti386typeconvnode.second_int_to_fix,
  1136. @ti386typeconvnode.second_real_to_fix,
  1137. @ti386typeconvnode.second_fix_to_real,
  1138. @ti386typeconvnode.second_proc_to_procvar,
  1139. @ti386typeconvnode.second_nothing, {arrayconstructor_to_set}
  1140. @ti386typeconvnode.second_load_smallset,
  1141. @ti386typeconvnode.second_cord_to_pointer,
  1142. @ti386typeconvnode.second_nothing, { interface 2 string }
  1143. @ti386typeconvnode.second_nothing { interface 2 guid }
  1144. );
  1145. type
  1146. tprocedureofobject = procedure of object;
  1147. var
  1148. r : packed record
  1149. proc : pointer;
  1150. obj : pointer;
  1151. end;
  1152. begin
  1153. { this is a little bit dirty but it works }
  1154. { and should be quite portable too }
  1155. r.proc:=secondconvert[c];
  1156. r.obj:=self;
  1157. tprocedureofobject(r){$ifdef FPC}();{$endif FPC}
  1158. end;
  1159. procedure ti386typeconvnode.pass_2;
  1160. {$ifdef TESTOBJEXT2}
  1161. var
  1162. r : preference;
  1163. nillabel : plabel;
  1164. {$endif TESTOBJEXT2}
  1165. begin
  1166. { this isn't good coding, I think tc_bool_2_int, shouldn't be }
  1167. { type conversion (FK) }
  1168. if not(convtype in [tc_bool_2_int,tc_bool_2_bool]) then
  1169. begin
  1170. secondpass(left);
  1171. set_location(location,left.location);
  1172. if codegenerror then
  1173. exit;
  1174. end;
  1175. second_call_helper(convtype);
  1176. {$ifdef TESTOBJEXT2}
  1177. { Check explicit conversions to objects pointers !! }
  1178. if p^.explizit and
  1179. (p^.resulttype^.deftype=pointerdef) and
  1180. (ppointerdef(p^.resulttype)^.definition^.deftype=objectdef) and not
  1181. (pobjectdef(ppointerdef(p^.resulttype)^.definition)^.isclass) and
  1182. ((pobjectdef(ppointerdef(p^.resulttype)^.definition)^.options and oo_hasvmt)<>0) and
  1183. (cs_check_range in aktlocalswitches) then
  1184. begin
  1185. new(r);
  1186. reset_reference(r^);
  1187. if p^.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  1188. r^.base:=p^.location.register
  1189. else
  1190. begin
  1191. {$ifndef noAllocEdi}
  1192. getexplicitregister32(R_EDI);
  1193. {$endif noAllocEdi}
  1194. emit_mov_loc_reg(p^.location,R_EDI);
  1195. r^.base:=R_EDI;
  1196. end;
  1197. { NIL must be accepted !! }
  1198. emit_reg_reg(A_OR,S_L,r^.base,r^.base);
  1199. {$ifndef noAllocEdi}
  1200. ungetregister32(R_EDI);
  1201. {$endif noAllocEdi}
  1202. getlabel(nillabel);
  1203. emitjmp(C_E,nillabel);
  1204. { this is one point where we need vmt_offset (PM) }
  1205. r^.offset:= pobjectdef(ppointerdef(p^.resulttype)^.definition)^.vmt_offset;
  1206. {$ifndef noAllocEdi}
  1207. getexplicitregister32(R_EDI);
  1208. {$endif noAllocEdi}
  1209. emit_ref_reg(A_MOV,S_L,r,R_EDI);
  1210. emit_sym(A_PUSH,S_L,
  1211. newasmsymbol(pobjectdef(ppointerdef(p^.resulttype)^.definition)^.vmt_mangledname));
  1212. emit_reg(A_PUSH,S_L,R_EDI);
  1213. {$ifndef noAllocEdi}
  1214. ungetregister32(R_EDI);
  1215. {$endif noAllocEdi}
  1216. emitcall('FPC_CHECK_OBJECT_EXT');
  1217. emitlab(nillabel);
  1218. end;
  1219. {$endif TESTOBJEXT2}
  1220. end;
  1221. {*****************************************************************************
  1222. TI386ISNODE
  1223. *****************************************************************************}
  1224. procedure ti386isnode.pass_2;
  1225. var
  1226. pushed : tpushed;
  1227. begin
  1228. { save all used registers }
  1229. pushusedregisters(pushed,$ff);
  1230. secondpass(left);
  1231. clear_location(location);
  1232. location.loc:=LOC_FLAGS;
  1233. location.resflags:=F_NE;
  1234. { push instance to check: }
  1235. case left.location.loc of
  1236. LOC_REGISTER,LOC_CREGISTER:
  1237. begin
  1238. emit_reg(A_PUSH,
  1239. S_L,left.location.register);
  1240. ungetregister32(left.location.register);
  1241. end;
  1242. LOC_MEM,LOC_REFERENCE:
  1243. begin
  1244. emit_ref(A_PUSH,
  1245. S_L,newreference(left.location.reference));
  1246. del_reference(left.location.reference);
  1247. end;
  1248. else internalerror(100);
  1249. end;
  1250. { generate type checking }
  1251. secondpass(right);
  1252. case right.location.loc of
  1253. LOC_REGISTER,LOC_CREGISTER:
  1254. begin
  1255. emit_reg(A_PUSH,
  1256. S_L,right.location.register);
  1257. ungetregister32(right.location.register);
  1258. end;
  1259. LOC_MEM,LOC_REFERENCE:
  1260. begin
  1261. emit_ref(A_PUSH,
  1262. S_L,newreference(right.location.reference));
  1263. del_reference(right.location.reference);
  1264. end;
  1265. else internalerror(100);
  1266. end;
  1267. emitcall('FPC_DO_IS');
  1268. emit_reg_reg(A_OR,S_B,R_AL,R_AL);
  1269. popusedregisters(pushed);
  1270. maybe_loadesi;
  1271. end;
  1272. {*****************************************************************************
  1273. TI386ASNODE
  1274. *****************************************************************************}
  1275. procedure ti386asnode.pass_2;
  1276. var
  1277. pushed : tpushed;
  1278. begin
  1279. secondpass(left);
  1280. { save all used registers }
  1281. pushusedregisters(pushed,$ff);
  1282. { push instance to check: }
  1283. case left.location.loc of
  1284. LOC_REGISTER,LOC_CREGISTER:
  1285. emit_reg(A_PUSH,
  1286. S_L,left.location.register);
  1287. LOC_MEM,LOC_REFERENCE:
  1288. emit_ref(A_PUSH,
  1289. S_L,newreference(left.location.reference));
  1290. else internalerror(100);
  1291. end;
  1292. { we doesn't modifiy the left side, we check only the type }
  1293. set_location(location,left.location);
  1294. { generate type checking }
  1295. secondpass(right);
  1296. case right.location.loc of
  1297. LOC_REGISTER,LOC_CREGISTER:
  1298. begin
  1299. emit_reg(A_PUSH,
  1300. S_L,right.location.register);
  1301. ungetregister32(right.location.register);
  1302. end;
  1303. LOC_MEM,LOC_REFERENCE:
  1304. begin
  1305. emit_ref(A_PUSH,
  1306. S_L,newreference(right.location.reference));
  1307. del_reference(right.location.reference);
  1308. end;
  1309. else internalerror(100);
  1310. end;
  1311. emitcall('FPC_DO_AS');
  1312. { restore register, this restores automatically the }
  1313. { result }
  1314. popusedregisters(pushed);
  1315. maybe_loadesi;
  1316. end;
  1317. begin
  1318. ctypeconvnode:=ti386typeconvnode;
  1319. cisnode:=ti386isnode;
  1320. casnode:=ti386asnode;
  1321. end.
  1322. {
  1323. $Log$
  1324. Revision 1.3 2000-11-04 14:25:23 florian
  1325. + merged Attila's changes for interfaces, not tested yet
  1326. Revision 1.2 2000/10/31 22:02:56 peter
  1327. * symtable splitted, no real code changes
  1328. Revision 1.1 2000/10/15 09:33:31 peter
  1329. * moved n386*.pas to i386/ cpu_target dir
  1330. Revision 1.1 2000/10/14 10:14:48 peter
  1331. * moehrendorf oct 2000 rewrite
  1332. }