n386cnv.pas 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103
  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_real;virtual;
  35. procedure second_cord_to_pointer;virtual;
  36. procedure second_proc_to_procvar;virtual;
  37. procedure second_bool_to_int;virtual;
  38. procedure second_int_to_bool;virtual;
  39. procedure second_load_smallset;virtual;
  40. procedure second_ansistring_to_pchar;virtual;
  41. { procedure second_pchar_to_string;virtual; }
  42. procedure second_class_to_intf;virtual;
  43. procedure second_char_to_char;virtual;
  44. procedure second_nothing;virtual;
  45. procedure pass_2;override;
  46. procedure second_call_helper(c : tconverttype);
  47. end;
  48. ti386asnode = class(tasnode)
  49. procedure pass_2;override;
  50. end;
  51. ti386isnode = class(tisnode)
  52. procedure pass_2;override;
  53. end;
  54. implementation
  55. uses
  56. verbose,globals,systems,
  57. symconst,symdef,aasm,
  58. cgbase,temp_gen,pass_2,
  59. ncon,ncal,
  60. cpubase,cpuasm,
  61. cga,tgcpu,n386util;
  62. {*****************************************************************************
  63. SecondTypeConv
  64. *****************************************************************************}
  65. procedure ti386typeconvnode.second_int_to_int;
  66. var
  67. op : tasmop;
  68. opsize : topsize;
  69. hregister,
  70. hregister2 : tregister;
  71. l : tasmlabel;
  72. begin
  73. { insert range check if not explicit conversion }
  74. if not(nf_explizit in flags) then
  75. emitrangecheck(left,resulttype.def);
  76. { is the result size smaller ? }
  77. if resulttype.def.size<left.resulttype.def.size then
  78. begin
  79. { only need to set the new size of a register }
  80. if (left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  81. begin
  82. case resulttype.def.size of
  83. 1 : location.register:=makereg8(left.location.register);
  84. 2 : location.register:=makereg16(left.location.register);
  85. 4 : location.register:=makereg32(left.location.register);
  86. end;
  87. { we can release the upper register }
  88. if is_64bitint(left.resulttype.def) then
  89. ungetregister32(left.location.registerhigh);
  90. end;
  91. end
  92. { is the result size bigger ? }
  93. else if resulttype.def.size>left.resulttype.def.size then
  94. begin
  95. { remove reference }
  96. if not(left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  97. begin
  98. del_reference(left.location.reference);
  99. { we can do this here as we need no temp inside }
  100. ungetiftemp(left.location.reference);
  101. end;
  102. { get op and opsize, handle separate for constants, because
  103. movz doesn't support constant values }
  104. if (left.location.loc=LOC_MEM) and (left.location.reference.is_immediate) then
  105. begin
  106. if is_64bitint(resulttype.def) then
  107. opsize:=S_L
  108. else
  109. opsize:=def_opsize(resulttype.def);
  110. op:=A_MOV;
  111. end
  112. else
  113. begin
  114. opsize:=def2def_opsize(left.resulttype.def,resulttype.def);
  115. if opsize in [S_B,S_W,S_L] then
  116. op:=A_MOV
  117. else
  118. if is_signed(left.resulttype.def) then
  119. op:=A_MOVSX
  120. else
  121. op:=A_MOVZX;
  122. end;
  123. { load the register we need }
  124. if left.location.loc<>LOC_REGISTER then
  125. hregister:=getregister32
  126. else
  127. hregister:=left.location.register;
  128. { set the correct register size and location }
  129. clear_location(location);
  130. location.loc:=LOC_REGISTER;
  131. { do we need a second register for a 64 bit type ? }
  132. if is_64bitint(resulttype.def) then
  133. begin
  134. hregister2:=getregister32;
  135. location.registerhigh:=hregister2;
  136. end;
  137. case resulttype.def.size of
  138. 1:
  139. location.register:=makereg8(hregister);
  140. 2:
  141. location.register:=makereg16(hregister);
  142. 4,8:
  143. location.register:=makereg32(hregister);
  144. end;
  145. { insert the assembler code }
  146. if left.location.loc in [LOC_CREGISTER,LOC_REGISTER] then
  147. emit_reg_reg(op,opsize,left.location.register,location.register)
  148. else
  149. emit_ref_reg(op,opsize,
  150. newreference(left.location.reference),location.register);
  151. { do we need a sign extension for int64? }
  152. if is_64bitint(resulttype.def) then
  153. { special case for constants (JM) }
  154. if is_constintnode(left) then
  155. begin
  156. if tordconstnode(left).value >= 0 then
  157. emit_reg_reg(A_XOR,S_L,
  158. hregister2,hregister2)
  159. else
  160. emit_const_reg(A_MOV,S_L,longint($ffffffff),hregister2);
  161. end
  162. else
  163. begin
  164. emit_reg_reg(A_XOR,S_L,
  165. hregister2,hregister2);
  166. if (torddef(resulttype.def).typ=s64bit) and
  167. is_signed(left.resulttype.def) then
  168. begin
  169. getlabel(l);
  170. emit_const_reg(A_TEST,S_L,longint($80000000),makereg32(hregister));
  171. emitjmp(C_Z,l);
  172. emit_reg(A_NOT,S_L,
  173. hregister2);
  174. emitlab(l);
  175. end;
  176. end;
  177. end;
  178. end;
  179. procedure ti386typeconvnode.second_cstring_to_pchar;
  180. var
  181. hr : preference;
  182. begin
  183. clear_location(location);
  184. location.loc:=LOC_REGISTER;
  185. case tstringdef(left.resulttype.def).string_typ of
  186. st_shortstring :
  187. begin
  188. inc(left.location.reference.offset);
  189. del_reference(left.location.reference);
  190. location.register:=getregister32;
  191. emit_ref_reg(A_LEA,S_L,newreference(left.location.reference),
  192. location.register);
  193. end;
  194. st_ansistring :
  195. begin
  196. if (left.nodetype=stringconstn) and
  197. (str_length(left)=0) then
  198. begin
  199. new(hr);
  200. reset_reference(hr^);
  201. hr^.symbol:=newasmsymbol('FPC_EMPTYCHAR');
  202. location.register:=getregister32;
  203. emit_ref_reg(A_LEA,S_L,hr,location.register);
  204. end
  205. else
  206. begin
  207. del_reference(left.location.reference);
  208. location.register:=getregister32;
  209. emit_ref_reg(A_MOV,S_L,newreference(left.location.reference),
  210. location.register);
  211. end;
  212. end;
  213. st_longstring:
  214. begin
  215. {!!!!!!!}
  216. internalerror(8888);
  217. end;
  218. st_widestring:
  219. begin
  220. if (left.nodetype=stringconstn) and
  221. (str_length(left)=0) then
  222. begin
  223. new(hr);
  224. reset_reference(hr^);
  225. hr^.symbol:=newasmsymbol('FPC_EMPTYCHAR');
  226. location.register:=getregister32;
  227. emit_ref_reg(A_LEA,S_L,hr,location.register);
  228. end
  229. else
  230. begin
  231. del_reference(left.location.reference);
  232. location.register:=getregister32;
  233. emit_ref_reg(A_MOV,S_L,newreference(left.location.reference),
  234. location.register);
  235. end;
  236. end;
  237. end;
  238. end;
  239. procedure ti386typeconvnode.second_string_to_chararray;
  240. var
  241. arrsize: longint;
  242. begin
  243. with tarraydef(resulttype.def) do
  244. arrsize := highrange-lowrange+1;
  245. if (left.nodetype = stringconstn) and
  246. { left.length+1 since there's always a terminating #0 character (JM) }
  247. (tstringconstnode(left).len+1 >= arrsize) and
  248. (tstringdef(left.resulttype.def).string_typ=st_shortstring) then
  249. begin
  250. inc(location.reference.offset);
  251. exit;
  252. end
  253. else
  254. { should be handled already in resulttype pass (JM) }
  255. internalerror(200108292);
  256. end;
  257. procedure ti386typeconvnode.second_array_to_pointer;
  258. begin
  259. del_reference(left.location.reference);
  260. clear_location(location);
  261. location.loc:=LOC_REGISTER;
  262. location.register:=getregister32;
  263. emit_ref_reg(A_LEA,S_L,newreference(left.location.reference),
  264. location.register);
  265. end;
  266. procedure ti386typeconvnode.second_pointer_to_array;
  267. begin
  268. clear_location(location);
  269. location.loc:=LOC_REFERENCE;
  270. reset_reference(location.reference);
  271. case left.location.loc of
  272. LOC_REGISTER :
  273. location.reference.base:=left.location.register;
  274. LOC_CREGISTER :
  275. begin
  276. location.reference.base:=getregister32;
  277. emit_reg_reg(A_MOV,S_L,left.location.register,location.reference.base);
  278. end
  279. else
  280. begin
  281. del_reference(left.location.reference);
  282. location.reference.base:=getregister32;
  283. emit_ref_reg(A_MOV,S_L,newreference(left.location.reference),
  284. location.reference.base);
  285. end;
  286. end;
  287. end;
  288. procedure ti386typeconvnode.second_char_to_string;
  289. begin
  290. clear_location(location);
  291. location.loc:=LOC_MEM;
  292. case tstringdef(resulttype.def).string_typ of
  293. st_shortstring :
  294. begin
  295. gettempofsizereference(256,location.reference);
  296. loadshortstring(left,self);
  297. end;
  298. { the rest is removed in the resulttype pass and coverted to compilerprocs }
  299. else
  300. internalerror(4179);
  301. end;
  302. end;
  303. procedure ti386typeconvnode.second_int_to_real;
  304. var
  305. r : preference;
  306. hregister : tregister;
  307. l1,l2 : tasmlabel;
  308. begin
  309. { for u32bit a solution is to push $0 and to load a comp }
  310. { does this first, it destroys maybe EDI }
  311. hregister:=R_EDI;
  312. if torddef(left.resulttype.def).typ=u32bit then
  313. push_int(0);
  314. if (left.location.loc=LOC_REGISTER) or
  315. (left.location.loc=LOC_CREGISTER) then
  316. begin
  317. if not (torddef(left.resulttype.def).typ in [u32bit,s32bit,u64bit,s64bit]) then
  318. getexplicitregister32(R_EDI);
  319. case torddef(left.resulttype.def).typ of
  320. s8bit : emit_reg_reg(A_MOVSX,S_BL,left.location.register,R_EDI);
  321. u8bit : emit_reg_reg(A_MOVZX,S_BL,left.location.register,R_EDI);
  322. s16bit : emit_reg_reg(A_MOVSX,S_WL,left.location.register,R_EDI);
  323. u16bit : emit_reg_reg(A_MOVZX,S_WL,left.location.register,R_EDI);
  324. u32bit,s32bit:
  325. hregister:=left.location.register;
  326. u64bit,s64bit:
  327. begin
  328. emit_reg(A_PUSH,S_L,left.location.registerhigh);
  329. hregister:=left.location.registerlow;
  330. end;
  331. end;
  332. ungetregister(left.location.register);
  333. end
  334. else
  335. begin
  336. r:=newreference(left.location.reference);
  337. getexplicitregister32(R_EDI);
  338. case torddef(left.resulttype.def).typ of
  339. s8bit:
  340. emit_ref_reg(A_MOVSX,S_BL,r,R_EDI);
  341. u8bit:
  342. emit_ref_reg(A_MOVZX,S_BL,r,R_EDI);
  343. s16bit:
  344. emit_ref_reg(A_MOVSX,S_WL,r,R_EDI);
  345. u16bit:
  346. emit_ref_reg(A_MOVZX,S_WL,r,R_EDI);
  347. u32bit,s32bit:
  348. emit_ref_reg(A_MOV,S_L,r,R_EDI);
  349. u64bit,s64bit:
  350. begin
  351. inc(r^.offset,4);
  352. emit_ref_reg(A_MOV,S_L,r,R_EDI);
  353. emit_reg(A_PUSH,S_L,R_EDI);
  354. r:=newreference(left.location.reference);
  355. emit_ref_reg(A_MOV,S_L,r,R_EDI);
  356. end;
  357. end;
  358. del_reference(left.location.reference);
  359. ungetiftemp(left.location.reference);
  360. end;
  361. { for 64 bit integers, the high dword is already pushed }
  362. emit_reg(A_PUSH,S_L,hregister);
  363. if hregister = R_EDI then
  364. ungetregister32(R_EDI);
  365. r:=new_reference(R_ESP,0);
  366. case torddef(left.resulttype.def).typ of
  367. u32bit:
  368. begin
  369. emit_ref(A_FILD,S_IQ,r);
  370. emit_const_reg(A_ADD,S_L,8,R_ESP);
  371. end;
  372. s64bit:
  373. begin
  374. emit_ref(A_FILD,S_IQ,r);
  375. emit_const_reg(A_ADD,S_L,8,R_ESP);
  376. end;
  377. u64bit:
  378. begin
  379. { unsigned 64 bit ints are harder to handle: }
  380. { we load bits 0..62 and then check bit 63: }
  381. { if it is 1 then we add $80000000 000000000 }
  382. { as double }
  383. inc(r^.offset,4);
  384. getexplicitregister32(R_EDI);
  385. emit_ref_reg(A_MOV,S_L,r,R_EDI);
  386. r:=new_reference(R_ESP,4);
  387. emit_const_ref(A_AND,S_L,$7fffffff,r);
  388. emit_const_reg(A_TEST,S_L,longint($80000000),R_EDI);
  389. ungetregister32(R_EDI);
  390. r:=new_reference(R_ESP,0);
  391. emit_ref(A_FILD,S_IQ,r);
  392. getdatalabel(l1);
  393. getlabel(l2);
  394. emitjmp(C_Z,l2);
  395. Consts.concat(Tai_label.Create(l1));
  396. { I got this constant from a test progtram (FK) }
  397. Consts.concat(Tai_const.Create_32bit(0));
  398. Consts.concat(Tai_const.Create_32bit(1138753536));
  399. r:=new_reference(R_NO,0);
  400. r^.symbol:=l1;
  401. emit_ref(A_FADD,S_FL,r);
  402. emitlab(l2);
  403. emit_const_reg(A_ADD,S_L,8,R_ESP);
  404. end
  405. else
  406. begin
  407. emit_ref(A_FILD,S_IL,r);
  408. getexplicitregister32(R_EDI);
  409. emit_reg(A_POP,S_L,R_EDI);
  410. ungetregister32(R_EDI);
  411. end;
  412. end;
  413. inc(fpuvaroffset);
  414. clear_location(location);
  415. location.loc:=LOC_FPU;
  416. end;
  417. procedure ti386typeconvnode.second_real_to_real;
  418. begin
  419. case left.location.loc of
  420. LOC_FPU : ;
  421. LOC_CFPUREGISTER:
  422. begin
  423. location:=left.location;
  424. exit;
  425. end;
  426. LOC_MEM,
  427. LOC_REFERENCE:
  428. begin
  429. floatload(tfloatdef(left.resulttype.def).typ,
  430. left.location.reference);
  431. { we have to free the reference }
  432. del_reference(left.location.reference);
  433. end;
  434. end;
  435. clear_location(location);
  436. location.loc:=LOC_FPU;
  437. end;
  438. procedure ti386typeconvnode.second_cord_to_pointer;
  439. begin
  440. { this can't happend, because constants are already processed in
  441. pass 1 }
  442. internalerror(47423985);
  443. end;
  444. procedure ti386typeconvnode.second_proc_to_procvar;
  445. begin
  446. { method pointer ? }
  447. if assigned(tcallnode(left).left) then
  448. begin
  449. set_location(location,left.location);
  450. end
  451. else
  452. begin
  453. clear_location(location);
  454. location.loc:=LOC_REGISTER;
  455. location.register:=getregister32;
  456. del_reference(left.location.reference);
  457. emit_ref_reg(A_LEA,S_L,
  458. newreference(left.location.reference),location.register);
  459. end;
  460. end;
  461. procedure ti386typeconvnode.second_bool_to_int;
  462. var
  463. oldtruelabel,oldfalselabel,hlabel : tasmlabel;
  464. hregister : tregister;
  465. newsize,
  466. opsize : topsize;
  467. op : tasmop;
  468. begin
  469. oldtruelabel:=truelabel;
  470. oldfalselabel:=falselabel;
  471. getlabel(truelabel);
  472. getlabel(falselabel);
  473. secondpass(left);
  474. { byte(boolean) or word(wordbool) or longint(longbool) must
  475. be accepted for var parameters }
  476. if (nf_explizit in flags) and
  477. (left.resulttype.def.size=resulttype.def.size) and
  478. (left.location.loc in [LOC_REFERENCE,LOC_MEM,LOC_CREGISTER]) then
  479. begin
  480. set_location(location,left.location);
  481. truelabel:=oldtruelabel;
  482. falselabel:=oldfalselabel;
  483. exit;
  484. end;
  485. clear_location(location);
  486. location.loc:=LOC_REGISTER;
  487. del_reference(left.location.reference);
  488. case left.resulttype.def.size of
  489. 1 : begin
  490. case resulttype.def.size of
  491. 1 : opsize:=S_B;
  492. 2 : opsize:=S_BW;
  493. 4 : opsize:=S_BL;
  494. end;
  495. end;
  496. 2 : begin
  497. case resulttype.def.size of
  498. 1 : begin
  499. if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  500. left.location.register:=reg16toreg8(left.location.register);
  501. opsize:=S_B;
  502. end;
  503. 2 : opsize:=S_W;
  504. 4 : opsize:=S_WL;
  505. end;
  506. end;
  507. 4 : begin
  508. case resulttype.def.size of
  509. 1 : begin
  510. if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  511. left.location.register:=reg32toreg8(left.location.register);
  512. opsize:=S_B;
  513. end;
  514. 2 : begin
  515. if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  516. left.location.register:=reg32toreg16(left.location.register);
  517. opsize:=S_W;
  518. end;
  519. 4 : opsize:=S_L;
  520. end;
  521. end;
  522. end;
  523. if opsize in [S_B,S_W,S_L] then
  524. op:=A_MOV
  525. else
  526. if is_signed(resulttype.def) then
  527. op:=A_MOVSX
  528. else
  529. op:=A_MOVZX;
  530. hregister:=getregister32;
  531. case resulttype.def.size of
  532. 1 : begin
  533. location.register:=reg32toreg8(hregister);
  534. newsize:=S_B;
  535. end;
  536. 2 : begin
  537. location.register:=reg32toreg16(hregister);
  538. newsize:=S_W;
  539. end;
  540. 4 : begin
  541. location.register:=hregister;
  542. newsize:=S_L;
  543. end;
  544. else
  545. internalerror(10060);
  546. end;
  547. case left.location.loc of
  548. LOC_MEM,
  549. LOC_REFERENCE : emit_ref_reg(op,opsize,
  550. newreference(left.location.reference),location.register);
  551. LOC_REGISTER,
  552. LOC_CREGISTER : begin
  553. { remove things like movb %al,%al }
  554. if left.location.register<>location.register then
  555. emit_reg_reg(op,opsize,
  556. left.location.register,location.register);
  557. end;
  558. LOC_FLAGS : begin
  559. emit_flag2reg(left.location.resflags,location.register);
  560. end;
  561. LOC_JUMP : begin
  562. getlabel(hlabel);
  563. emitlab(truelabel);
  564. emit_const_reg(A_MOV,newsize,1,location.register);
  565. emitjmp(C_None,hlabel);
  566. emitlab(falselabel);
  567. emit_reg_reg(A_XOR,newsize,location.register,
  568. location.register);
  569. emitlab(hlabel);
  570. end;
  571. else
  572. internalerror(10061);
  573. end;
  574. truelabel:=oldtruelabel;
  575. falselabel:=oldfalselabel;
  576. end;
  577. procedure ti386typeconvnode.second_int_to_bool;
  578. var
  579. hregister : tregister;
  580. resflags : tresflags;
  581. opsize : topsize;
  582. begin
  583. clear_location(location);
  584. { byte(boolean) or word(wordbool) or longint(longbool) must
  585. be accepted for var parameters }
  586. if (nf_explizit in flags) and
  587. (left.resulttype.def.size=resulttype.def.size) and
  588. (left.location.loc in [LOC_REFERENCE,LOC_MEM,LOC_CREGISTER]) then
  589. begin
  590. set_location(location,left.location);
  591. exit;
  592. end;
  593. location.loc:=LOC_REGISTER;
  594. del_reference(left.location.reference);
  595. opsize:=def_opsize(left.resulttype.def);
  596. case left.location.loc of
  597. LOC_MEM,LOC_REFERENCE :
  598. begin
  599. hregister:=def_getreg(left.resulttype.def);
  600. emit_ref_reg(A_MOV,opsize,
  601. newreference(left.location.reference),hregister);
  602. emit_reg_reg(A_OR,opsize,hregister,hregister);
  603. resflags:=F_NE;
  604. end;
  605. LOC_FLAGS :
  606. begin
  607. hregister:=getregister32;
  608. resflags:=left.location.resflags;
  609. end;
  610. LOC_REGISTER,LOC_CREGISTER :
  611. begin
  612. hregister:=left.location.register;
  613. emit_reg_reg(A_OR,opsize,hregister,hregister);
  614. resflags:=F_NE;
  615. end;
  616. else
  617. internalerror(10062);
  618. end;
  619. case resulttype.def.size of
  620. 1 : location.register:=makereg8(hregister);
  621. 2 : location.register:=makereg16(hregister);
  622. 4 : location.register:=makereg32(hregister);
  623. else
  624. internalerror(10064);
  625. end;
  626. emit_flag2reg(resflags,location.register);
  627. end;
  628. procedure ti386typeconvnode.second_load_smallset;
  629. var
  630. href : treference;
  631. pushedregs : tpushed;
  632. begin
  633. href.symbol:=nil;
  634. pushusedregisters(pushedregs,$ff);
  635. gettempofsizereference(32,href);
  636. emit_push_mem_size(left.location.reference,4);
  637. emitpushreferenceaddr(href);
  638. saveregvars($ff);
  639. emitcall('FPC_SET_LOAD_SMALL');
  640. maybe_loadself;
  641. popusedregisters(pushedregs);
  642. clear_location(location);
  643. location.loc:=LOC_MEM;
  644. location.reference:=href;
  645. end;
  646. procedure ti386typeconvnode.second_ansistring_to_pchar;
  647. var
  648. l1 : tasmlabel;
  649. hr : preference;
  650. begin
  651. clear_location(location);
  652. location.loc:=LOC_REGISTER;
  653. getlabel(l1);
  654. case left.location.loc of
  655. LOC_CREGISTER,LOC_REGISTER:
  656. location.register:=left.location.register;
  657. LOC_MEM,LOC_REFERENCE:
  658. begin
  659. location.register:=getregister32;
  660. emit_ref_reg(A_MOV,S_L,newreference(left.location.reference),
  661. location.register);
  662. del_reference(left.location.reference);
  663. end;
  664. end;
  665. emit_const_reg(A_CMP,S_L,0,location.register);
  666. emitjmp(C_NZ,l1);
  667. new(hr);
  668. reset_reference(hr^);
  669. hr^.symbol:=newasmsymbol('FPC_EMPTYCHAR');
  670. emit_ref_reg(A_LEA,S_L,hr,location.register);
  671. emitlab(l1);
  672. end;
  673. procedure ti386typeconvnode.second_class_to_intf;
  674. var
  675. hreg : tregister;
  676. l1 : tasmlabel;
  677. begin
  678. case left.location.loc of
  679. LOC_MEM,
  680. LOC_REFERENCE:
  681. begin
  682. del_reference(left.location.reference);
  683. hreg:=getregister32;
  684. exprasmList.concat(Taicpu.Op_ref_reg(
  685. A_MOV,S_L,newreference(left.location.reference),hreg));
  686. end;
  687. LOC_CREGISTER:
  688. begin
  689. hreg:=getregister32;
  690. exprasmList.concat(Taicpu.Op_reg_reg(
  691. A_MOV,S_L,left.location.register,hreg));
  692. end;
  693. LOC_REGISTER:
  694. hreg:=left.location.register;
  695. else internalerror(121120001);
  696. end;
  697. emit_reg_reg(A_TEST,S_L,hreg,hreg);
  698. getlabel(l1);
  699. emitjmp(C_Z,l1);
  700. emit_const_reg(A_ADD,S_L,tobjectdef(left.resulttype.def).implementedinterfaces.ioffsets(
  701. tobjectdef(left.resulttype.def).implementedinterfaces.searchintf(resulttype.def))^,hreg);
  702. emitlab(l1);
  703. location.loc:=LOC_REGISTER;
  704. location.register:=hreg;
  705. end;
  706. procedure ti386typeconvnode.second_char_to_char;
  707. begin
  708. {$warning todo: add RTL routine for widechar-char conversion }
  709. { Quick hack to atleast generate 'working' code (PFV) }
  710. second_int_to_int;
  711. end;
  712. procedure ti386typeconvnode.second_nothing;
  713. begin
  714. end;
  715. {****************************************************************************
  716. TI386TYPECONVNODE
  717. ****************************************************************************}
  718. procedure ti386typeconvnode.second_call_helper(c : tconverttype);
  719. const
  720. secondconvert : array[tconverttype] of pointer = (
  721. @ti386typeconvnode.second_nothing, {equal}
  722. @ti386typeconvnode.second_nothing, {not_possible}
  723. @ti386typeconvnode.second_nothing, {second_string_to_string, handled in resulttype pass }
  724. @ti386typeconvnode.second_char_to_string,
  725. @ti386typeconvnode.second_nothing, { pchar_to_string, handled in resulttype pass }
  726. @ti386typeconvnode.second_nothing, {cchar_to_pchar}
  727. @ti386typeconvnode.second_cstring_to_pchar,
  728. @ti386typeconvnode.second_ansistring_to_pchar,
  729. @ti386typeconvnode.second_string_to_chararray,
  730. @ti386typeconvnode.second_nothing, { chararray_to_string, handled in resulttype pass }
  731. @ti386typeconvnode.second_array_to_pointer,
  732. @ti386typeconvnode.second_pointer_to_array,
  733. @ti386typeconvnode.second_int_to_int,
  734. @ti386typeconvnode.second_int_to_bool,
  735. @ti386typeconvnode.second_bool_to_int, { bool_to_bool }
  736. @ti386typeconvnode.second_bool_to_int,
  737. @ti386typeconvnode.second_real_to_real,
  738. @ti386typeconvnode.second_int_to_real,
  739. @ti386typeconvnode.second_proc_to_procvar,
  740. @ti386typeconvnode.second_nothing, {arrayconstructor_to_set}
  741. @ti386typeconvnode.second_load_smallset,
  742. @ti386typeconvnode.second_cord_to_pointer,
  743. @ti386typeconvnode.second_nothing, { interface 2 string }
  744. @ti386typeconvnode.second_nothing, { interface 2 guid }
  745. @ti386typeconvnode.second_class_to_intf,
  746. @ti386typeconvnode.second_char_to_char,
  747. @ti386typeconvnode.second_nothing { normal_2_smallset }
  748. );
  749. type
  750. tprocedureofobject = procedure of object;
  751. var
  752. r : packed record
  753. proc : pointer;
  754. obj : pointer;
  755. end;
  756. begin
  757. { this is a little bit dirty but it works }
  758. { and should be quite portable too }
  759. r.proc:=secondconvert[c];
  760. r.obj:=self;
  761. tprocedureofobject(r){$ifdef FPC}();{$endif FPC}
  762. end;
  763. procedure ti386typeconvnode.pass_2;
  764. {$ifdef TESTOBJEXT2}
  765. var
  766. r : preference;
  767. nillabel : plabel;
  768. {$endif TESTOBJEXT2}
  769. begin
  770. { this isn't good coding, I think tc_bool_2_int, shouldn't be }
  771. { type conversion (FK) }
  772. if not(convtype in [tc_bool_2_int,tc_bool_2_bool]) then
  773. begin
  774. secondpass(left);
  775. set_location(location,left.location);
  776. if codegenerror then
  777. exit;
  778. end;
  779. second_call_helper(convtype);
  780. {$ifdef TESTOBJEXT2}
  781. { Check explicit conversions to objects pointers !! }
  782. if p^.explizit and
  783. (p^.resulttype.def.deftype=pointerdef) and
  784. (tpointerdef(p^.resulttype.def).definition.deftype=objectdef) and not
  785. (tobjectdef(tpointerdef(p^.resulttype.def).definition).isclass) and
  786. ((tobjectdef(tpointerdef(p^.resulttype.def).definition).options and oo_hasvmt)<>0) and
  787. (cs_check_range in aktlocalswitches) then
  788. begin
  789. new(r);
  790. reset_reference(r^);
  791. if p^.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  792. r^.base:=p^.location.register
  793. else
  794. begin
  795. getexplicitregister32(R_EDI);
  796. emit_mov_loc_reg(p^.location,R_EDI);
  797. r^.base:=R_EDI;
  798. end;
  799. { NIL must be accepted !! }
  800. emit_reg_reg(A_OR,S_L,r^.base,r^.base);
  801. ungetregister32(R_EDI);
  802. getlabel(nillabel);
  803. emitjmp(C_E,nillabel);
  804. { this is one point where we need vmt_offset (PM) }
  805. r^.offset:= tobjectdef(tpointerdef(p^.resulttype.def).definition).vmt_offset;
  806. getexplicitregister32(R_EDI);
  807. emit_ref_reg(A_MOV,S_L,r,R_EDI);
  808. emit_sym(A_PUSH,S_L,
  809. newasmsymbol(tobjectdef(tpointerdef(p^.resulttype.def).definition).vmt_mangledname));
  810. emit_reg(A_PUSH,S_L,R_EDI);
  811. ungetregister32(R_EDI);
  812. emitcall('FPC_CHECK_OBJECT_EXT');
  813. emitlab(nillabel);
  814. end;
  815. {$endif TESTOBJEXT2}
  816. end;
  817. {*****************************************************************************
  818. TI386ISNODE
  819. *****************************************************************************}
  820. procedure ti386isnode.pass_2;
  821. var
  822. pushed : tpushed;
  823. begin
  824. { save all used registers }
  825. pushusedregisters(pushed,$ff);
  826. secondpass(left);
  827. clear_location(location);
  828. location.loc:=LOC_FLAGS;
  829. location.resflags:=F_NE;
  830. { push instance to check: }
  831. case left.location.loc of
  832. LOC_REGISTER,LOC_CREGISTER:
  833. begin
  834. emit_reg(A_PUSH,
  835. S_L,left.location.register);
  836. ungetregister32(left.location.register);
  837. end;
  838. LOC_MEM,LOC_REFERENCE:
  839. begin
  840. emit_ref(A_PUSH,
  841. S_L,newreference(left.location.reference));
  842. del_reference(left.location.reference);
  843. end;
  844. else internalerror(100);
  845. end;
  846. { generate type checking }
  847. secondpass(right);
  848. case right.location.loc of
  849. LOC_REGISTER,LOC_CREGISTER:
  850. begin
  851. emit_reg(A_PUSH,
  852. S_L,right.location.register);
  853. ungetregister32(right.location.register);
  854. end;
  855. LOC_MEM,LOC_REFERENCE:
  856. begin
  857. emit_ref(A_PUSH,
  858. S_L,newreference(right.location.reference));
  859. del_reference(right.location.reference);
  860. end;
  861. else internalerror(100);
  862. end;
  863. saveregvars($ff);
  864. emitcall('FPC_DO_IS');
  865. emit_reg_reg(A_OR,S_B,R_AL,R_AL);
  866. popusedregisters(pushed);
  867. maybe_loadself;
  868. end;
  869. {*****************************************************************************
  870. TI386ASNODE
  871. *****************************************************************************}
  872. procedure ti386asnode.pass_2;
  873. var
  874. pushed : tpushed;
  875. begin
  876. secondpass(left);
  877. { save all used registers }
  878. pushusedregisters(pushed,$ff);
  879. { push instance to check: }
  880. case left.location.loc of
  881. LOC_REGISTER,LOC_CREGISTER:
  882. emit_reg(A_PUSH,
  883. S_L,left.location.register);
  884. LOC_MEM,LOC_REFERENCE:
  885. emit_ref(A_PUSH,
  886. S_L,newreference(left.location.reference));
  887. else internalerror(100);
  888. end;
  889. { we doesn't modifiy the left side, we check only the type }
  890. set_location(location,left.location);
  891. { generate type checking }
  892. secondpass(right);
  893. case right.location.loc of
  894. LOC_REGISTER,LOC_CREGISTER:
  895. begin
  896. emit_reg(A_PUSH,
  897. S_L,right.location.register);
  898. ungetregister32(right.location.register);
  899. end;
  900. LOC_MEM,LOC_REFERENCE:
  901. begin
  902. emit_ref(A_PUSH,
  903. S_L,newreference(right.location.reference));
  904. del_reference(right.location.reference);
  905. end;
  906. else internalerror(100);
  907. end;
  908. saveregvars($ff);
  909. emitcall('FPC_DO_AS');
  910. { restore register, this restores automatically the }
  911. { result }
  912. popusedregisters(pushed);
  913. maybe_loadself;
  914. end;
  915. begin
  916. ctypeconvnode:=ti386typeconvnode;
  917. cisnode:=ti386isnode;
  918. casnode:=ti386asnode;
  919. end.
  920. {
  921. $Log$
  922. Revision 1.23 2001-09-03 13:27:42 jonas
  923. * compilerproc implementation of set addition/substraction/...
  924. * changed the declaration of some set helpers somewhat to accomodate the
  925. above change
  926. * i386 still uses the old code for comparisons of sets, because its
  927. helpers return the results in the flags
  928. * dummy tc_normal_2_small_set type conversion because I need the original
  929. resulttype of the set add nodes
  930. NOTE: you have to start a cycle with 1.0.5!
  931. Revision 1.22 2001/08/29 19:49:03 jonas
  932. * some fixes in compilerprocs for chararray to string conversions
  933. * conversion from string to chararray is now also done via compilerprocs
  934. Revision 1.21 2001/08/28 13:24:47 jonas
  935. + compilerproc implementation of most string-related type conversions
  936. - removed all code from the compiler which has been replaced by
  937. compilerproc implementations (using {$ifdef hascompilerproc} is not
  938. necessary in the compiler)
  939. Revision 1.20 2001/08/26 13:36:57 florian
  940. * some cg reorganisation
  941. * some PPC updates
  942. Revision 1.19 2001/08/01 21:44:59 peter
  943. * fixed empty pwidechar register allocation
  944. Revision 1.18 2001/07/30 20:59:29 peter
  945. * m68k updates from v10 merged
  946. Revision 1.17 2001/07/16 13:19:08 jonas
  947. * fixed allocation of register before release in second_cstring_to_pchar
  948. Revision 1.16 2001/07/08 21:00:17 peter
  949. * various widestring updates, it works now mostly without charset
  950. mapping supported
  951. Revision 1.15 2001/05/08 21:06:33 florian
  952. * some more support for widechars commited especially
  953. regarding type casting and constants
  954. Revision 1.14 2001/04/13 01:22:18 peter
  955. * symtable change to classes
  956. * range check generation and errors fixed, make cycle DEBUG=1 works
  957. * memory leaks fixed
  958. Revision 1.13 2001/04/02 21:20:36 peter
  959. * resulttype rewrite
  960. Revision 1.12 2001/01/08 21:45:11 peter
  961. * internalerror for string to chararray
  962. Revision 1.11 2000/12/25 00:07:32 peter
  963. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  964. tlinkedlist objects)
  965. Revision 1.10 2000/12/07 17:19:46 jonas
  966. * new constant handling: from now on, hex constants >$7fffffff are
  967. parsed as unsigned constants (otherwise, $80000000 got sign extended
  968. and became $ffffffff80000000), all constants in the longint range
  969. become longints, all constants >$7fffffff and <=cardinal($ffffffff)
  970. are cardinals and the rest are int64's.
  971. * added lots of longint typecast to prevent range check errors in the
  972. compiler and rtl
  973. * type casts of symbolic ordinal constants are now preserved
  974. * fixed bug where the original resulttype.def wasn't restored correctly
  975. after doing a 64bit rangecheck
  976. Revision 1.9 2000/12/05 11:44:33 jonas
  977. + new integer regvar handling, should be much more efficient
  978. Revision 1.8 2000/11/29 00:30:46 florian
  979. * unused units removed from uses clause
  980. * some changes for widestrings
  981. Revision 1.7 2000/11/16 15:27:48 jonas
  982. * fixed web bug 1242
  983. Revision 1.6 2000/11/13 11:30:56 florian
  984. * some bugs with interfaces and NIL fixed
  985. Revision 1.5 2000/11/12 23:24:14 florian
  986. * interfaces are basically running
  987. Revision 1.4 2000/11/11 16:00:10 jonas
  988. * optimize converting of 8/16/32 bit constants to 64bit ones
  989. Revision 1.3 2000/11/04 14:25:23 florian
  990. + merged Attila's changes for interfaces, not tested yet
  991. Revision 1.2 2000/10/31 22:02:56 peter
  992. * symtable splitted, no real code changes
  993. Revision 1.1 2000/10/15 09:33:31 peter
  994. * moved n386*.pas to i386/ cpu_target dir
  995. Revision 1.1 2000/10/14 10:14:48 peter
  996. * moehrendorf oct 2000 rewrite
  997. }