n386ld.pas 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. Generate i386 assembler for load/assignment 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 n386ld;
  19. {$i defines.inc}
  20. interface
  21. uses
  22. node,nld;
  23. type
  24. ti386loadnode = class(tloadnode)
  25. procedure pass_2;override;
  26. end;
  27. ti386assignmentnode = class(tassignmentnode)
  28. procedure pass_2;override;
  29. end;
  30. ti386funcretnode = class(tfuncretnode)
  31. procedure pass_2;override;
  32. end;
  33. ti386arrayconstructornode = class(tarrayconstructornode)
  34. procedure pass_2;override;
  35. end;
  36. implementation
  37. uses
  38. systems,
  39. verbose,globals,
  40. symconst,symtype,symdef,symsym,symtable,aasm,types,
  41. cgbase,temp_gen,pass_2,
  42. nmem,ncon,ncnv,
  43. cpubase,cpuasm,
  44. cga,tgcpu,n386cnv,n386util,regvars;
  45. {*****************************************************************************
  46. SecondLoad
  47. *****************************************************************************}
  48. procedure ti386loadnode.pass_2;
  49. var
  50. hregister : tregister;
  51. symtabletype : tsymtabletype;
  52. i : longint;
  53. hp : preference;
  54. s : tasmsymbol;
  55. popeax : boolean;
  56. //pushed : tpushed;
  57. //hr : treference;
  58. begin
  59. simple_loadn:=true;
  60. reset_reference(location.reference);
  61. case symtableentry.typ of
  62. { this is only for toasm and toaddr }
  63. absolutesym :
  64. begin
  65. location.reference.symbol:=nil;
  66. if (tabsolutesym(symtableentry).abstyp=toaddr) then
  67. begin
  68. if tabsolutesym(symtableentry).absseg then
  69. location.reference.segment:=R_FS;
  70. location.reference.offset:=tabsolutesym(symtableentry).address;
  71. end
  72. else
  73. location.reference.symbol:=newasmsymbol(tabsolutesym(symtableentry).mangledname);
  74. end;
  75. constsym:
  76. begin
  77. if tconstsym(symtableentry).consttyp=constresourcestring then
  78. begin
  79. location.loc:=LOC_MEM;
  80. location.reference.symbol:=newasmsymbol(tconstsym(symtableentry).owner.name^+'_RESOURCESTRINGLIST');
  81. location.reference.offset:=tconstsym(symtableentry).resstrindex*16+8;
  82. end
  83. else
  84. internalerror(22798);
  85. end;
  86. varsym :
  87. begin
  88. hregister:=R_NO;
  89. { C variable }
  90. if (vo_is_C_var in tvarsym(symtableentry).varoptions) then
  91. begin
  92. location.reference.symbol:=newasmsymbol(tvarsym(symtableentry).mangledname);
  93. end
  94. { DLL variable }
  95. else if (vo_is_dll_var in tvarsym(symtableentry).varoptions) then
  96. begin
  97. hregister:=getregisterint;
  98. location.reference.symbol:=newasmsymbol(tvarsym(symtableentry).mangledname);
  99. emit_ref_reg(A_MOV,S_L,newreference(location.reference),hregister);
  100. location.reference.symbol:=nil;
  101. location.reference.base:=hregister;
  102. end
  103. { external variable }
  104. else if (vo_is_external in tvarsym(symtableentry).varoptions) then
  105. begin
  106. location.reference.symbol:=newasmsymbol(tvarsym(symtableentry).mangledname);
  107. end
  108. { thread variable }
  109. else if (vo_is_thread_var in tvarsym(symtableentry).varoptions) then
  110. begin
  111. popeax:=not(R_EAX in unused);
  112. if popeax then
  113. emit_reg(A_PUSH,S_L,R_EAX);
  114. location.reference.symbol:=newasmsymbol(tvarsym(symtableentry).mangledname);
  115. emit_ref(A_PUSH,S_L,newreference(location.reference));
  116. { the called procedure isn't allowed to change }
  117. { any register except EAX }
  118. emitcall('FPC_RELOCATE_THREADVAR');
  119. reset_reference(location.reference);
  120. location.reference.base:=getregisterint;
  121. emit_reg_reg(A_MOV,S_L,R_EAX,location.reference.base);
  122. if popeax then
  123. emit_reg(A_POP,S_L,R_EAX);
  124. end
  125. { normal variable }
  126. else
  127. begin
  128. symtabletype:=symtable.symtabletype;
  129. { in case it is a register variable: }
  130. if tvarsym(symtableentry).reg<>R_NO then
  131. begin
  132. if tvarsym(symtableentry).reg in [R_ST0..R_ST7] then
  133. begin
  134. location.loc:=LOC_CFPUREGISTER;
  135. location.register:=tvarsym(symtableentry).reg;
  136. end
  137. else
  138. if not(makereg32(tvarsym(symtableentry).reg) in [R_EAX..R_EBX]) or
  139. regvar_loaded[tvarsym(symtableentry).reg] then
  140. begin
  141. location.loc:=LOC_CREGISTER;
  142. location.register:=tvarsym(symtableentry).reg;
  143. unused:=unused-[tvarsym(symtableentry).reg];
  144. end
  145. else
  146. begin
  147. load_regvar(exprasmlist,tvarsym(symtableentry));
  148. location.loc:=LOC_CREGISTER;
  149. location.register:=tvarsym(symtableentry).reg;
  150. unused:=unused-[tvarsym(symtableentry).reg];
  151. end
  152. end
  153. else
  154. begin
  155. { first handle local and temporary variables }
  156. if (symtabletype in [parasymtable,inlinelocalsymtable,
  157. inlineparasymtable,localsymtable]) then
  158. begin
  159. location.reference.base:=procinfo^.framepointer;
  160. if (symtabletype in [inlinelocalsymtable,
  161. localsymtable]) then
  162. location.reference.offset:=
  163. tvarsym(symtableentry).address-symtable.address_fixup
  164. else
  165. location.reference.offset:=
  166. tvarsym(symtableentry).address+symtable.address_fixup;
  167. if (symtabletype in [localsymtable,inlinelocalsymtable]) then
  168. begin
  169. if use_esp_stackframe then
  170. dec(location.reference.offset,
  171. tvarsym(symtableentry).getvaluesize)
  172. else
  173. location.reference.offset:=-location.reference.offset;
  174. end;
  175. if (lexlevel>(symtable.symtablelevel)) then
  176. begin
  177. hregister:=getregisterint;
  178. { make a reference }
  179. hp:=new_reference(procinfo^.framepointer,
  180. procinfo^.framepointer_offset);
  181. emit_ref_reg(A_MOV,S_L,hp,hregister);
  182. simple_loadn:=false;
  183. i:=lexlevel-1;
  184. while i>(symtable.symtablelevel) do
  185. begin
  186. { make a reference }
  187. hp:=new_reference(hregister,8);
  188. emit_ref_reg(A_MOV,S_L,hp,hregister);
  189. dec(i);
  190. end;
  191. location.reference.base:=hregister;
  192. end;
  193. end
  194. else
  195. case symtabletype of
  196. globalsymtable,
  197. staticsymtable :
  198. begin
  199. location.reference.symbol:=newasmsymbol(tvarsym(symtableentry).mangledname);
  200. end;
  201. stt_exceptsymtable:
  202. begin
  203. location.reference.base:=procinfo^.framepointer;
  204. location.reference.offset:=tvarsym(symtableentry).address;
  205. end;
  206. objectsymtable:
  207. begin
  208. getexplicitregister32(R_ESI);
  209. if (sp_static in tvarsym(symtableentry).symoptions) then
  210. begin
  211. location.reference.symbol:=newasmsymbol(tvarsym(symtableentry).mangledname);
  212. end
  213. else
  214. begin
  215. location.reference.base:=R_ESI;
  216. location.reference.offset:=tvarsym(symtableentry).address;
  217. end;
  218. end;
  219. withsymtable:
  220. begin
  221. { make a reference }
  222. { symtable datasize field
  223. contains the offset of the temp
  224. stored }
  225. { hp:=new_reference(procinfo^.framepointer,
  226. symtable.datasize);
  227. emit_ref_reg(A_MOV,S_L,hp,hregister);}
  228. if nf_islocal in tnode(twithsymtable(symtable).withnode).flags then
  229. begin
  230. location.reference:=twithnode(twithsymtable(symtable).withnode).withreference^;
  231. end
  232. else
  233. begin
  234. hregister:=getregisterint;
  235. location.reference.base:=hregister;
  236. emit_ref_reg(A_MOV,S_L,
  237. newreference(twithnode(twithsymtable(symtable).withnode).withreference^),
  238. hregister);
  239. end;
  240. inc(location.reference.offset,tvarsym(symtableentry).address);
  241. end;
  242. end;
  243. end;
  244. { in case call by reference, then calculate. Open array
  245. is always an reference! }
  246. if (tvarsym(symtableentry).varspez in [vs_var,vs_out]) or
  247. is_open_array(tvarsym(symtableentry).vartype.def) or
  248. is_array_of_const(tvarsym(symtableentry).vartype.def) or
  249. ((tvarsym(symtableentry).varspez=vs_const) and
  250. push_addr_param(tvarsym(symtableentry).vartype.def)) then
  251. begin
  252. simple_loadn:=false;
  253. if hregister=R_NO then
  254. hregister:=getregisterint;
  255. if location.loc=LOC_CREGISTER then
  256. begin
  257. emit_reg_reg(A_MOV,S_L,
  258. location.register,hregister);
  259. location.loc:=LOC_REFERENCE;
  260. end
  261. else
  262. begin
  263. emit_ref_reg(A_MOV,S_L,
  264. newreference(location.reference),
  265. hregister);
  266. end;
  267. reset_reference(location.reference);
  268. location.reference.base:=hregister;
  269. end;
  270. end;
  271. end;
  272. procsym:
  273. begin
  274. if assigned(left) then
  275. begin
  276. location.loc:=LOC_MEM;
  277. gettempofsizereference(8,location.reference);
  278. if left.nodetype=typen then
  279. begin
  280. if left.resulttype.def.deftype<>objectdef then
  281. internalerror(200103261);
  282. getexplicitregister32(R_EDI);
  283. hregister:=R_EDI;
  284. new(hp);
  285. emit_sym_ofs_reg(A_MOV,S_L,
  286. newasmsymbol(tobjectdef(left.resulttype.def).vmt_mangledname),0,R_EDI);
  287. end
  288. else
  289. begin
  290. secondpass(left);
  291. { load class instance address }
  292. case left.location.loc of
  293. LOC_CREGISTER,
  294. LOC_REGISTER:
  295. begin
  296. hregister:=left.location.register;
  297. ungetregister32(left.location.register);
  298. if is_object(left.resulttype.def) then
  299. CGMessage(cg_e_illegal_expression);
  300. end;
  301. LOC_MEM,
  302. LOC_REFERENCE:
  303. begin
  304. getexplicitregister32(R_EDI);
  305. hregister:=R_EDI;
  306. if is_class_or_interface(left.resulttype.def) then
  307. emit_ref_reg(A_MOV,S_L,
  308. newreference(left.location.reference),R_EDI)
  309. else
  310. emit_ref_reg(A_LEA,S_L,
  311. newreference(left.location.reference),R_EDI);
  312. del_reference(left.location.reference);
  313. ungetiftemp(left.location.reference);
  314. end;
  315. else internalerror(26019);
  316. end;
  317. end;
  318. { store the class instance address }
  319. new(hp);
  320. hp^:=location.reference;
  321. inc(hp^.offset,4);
  322. emit_reg_ref(A_MOV,S_L,
  323. hregister,hp);
  324. { virtual method ? }
  325. if (po_virtualmethod in tprocdef(resulttype.def).procoptions) then
  326. begin
  327. new(hp);
  328. reset_reference(hp^);
  329. hp^.base:=hregister;
  330. { load vmt pointer }
  331. emit_ref_reg(A_MOV,S_L,
  332. hp,R_EDI);
  333. {$IfDef regallocfix}
  334. del_reference(hp^);
  335. {$EndIf regallocfix}
  336. { load method address }
  337. new(hp);
  338. reset_reference(hp^);
  339. hp^.base:=R_EDI;
  340. hp^.offset:=tprocdef(resulttype.def)._class.vmtmethodoffset(
  341. tprocdef(resulttype.def).extnumber);
  342. emit_ref_reg(A_MOV,S_L,
  343. hp,R_EDI);
  344. { ... and store it }
  345. emit_reg_ref(A_MOV,S_L,
  346. R_EDI,newreference(location.reference));
  347. ungetregister32(R_EDI);
  348. end
  349. else
  350. begin
  351. ungetregister32(R_EDI);
  352. s:=newasmsymbol(tprocdef(resulttype.def).mangledname);
  353. emit_sym_ofs_ref(A_MOV,S_L,s,0,
  354. newreference(location.reference));
  355. end;
  356. end
  357. else
  358. begin
  359. {!!!!! Be aware, work on virtual methods too }
  360. location.reference.symbol:=newasmsymbol(tprocdef(resulttype.def).mangledname);
  361. end;
  362. end;
  363. typedconstsym :
  364. begin
  365. location.reference.symbol:=newasmsymbol(ttypedconstsym(symtableentry).mangledname);
  366. end;
  367. else internalerror(4);
  368. end;
  369. end;
  370. {*****************************************************************************
  371. SecondAssignment
  372. *****************************************************************************}
  373. procedure ti386assignmentnode.pass_2;
  374. var
  375. opsize : topsize;
  376. otlabel,hlabel,oflabel : tasmlabel;
  377. fputyp : tfloattype;
  378. loc : tloc;
  379. r : preference;
  380. ai : taicpu;
  381. op : tasmop;
  382. pushed : boolean;
  383. regspushed : tpushed;
  384. regs_to_push: byte;
  385. ungettemp : boolean;
  386. begin
  387. otlabel:=truelabel;
  388. oflabel:=falselabel;
  389. getlabel(truelabel);
  390. getlabel(falselabel);
  391. { calculate left sides }
  392. { don't do it yet if it's a crgister (JM) }
  393. if not(nf_concat_string in flags) then
  394. secondpass(left);
  395. if codegenerror then
  396. exit;
  397. if not(left.location.loc in [LOC_REFERENCE,LOC_CFPUREGISTER,
  398. LOC_CREGISTER,LOC_CMMXREGISTER]) then
  399. begin
  400. CGMessage(cg_e_illegal_expression);
  401. exit;
  402. end;
  403. loc:=left.location.loc;
  404. { lets try to optimize this (PM) }
  405. { define a dest_loc that is the location }
  406. { and a ptree to verify that it is the right }
  407. { place to insert it }
  408. {$ifdef test_dest_loc}
  409. if (aktexprlevel<4) then
  410. begin
  411. dest_loc_known:=true;
  412. dest_loc:=left.location;
  413. dest_loc_tree:=right;
  414. end;
  415. {$endif test_dest_loc}
  416. { left can't be never a 64 bit LOC_REGISTER, so the 3. arg }
  417. { can be false }
  418. pushed:=maybe_push(right.registers32,left,false);
  419. secondpass(right);
  420. { restoring here is nonsense for LOC_JMP !! }
  421. { This generated code that was after a jmp and before any
  422. label => unreachable !!
  423. Could this be tested somehow ?? PM }
  424. if pushed and (right.location.loc <>LOC_JUMP) then
  425. restore(left,false);
  426. if codegenerror then
  427. exit;
  428. {$ifdef test_dest_loc}
  429. dest_loc_known:=false;
  430. if in_dest_loc then
  431. begin
  432. truelabel:=otlabel;
  433. falselabel:=oflabel;
  434. in_dest_loc:=false;
  435. exit;
  436. end;
  437. {$endif test_dest_loc}
  438. if left.resulttype.def.deftype=stringdef then
  439. begin
  440. if is_ansistring(left.resulttype.def) or
  441. is_widestring(left.resulttype.def) then
  442. begin
  443. { before pushing any parameter, we have to save all used }
  444. { registers, but before that we have to release the }
  445. { registers of that node to save uneccessary pushed }
  446. { so be careful, if you think you can optimize that code (FK) }
  447. { nevertheless, this has to be changed, because otherwise the }
  448. { register is released before it's contents are pushed -> }
  449. { problems with the optimizer (JM) }
  450. ungettemp:=false;
  451. { Find out which registers have to be pushed (JM) }
  452. regs_to_push := $ff;
  453. remove_non_regvars_from_loc(right.location,regs_to_push);
  454. remove_non_regvars_from_loc(left.location,regs_to_push);
  455. { And push them (JM) }
  456. pushusedregisters(regspushed,regs_to_push);
  457. case right.location.loc of
  458. LOC_REGISTER,LOC_CREGISTER:
  459. begin
  460. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,right.location.register));
  461. ungetregister32(right.location.register);
  462. end;
  463. LOC_REFERENCE,LOC_MEM:
  464. begin
  465. { First release the registers because emit_push_mem may }
  466. { load the reference in edi before pushing and then the }
  467. { dealloc is too late (and optimizations are missed (JM) }
  468. del_reference(right.location.reference);
  469. { This one doesn't need extra registers (JM) }
  470. emit_push_mem(right.location.reference);
  471. ungettemp:=true;
  472. end;
  473. end;
  474. emitpushreferenceaddr(left.location.reference);
  475. del_reference(left.location.reference);
  476. saveregvars($ff);
  477. if is_ansistring(left.resulttype.def) then
  478. emitcall('FPC_ANSISTR_ASSIGN')
  479. else
  480. emitcall('FPC_WIDESTR_ASSIGN');
  481. maybe_loadself;
  482. popusedregisters(regspushed);
  483. if ungettemp then
  484. ungetiftemp(right.location.reference);
  485. end
  486. else
  487. if is_shortstring(left.resulttype.def) and
  488. not (nf_concat_string in flags) then
  489. begin
  490. if is_ansistring(right.resulttype.def) then
  491. begin
  492. if (right.nodetype=stringconstn) and
  493. (tstringconstnode(right).len=0) then
  494. begin
  495. emit_const_ref(A_MOV,S_B,
  496. 0,newreference(left.location.reference));
  497. del_reference(left.location.reference);
  498. end
  499. else
  500. loadansi2short(right,left);
  501. end
  502. else
  503. begin
  504. { we do not need destination anymore }
  505. del_reference(left.location.reference);
  506. {del_reference(right.location.reference);
  507. done in loadshortstring }
  508. loadshortstring(right,left);
  509. ungetiftemp(right.location.reference);
  510. end;
  511. end
  512. else if is_longstring(left.resulttype.def) then
  513. begin
  514. internalerror(200105261);
  515. end
  516. else
  517. begin
  518. { its the only thing we have to do }
  519. del_reference(right.location.reference);
  520. end
  521. end
  522. else if is_interfacecom(left.resulttype.def) then
  523. begin
  524. loadinterfacecom(self);
  525. end
  526. else case right.location.loc of
  527. LOC_REFERENCE,
  528. LOC_MEM : begin
  529. { extra handling for ordinal constants }
  530. if (right.nodetype in [ordconstn,pointerconstn,niln]) or
  531. (loc=LOC_CREGISTER) then
  532. begin
  533. case left.resulttype.def.size of
  534. 1 : opsize:=S_B;
  535. 2 : opsize:=S_W;
  536. 4 : opsize:=S_L;
  537. { S_L is correct, the copy is done }
  538. { with two moves }
  539. 8 : opsize:=S_L;
  540. end;
  541. if loc=LOC_CREGISTER then
  542. begin
  543. emit_ref_reg(A_MOV,opsize,
  544. newreference(right.location.reference),
  545. left.location.register);
  546. if left.resulttype.def.size=8 then
  547. begin
  548. r:=newreference(right.location.reference);
  549. inc(r^.offset,4);
  550. emit_ref_reg(A_MOV,opsize,r,
  551. left.location.registerhigh);
  552. end;
  553. {$IfDef regallocfix}
  554. del_reference(right.location.reference);
  555. {$EndIf regallocfix}
  556. end
  557. else
  558. begin
  559. if left.resulttype.def.size=8 then
  560. begin
  561. emit_const_ref(A_MOV,opsize,
  562. longint(lo(tordconstnode(right).value)),
  563. newreference(left.location.reference));
  564. r:=newreference(left.location.reference);
  565. inc(r^.offset,4);
  566. emit_const_ref(A_MOV,opsize,
  567. longint(hi(tordconstnode(right).value)),r);
  568. end
  569. else
  570. begin
  571. emit_const_ref(A_MOV,opsize,
  572. right.location.reference.offset,
  573. newreference(left.location.reference));
  574. end;
  575. {$IfDef regallocfix}
  576. del_reference(left.location.reference);
  577. {$EndIf regallocfix}
  578. {emit_const_loc(A_MOV,opsize,
  579. right.location.reference.offset,
  580. left.location);}
  581. end;
  582. end
  583. else if loc=LOC_CFPUREGISTER then
  584. begin
  585. floatloadops(tfloatdef(right.resulttype.def).typ,op,opsize);
  586. emit_ref(op,opsize,
  587. newreference(right.location.reference));
  588. emit_reg(A_FSTP,S_NO,
  589. correct_fpuregister(left.location.register,fpuvaroffset+1));
  590. end
  591. else
  592. begin
  593. if (right.resulttype.def.needs_inittable) then
  594. begin
  595. { this would be a problem }
  596. if not(left.resulttype.def.needs_inittable) then
  597. internalerror(3457);
  598. { increment source reference counter }
  599. new(r);
  600. reset_reference(r^);
  601. r^.symbol:=tstoreddef(right.resulttype.def).get_rtti_label(initrtti);
  602. emitpushreferenceaddr(r^);
  603. emitpushreferenceaddr(right.location.reference);
  604. emitcall('FPC_ADDREF');
  605. { decrement destination reference counter }
  606. new(r);
  607. reset_reference(r^);
  608. r^.symbol:=tstoreddef(left.resulttype.def).get_rtti_label(initrtti);
  609. emitpushreferenceaddr(r^);
  610. emitpushreferenceaddr(left.location.reference);
  611. emitcall('FPC_DECREF');
  612. end;
  613. concatcopy(right.location.reference,
  614. left.location.reference,left.resulttype.def.size,true,false);
  615. del_reference(left.location.reference);
  616. { done by concatcopy
  617. del_reference(right.location.reference);
  618. ungetiftemp(right.location.reference); }
  619. end;
  620. end;
  621. {$ifdef SUPPORT_MMX}
  622. LOC_CMMXREGISTER,
  623. LOC_MMXREGISTER:
  624. begin
  625. if loc=LOC_CMMXREGISTER then
  626. emit_reg_reg(A_MOVQ,S_NO,
  627. right.location.register,left.location.register)
  628. else
  629. emit_reg_ref(A_MOVQ,S_NO,
  630. right.location.register,newreference(left.location.reference));
  631. end;
  632. {$endif SUPPORT_MMX}
  633. LOC_REGISTER,
  634. LOC_CREGISTER : begin
  635. case right.resulttype.def.size of
  636. 1 : opsize:=S_B;
  637. 2 : opsize:=S_W;
  638. 4 : opsize:=S_L;
  639. 8 : opsize:=S_L;
  640. end;
  641. { simplified with op_reg_loc }
  642. if loc=LOC_CREGISTER then
  643. begin
  644. emit_reg_reg(A_MOV,opsize,
  645. right.location.register,
  646. left.location.register);
  647. ungetregister(right.location.register);
  648. end
  649. else
  650. Begin
  651. emit_reg_ref(A_MOV,opsize,
  652. right.location.register,
  653. newreference(left.location.reference));
  654. ungetregister(right.location.register);
  655. {$IfDef regallocfix}
  656. del_reference(left.location.reference);
  657. {$EndIf regallocfix}
  658. end;
  659. if is_64bitint(right.resulttype.def) then
  660. begin
  661. { simplified with op_reg_loc }
  662. if loc=LOC_CREGISTER then
  663. emit_reg_reg(A_MOV,opsize,
  664. right.location.registerhigh,
  665. left.location.registerhigh)
  666. else
  667. begin
  668. r:=newreference(left.location.reference);
  669. inc(r^.offset,4);
  670. emit_reg_ref(A_MOV,opsize,
  671. right.location.registerhigh,r);
  672. end;
  673. end;
  674. {emit_reg_loc(A_MOV,opsize,
  675. right.location.register,
  676. left.location); }
  677. end;
  678. LOC_FPU : begin
  679. if (left.resulttype.def.deftype=floatdef) then
  680. fputyp:=tfloatdef(left.resulttype.def).typ
  681. else
  682. if (right.resulttype.def.deftype=floatdef) then
  683. fputyp:=tfloatdef(right.resulttype.def).typ
  684. else
  685. if (right.nodetype=typeconvn) and
  686. (ttypeconvnode(right).left.resulttype.def.deftype=floatdef) then
  687. fputyp:=tfloatdef(ttypeconvnode(right).left.resulttype.def).typ
  688. else
  689. fputyp:=s32real;
  690. case loc of
  691. LOC_CFPUREGISTER:
  692. begin
  693. emit_reg(A_FSTP,S_NO,
  694. correct_fpuregister(left.location.register,fpuvaroffset));
  695. dec(fpuvaroffset);
  696. end;
  697. LOC_REFERENCE:
  698. floatstore(fputyp,left.location.reference);
  699. else
  700. internalerror(48991);
  701. end;
  702. end;
  703. LOC_CFPUREGISTER: begin
  704. if (left.resulttype.def.deftype=floatdef) then
  705. fputyp:=tfloatdef(left.resulttype.def).typ
  706. else
  707. if (right.resulttype.def.deftype=floatdef) then
  708. fputyp:=tfloatdef(right.resulttype.def).typ
  709. else
  710. if (right.nodetype=typeconvn) and
  711. (ttypeconvnode(right).left.resulttype.def.deftype=floatdef) then
  712. fputyp:=tfloatdef(ttypeconvnode(right).left.resulttype.def).typ
  713. else
  714. fputyp:=s32real;
  715. emit_reg(A_FLD,S_NO,
  716. correct_fpuregister(right.location.register,fpuvaroffset));
  717. inc(fpuvaroffset);
  718. case loc of
  719. LOC_CFPUREGISTER:
  720. begin
  721. emit_reg(A_FSTP,S_NO,
  722. correct_fpuregister(right.location.register,fpuvaroffset));
  723. dec(fpuvaroffset);
  724. end;
  725. LOC_REFERENCE:
  726. floatstore(fputyp,left.location.reference);
  727. else
  728. internalerror(48992);
  729. end;
  730. end;
  731. LOC_JUMP : begin
  732. opsize:=def_opsize(left.resulttype.def);
  733. getlabel(hlabel);
  734. emitlab(truelabel);
  735. if pushed then
  736. restore(left,false);
  737. if loc=LOC_CREGISTER then
  738. emit_const_reg(A_MOV,opsize,
  739. 1,left.location.register)
  740. else
  741. emit_const_ref(A_MOV,opsize,
  742. 1,newreference(left.location.reference));
  743. emitjmp(C_None,hlabel);
  744. emitlab(falselabel);
  745. if pushed then
  746. restore(left,false);
  747. if loc=LOC_CREGISTER then
  748. emit_reg_reg(A_XOR,opsize,
  749. left.location.register,
  750. left.location.register)
  751. else
  752. begin
  753. emit_const_ref(A_MOV,opsize,
  754. 0,newreference(left.location.reference));
  755. {$IfDef regallocfix}
  756. del_reference(left.location.reference);
  757. {$EndIf regallocfix}
  758. end;
  759. emitlab(hlabel);
  760. end;
  761. LOC_FLAGS : begin
  762. if loc=LOC_CREGISTER then
  763. emit_flag2reg(right.location.resflags,left.location.register)
  764. else
  765. begin
  766. ai:=Taicpu.Op_ref(A_Setcc,S_B,newreference(left.location.reference));
  767. ai.SetCondition(flags_to_cond(right.location.resflags));
  768. exprasmList.concat(ai);
  769. end;
  770. {$IfDef regallocfix}
  771. del_reference(left.location.reference);
  772. {$EndIf regallocfix}
  773. end;
  774. end;
  775. truelabel:=otlabel;
  776. falselabel:=oflabel;
  777. end;
  778. {*****************************************************************************
  779. SecondFuncRet
  780. *****************************************************************************}
  781. procedure ti386funcretnode.pass_2;
  782. var
  783. hr : tregister;
  784. hp : preference;
  785. pp : pprocinfo;
  786. hr_valid : boolean;
  787. i : integer;
  788. begin
  789. reset_reference(location.reference);
  790. hr_valid:=false;
  791. if (not inlining_procedure) and
  792. (lexlevel<>funcretsym.owner.symtablelevel) then
  793. begin
  794. hr:=getregisterint;
  795. hr_valid:=true;
  796. hp:=new_reference(procinfo^.framepointer,procinfo^.framepointer_offset);
  797. emit_ref_reg(A_MOV,S_L,hp,hr);
  798. { walk up the stack frame }
  799. pp:=procinfo^.parent;
  800. i:=lexlevel-1;
  801. while i>funcretsym.owner.symtablelevel do
  802. begin
  803. hp:=new_reference(hr,pp^.framepointer_offset);
  804. emit_ref_reg(A_MOV,S_L,hp,hr);
  805. pp:=pp^.parent;
  806. dec(i);
  807. end;
  808. location.reference.base:=hr;
  809. location.reference.offset:=pp^.return_offset;
  810. end
  811. else
  812. begin
  813. location.reference.base:=procinfo^.framepointer;
  814. location.reference.offset:=procinfo^.return_offset;
  815. end;
  816. if ret_in_param(resulttype.def) then
  817. begin
  818. if not hr_valid then
  819. hr:=getregisterint;
  820. emit_ref_reg(A_MOV,S_L,newreference(location.reference),hr);
  821. location.reference.base:=hr;
  822. location.reference.offset:=0;
  823. end;
  824. end;
  825. {*****************************************************************************
  826. SecondArrayConstruct
  827. *****************************************************************************}
  828. const
  829. vtInteger = 0;
  830. vtBoolean = 1;
  831. vtChar = 2;
  832. vtExtended = 3;
  833. vtString = 4;
  834. vtPointer = 5;
  835. vtPChar = 6;
  836. vtObject = 7;
  837. vtClass = 8;
  838. vtWideChar = 9;
  839. vtPWideChar = 10;
  840. vtAnsiString = 11;
  841. vtCurrency = 12;
  842. vtVariant = 13;
  843. vtInterface = 14;
  844. vtWideString = 15;
  845. vtInt64 = 16;
  846. vtQWord = 17;
  847. procedure ti386arrayconstructornode.pass_2;
  848. var
  849. hp : tarrayconstructornode;
  850. href : treference;
  851. lt : tdef;
  852. vaddr : boolean;
  853. vtype : longint;
  854. freetemp,
  855. dovariant : boolean;
  856. elesize : longint;
  857. begin
  858. dovariant:=(nf_forcevaria in flags) or tarraydef(resulttype.def).isvariant;
  859. if dovariant then
  860. elesize:=8
  861. else
  862. elesize:=tarraydef(resulttype.def).elesize;
  863. if not(nf_cargs in flags) then
  864. begin
  865. reset_reference(location.reference);
  866. { Allocate always a temp, also if no elements are required, to
  867. be sure that location is valid (PFV) }
  868. if tarraydef(resulttype.def).highrange=-1 then
  869. gettempofsizereference(elesize,location.reference)
  870. else
  871. gettempofsizereference((tarraydef(resulttype.def).highrange+1)*elesize,location.reference);
  872. href:=location.reference;
  873. end;
  874. hp:=self;
  875. while assigned(hp) do
  876. begin
  877. if assigned(hp.left) then
  878. begin
  879. freetemp:=true;
  880. secondpass(hp.left);
  881. if codegenerror then
  882. exit;
  883. if dovariant then
  884. begin
  885. { find the correct vtype value }
  886. vtype:=$ff;
  887. vaddr:=false;
  888. lt:=hp.left.resulttype.def;
  889. case lt.deftype of
  890. enumdef,
  891. orddef :
  892. begin
  893. if is_64bitint(lt) then
  894. begin
  895. case torddef(lt).typ of
  896. s64bit:
  897. vtype:=vtInt64;
  898. u64bit:
  899. vtype:=vtQWord;
  900. end;
  901. freetemp:=false;
  902. vaddr:=true;
  903. end
  904. else if (lt.deftype=enumdef) or
  905. is_integer(lt) then
  906. vtype:=vtInteger
  907. else
  908. if is_boolean(lt) then
  909. vtype:=vtBoolean
  910. else
  911. if (lt.deftype=orddef) and (torddef(lt).typ=uchar) then
  912. vtype:=vtChar;
  913. end;
  914. floatdef :
  915. begin
  916. vtype:=vtExtended;
  917. vaddr:=true;
  918. freetemp:=false;
  919. end;
  920. procvardef,
  921. pointerdef :
  922. begin
  923. if is_pchar(lt) then
  924. vtype:=vtPChar
  925. else
  926. vtype:=vtPointer;
  927. end;
  928. classrefdef :
  929. vtype:=vtClass;
  930. objectdef :
  931. begin
  932. vtype:=vtObject;
  933. end;
  934. stringdef :
  935. begin
  936. if is_shortstring(lt) then
  937. begin
  938. vtype:=vtString;
  939. vaddr:=true;
  940. freetemp:=false;
  941. end
  942. else
  943. if is_ansistring(lt) then
  944. begin
  945. vtype:=vtAnsiString;
  946. freetemp:=false;
  947. end
  948. else
  949. if is_widestring(lt) then
  950. begin
  951. vtype:=vtWideString;
  952. freetemp:=false;
  953. end;
  954. end;
  955. end;
  956. if vtype=$ff then
  957. internalerror(14357);
  958. { write C style pushes or an pascal array }
  959. if nf_cargs in flags then
  960. begin
  961. if vaddr then
  962. begin
  963. emit_to_mem(hp.left.location,hp.left.resulttype.def);
  964. emit_push_lea_loc(hp.left.location,freetemp);
  965. del_reference(hp.left.location.reference);
  966. end
  967. else
  968. emit_push_loc(hp.left.location);
  969. inc(pushedparasize,4);
  970. end
  971. else
  972. begin
  973. { write changing field update href to the next element }
  974. inc(href.offset,4);
  975. if vaddr then
  976. begin
  977. emit_to_mem(hp.left.location,hp.left.resulttype.def);
  978. emit_lea_loc_ref(hp.left.location,href,freetemp);
  979. end
  980. else
  981. begin
  982. emit_mov_loc_ref(hp.left.location,href,S_L,freetemp);
  983. end;
  984. { update href to the vtype field and write it }
  985. dec(href.offset,4);
  986. emit_const_ref(A_MOV,S_L,vtype,newreference(href));
  987. { goto next array element }
  988. inc(href.offset,8);
  989. end;
  990. end
  991. else
  992. { normal array constructor of the same type }
  993. begin
  994. case elesize of
  995. 1 :
  996. emit_mov_loc_ref(hp.left.location,href,S_B,freetemp);
  997. 2 :
  998. emit_mov_loc_ref(hp.left.location,href,S_W,freetemp);
  999. 4 :
  1000. emit_mov_loc_ref(hp.left.location,href,S_L,freetemp);
  1001. 8 :
  1002. begin
  1003. if hp.left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  1004. begin
  1005. emit_reg_ref(A_MOV,S_L,hp.left.location.registerlow,newreference(href));
  1006. { update href to the high bytes and write it }
  1007. inc(href.offset,4);
  1008. emit_reg_ref(A_MOV,S_L,hp.left.location.registerhigh,newreference(href));
  1009. dec(href.offset,4)
  1010. end
  1011. else
  1012. concatcopy(hp.left.location.reference,href,elesize,freetemp,false);
  1013. end;
  1014. else
  1015. begin
  1016. { concatcopy only supports reference }
  1017. if not(hp.left.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  1018. internalerror(200108012);
  1019. concatcopy(hp.left.location.reference,href,elesize,freetemp,false);
  1020. end;
  1021. end;
  1022. inc(href.offset,elesize);
  1023. end;
  1024. end;
  1025. { load next entry }
  1026. hp:=tarrayconstructornode(hp.right);
  1027. end;
  1028. end;
  1029. begin
  1030. cloadnode:=ti386loadnode;
  1031. cassignmentnode:=ti386assignmentnode;
  1032. cfuncretnode:=ti386funcretnode;
  1033. carrayconstructornode:=ti386arrayconstructornode;
  1034. end.
  1035. {
  1036. $Log$
  1037. Revision 1.29 2002-03-04 19:10:14 peter
  1038. * removed compiler warnings
  1039. Revision 1.28 2001/12/30 17:24:46 jonas
  1040. * range checking is now processor independent (part in cgobj,
  1041. part in cg64f32) and should work correctly again (it needed
  1042. some changes after the changes of the low and high of
  1043. tordef's to int64)
  1044. * maketojumpbool() is now processor independent (in ncgutil)
  1045. * getregister32 is now called getregisterint
  1046. Revision 1.27 2001/12/17 23:16:05 florian
  1047. * array of const can now take widestring parameters as well
  1048. Revision 1.26 2001/11/02 22:58:11 peter
  1049. * procsym definition rewrite
  1050. Revision 1.25 2001/10/28 17:22:25 peter
  1051. * allow assignment of overloaded procedures to procvars when we know
  1052. which procedure to take
  1053. Revision 1.24 2001/10/14 11:49:51 jonas
  1054. * finetuned register allocation info for assignments
  1055. Revision 1.23 2001/10/04 14:33:28 jonas
  1056. * fixed range check errors
  1057. Revision 1.22 2001/09/09 08:51:09 jonas
  1058. * fixed bug with assigning ansistrings (left^.location was released too
  1059. early, caused bug reported by Aleksey V. Vaneev in mailing list on
  1060. 2001/09/07 regarding 'problems with nested procedures and local vars'
  1061. ("merged" from cga.pas in the fixes branch)
  1062. Revision 1.21 2001/08/30 20:13:57 peter
  1063. * rtti/init table updates
  1064. * rttisym for reusable global rtti/init info
  1065. * support published for interfaces
  1066. Revision 1.20 2001/08/30 11:57:20 michael
  1067. + Patch for wrong paramsize
  1068. Revision 1.19 2001/08/26 13:36:59 florian
  1069. * some cg reorganisation
  1070. * some PPC updates
  1071. Revision 1.18 2001/08/06 21:40:50 peter
  1072. * funcret moved from tprocinfo to tprocdef
  1073. Revision 1.17 2001/08/05 13:19:51 peter
  1074. * partly fix for proc of obj=nil
  1075. Revision 1.15 2001/07/28 15:13:17 peter
  1076. * fixed opsize for assignment with LOC_JUMP
  1077. Revision 1.14 2001/05/27 14:30:56 florian
  1078. + some widestring stuff added
  1079. Revision 1.13 2001/04/13 01:22:19 peter
  1080. * symtable change to classes
  1081. * range check generation and errors fixed, make cycle DEBUG=1 works
  1082. * memory leaks fixed
  1083. Revision 1.12 2001/04/02 21:20:37 peter
  1084. * resulttype rewrite
  1085. Revision 1.11 2000/12/25 00:07:33 peter
  1086. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  1087. tlinkedlist objects)
  1088. Revision 1.10 2000/12/05 11:44:33 jonas
  1089. + new integer regvar handling, should be much more efficient
  1090. Revision 1.9 2000/11/29 00:30:48 florian
  1091. * unused units removed from uses clause
  1092. * some changes for widestrings
  1093. Revision 1.8 2000/11/13 14:44:36 jonas
  1094. * fixes so no more range errors with improved range checking code
  1095. Revision 1.7 2000/11/12 23:24:15 florian
  1096. * interfaces are basically running
  1097. Revision 1.6 2000/11/11 22:59:20 florian
  1098. * fixed resourcestrings, made a stupid mistake yesterday
  1099. Revision 1.5 2000/11/09 18:52:06 florian
  1100. * resourcestrings doesn't need the helper anymore they
  1101. access the table now direct
  1102. Revision 1.4 2000/11/06 23:15:02 peter
  1103. * added copyvaluepara call again
  1104. Revision 1.3 2000/11/04 14:25:23 florian
  1105. + merged Attila's changes for interfaces, not tested yet
  1106. Revision 1.2 2000/10/31 22:02:56 peter
  1107. * symtable splitted, no real code changes
  1108. Revision 1.1 2000/10/15 09:33:31 peter
  1109. * moved n386*.pas to i386/ cpu_target dir
  1110. Revision 1.1 2000/10/14 10:14:49 peter
  1111. * moehrendorf oct 2000 rewrite
  1112. }