cg386cnv.pas 57 KB

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